ref: 61e35a208c16f339e39e5b4d6244e12ddcc980f7
parent: 4cae69d325329e3c1d7bf043eb52d610369a26bb
author: Konstantinn Bonnet <[email protected]>
date: Sun Jun 28 12:02:21 EDT 2015
more mostly pointless file shuffling - merge headers (except adivtab.h, anorms.h, rand1k.h) → dat.h, fns.h and game/game.h. game.h remains for mod shit - remove const qualifiers (mostly from menu stuff) - put TARG in mk.$game for setting binary's name for each mod - plan9-ish C style for some files
--- /dev/null
+++ b/adivtab.h
@@ -1,0 +1,1058 @@
+// table of quotients and remainders for [-15...16] / [-15...16]
+
+// numerator = -15
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{1, -6},
+{1, -7},
+{2, -1},
+{2, -3},
+{3, 0},
+{3, -3},
+{5, 0},
+{7, -1},
+{15, 0},
+{0, 0},
+{-15, 0},
+{-8, 1},
+{-5, 0},
+{-4, 1},
+{-3, 0},
+{-3, 3},
+{-3, 6},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-2, 7},
+{-2, 9},
+{-2, 11},
+{-2, 13},
+{-1, 0},
+{-1, 1},
+// numerator = -14
+{0, -14},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{1, -6},
+{2, 0},
+{2, -2},
+{2, -4},
+{3, -2},
+{4, -2},
+{7, 0},
+{14, 0},
+{0, 0},
+{-14, 0},
+{-7, 0},
+{-5, 1},
+{-4, 2},
+{-3, 1},
+{-3, 4},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-2, 6},
+{-2, 8},
+{-2, 10},
+{-2, 12},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+// numerator = -13
+{0, -13},
+{0, -13},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{1, -6},
+{2, -1},
+{2, -3},
+{3, -1},
+{4, -1},
+{6, -1},
+{13, 0},
+{0, 0},
+{-13, 0},
+{-7, 1},
+{-5, 2},
+{-4, 3},
+{-3, 2},
+{-3, 5},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-2, 7},
+{-2, 9},
+{-2, 11},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+// numerator = -12
+{0, -12},
+{0, -12},
+{0, -12},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{2, 0},
+{2, -2},
+{3, 0},
+{4, 0},
+{6, 0},
+{12, 0},
+{0, 0},
+{-12, 0},
+{-6, 0},
+{-4, 0},
+{-3, 0},
+{-3, 3},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-2, 6},
+{-2, 8},
+{-2, 10},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+// numerator = -11
+{0, -11},
+{0, -11},
+{0, -11},
+{0, -11},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{1, -5},
+{2, -1},
+{2, -3},
+{3, -2},
+{5, -1},
+{11, 0},
+{0, 0},
+{-11, 0},
+{-6, 1},
+{-4, 1},
+{-3, 1},
+{-3, 4},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-2, 7},
+{-2, 9},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+// numerator = -10
+{0, -10},
+{0, -10},
+{0, -10},
+{0, -10},
+{0, -10},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{2, 0},
+{2, -2},
+{3, -1},
+{5, 0},
+{10, 0},
+{0, 0},
+{-10, 0},
+{-5, 0},
+{-4, 2},
+{-3, 2},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-2, 6},
+{-2, 8},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+// numerator = -9
+{0, -9},
+{0, -9},
+{0, -9},
+{0, -9},
+{0, -9},
+{0, -9},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{1, -4},
+{2, -1},
+{3, 0},
+{4, -1},
+{9, 0},
+{0, 0},
+{-9, 0},
+{-5, 1},
+{-3, 0},
+{-3, 3},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-2, 7},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+// numerator = -8
+{0, -8},
+{0, -8},
+{0, -8},
+{0, -8},
+{0, -8},
+{0, -8},
+{0, -8},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{2, 0},
+{2, -2},
+{4, 0},
+{8, 0},
+{0, 0},
+{-8, 0},
+{-4, 0},
+{-3, 1},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-2, 6},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+// numerator = -7
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{0, -7},
+{1, 0},
+{1, -1},
+{1, -2},
+{1, -3},
+{2, -1},
+{3, -1},
+{7, 0},
+{0, 0},
+{-7, 0},
+{-4, 1},
+{-3, 2},
+{-2, 1},
+{-2, 3},
+{-2, 5},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+// numerator = -6
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{0, -6},
+{1, 0},
+{1, -1},
+{1, -2},
+{2, 0},
+{3, 0},
+{6, 0},
+{0, 0},
+{-6, 0},
+{-3, 0},
+{-2, 0},
+{-2, 2},
+{-2, 4},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+// numerator = -5
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{0, -5},
+{1, 0},
+{1, -1},
+{1, -2},
+{2, -1},
+{5, 0},
+{0, 0},
+{-5, 0},
+{-3, 1},
+{-2, 1},
+{-2, 3},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+// numerator = -4
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{0, -4},
+{1, 0},
+{1, -1},
+{2, 0},
+{4, 0},
+{0, 0},
+{-4, 0},
+{-2, 0},
+{-2, 2},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+{-1, 12},
+// numerator = -3
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{0, -3},
+{1, 0},
+{1, -1},
+{3, 0},
+{0, 0},
+{-3, 0},
+{-2, 1},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+{-1, 12},
+{-1, 13},
+// numerator = -2
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{0, -2},
+{1, 0},
+{2, 0},
+{0, 0},
+{-2, 0},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+{-1, 12},
+{-1, 13},
+{-1, 14},
+// numerator = -1
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{0, -1},
+{1, 0},
+{0, 0},
+{-1, 0},
+{-1, 1},
+{-1, 2},
+{-1, 3},
+{-1, 4},
+{-1, 5},
+{-1, 6},
+{-1, 7},
+{-1, 8},
+{-1, 9},
+{-1, 10},
+{-1, 11},
+{-1, 12},
+{-1, 13},
+{-1, 14},
+{-1, 15},
+// numerator = 0
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+{0, 0},
+// numerator = 1
+{-1, -14},
+{-1, -13},
+{-1, -12},
+{-1, -11},
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{0, 0},
+{1, 0},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+{0, 1},
+// numerator = 2
+{-1, -13},
+{-1, -12},
+{-1, -11},
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, 0},
+{0, 0},
+{2, 0},
+{1, 0},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+{0, 2},
+// numerator = 3
+{-1, -12},
+{-1, -11},
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -1},
+{-3, 0},
+{0, 0},
+{3, 0},
+{1, 1},
+{1, 0},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+{0, 3},
+// numerator = 4
+{-1, -11},
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -2},
+{-2, 0},
+{-4, 0},
+{0, 0},
+{4, 0},
+{2, 0},
+{1, 1},
+{1, 0},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+{0, 4},
+// numerator = 5
+{-1, -10},
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -3},
+{-2, -1},
+{-3, -1},
+{-5, 0},
+{0, 0},
+{5, 0},
+{2, 1},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+{0, 5},
+// numerator = 6
+{-1, -9},
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, 0},
+{-6, 0},
+{0, 0},
+{6, 0},
+{3, 0},
+{2, 0},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+{0, 6},
+// numerator = 7
+{-1, -8},
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -2},
+{-4, -1},
+{-7, 0},
+{0, 0},
+{7, 0},
+{3, 1},
+{2, 1},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+{0, 7},
+// numerator = 8
+{-1, -7},
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -1},
+{-4, 0},
+{-8, 0},
+{0, 0},
+{8, 0},
+{4, 0},
+{2, 2},
+{2, 0},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+{0, 8},
+// numerator = 9
+{-1, -6},
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -7},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -3},
+{-3, 0},
+{-5, -1},
+{-9, 0},
+{0, 0},
+{9, 0},
+{4, 1},
+{3, 0},
+{2, 1},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 9},
+{0, 9},
+{0, 9},
+{0, 9},
+{0, 9},
+{0, 9},
+{0, 9},
+// numerator = 10
+{-1, -5},
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -8},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -2},
+{-4, -2},
+{-5, 0},
+{-10, 0},
+{0, 0},
+{10, 0},
+{5, 0},
+{3, 1},
+{2, 2},
+{2, 0},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 10},
+{0, 10},
+{0, 10},
+{0, 10},
+{0, 10},
+{0, 10},
+// numerator = 11
+{-1, -4},
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -9},
+{-2, -7},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -4},
+{-3, -1},
+{-4, -1},
+{-6, -1},
+{-11, 0},
+{0, 0},
+{11, 0},
+{5, 1},
+{3, 2},
+{2, 3},
+{2, 1},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 11},
+{0, 11},
+{0, 11},
+{0, 11},
+{0, 11},
+// numerator = 12
+{-1, -3},
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -10},
+{-2, -8},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -3},
+{-3, 0},
+{-4, 0},
+{-6, 0},
+{-12, 0},
+{0, 0},
+{12, 0},
+{6, 0},
+{4, 0},
+{3, 0},
+{2, 2},
+{2, 0},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 12},
+{0, 12},
+{0, 12},
+{0, 12},
+// numerator = 13
+{-1, -2},
+{-1, -1},
+{-1, 0},
+{-2, -11},
+{-2, -9},
+{-2, -7},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -5},
+{-3, -2},
+{-4, -3},
+{-5, -2},
+{-7, -1},
+{-13, 0},
+{0, 0},
+{13, 0},
+{6, 1},
+{4, 1},
+{3, 1},
+{2, 3},
+{2, 1},
+{1, 6},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 13},
+{0, 13},
+{0, 13},
+// numerator = 14
+{-1, -1},
+{-1, 0},
+{-2, -12},
+{-2, -10},
+{-2, -8},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -4},
+{-3, -1},
+{-4, -2},
+{-5, -1},
+{-7, 0},
+{-14, 0},
+{0, 0},
+{14, 0},
+{7, 0},
+{4, 2},
+{3, 2},
+{2, 4},
+{2, 2},
+{2, 0},
+{1, 6},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 14},
+{0, 14},
+// numerator = 15
+{-1, 0},
+{-2, -13},
+{-2, -11},
+{-2, -9},
+{-2, -7},
+{-2, -5},
+{-2, -3},
+{-2, -1},
+{-3, -6},
+{-3, -3},
+{-3, 0},
+{-4, -1},
+{-5, 0},
+{-8, -1},
+{-15, 0},
+{0, 0},
+{15, 0},
+{7, 1},
+{5, 0},
+{3, 3},
+{3, 0},
+{2, 3},
+{2, 1},
+{1, 7},
+{1, 6},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
+{0, 15},
+// numerator = 16
+{-2, -14},
+{-2, -12},
+{-2, -10},
+{-2, -8},
+{-2, -6},
+{-2, -4},
+{-2, -2},
+{-2, 0},
+{-3, -5},
+{-3, -2},
+{-4, -4},
+{-4, 0},
+{-6, -2},
+{-8, 0},
+{-16, 0},
+{0, 0},
+{16, 0},
+{8, 0},
+{5, 1},
+{4, 0},
+{3, 1},
+{2, 4},
+{2, 2},
+{2, 0},
+{1, 7},
+{1, 6},
+{1, 5},
+{1, 4},
+{1, 3},
+{1, 2},
+{1, 1},
+{1, 0},
--- /dev/null
+++ b/cd.c
@@ -1,0 +1,415 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+qboolean cdValid = false;
+qboolean playing = false;
+qboolean wasPlaying = false;
+qboolean initialized = false;
+qboolean enabled = true;
+qboolean playLooping = false;
+float cdvolume;
+byte remap[100];
+byte playTrack;
+byte maxTrack;
+int cdfile = -1;
+
+cvar_t *cd_volume;
+cvar_t *cd_nocd;
+cvar_t *cd_dev;
+
+
+void CDAudio_Eject(void)
+{
+ if (cdfile == -1 || !enabled)
+ return;
+
+ Com_DPrintf("CDAudio_Eject: PORTME\n");
+ /*
+ if ( ioctl(cdfile, CDROMEJECT) == -1 )
+ Com_DPrintf("ioctl cdromeject failed\n");
+ */
+}
+
+void CDAudio_CloseDoor(void)
+{
+ if (cdfile == -1 || !enabled)
+ return;
+
+ Com_DPrintf("CDAudio_CloseDoor: PORTME\n");
+ /*
+ if ( ioctl(cdfile, CDROMCLOSETRAY) == -1 )
+ Com_DPrintf("ioctl cdromclosetray failed\n");
+ */
+}
+
+int CDAudio_GetAudioDiskInfo(void)
+{
+ cdValid = false;
+ Com_DPrintf("CDAudio_GetAudioDiskInfo: PORTME\n");
+ return -1;
+
+ /*
+ struct cdrom_tochdr tochdr;
+
+ if ( ioctl(cdfile, CDROMREADTOCHDR, &tochdr) == -1 )
+ {
+ Com_DPrintf("ioctl cdromreadtochdr failed\n");
+ return -1;
+ }
+
+ if (tochdr.cdth_trk0 < 1)
+ {
+ Com_DPrintf("CDAudio: no music tracks\n");
+ return -1;
+ }
+
+ cdValid = true;
+ maxTrack = tochdr.cdth_trk1;
+ return 0;
+ */
+}
+
+void CDAudio_Pause(void)
+{
+ if (cdfile == -1 || !enabled)
+ return;
+ if (!playing)
+ return;
+
+ Com_DPrintf("CDAudio_GetAudioDiskInfo: PORTME\n");
+
+ /*
+ if ( ioctl(cdfile, CDROMPAUSE) == -1 )
+ Com_DPrintf("ioctl cdrompause failed\n");
+
+ wasPlaying = playing;
+ playing = false;
+ */
+}
+
+void CDAudio_Play(int track, qboolean looping)
+{
+ if (cdfile == -1 || !enabled)
+ return;
+ if (!cdValid)
+ {
+ CDAudio_GetAudioDiskInfo();
+ if (!cdValid)
+ return;
+ }
+
+ track = remap[track];
+ if (track < 1 || track > maxTrack)
+ {
+ Com_DPrintf("CDAudio: Bad track number %u.\n", track);
+ return;
+ }
+
+ USED(looping);
+ Com_DPrintf("CDAudio_Play: PORTME\n");
+
+ /*
+ struct cdrom_tocentry entry;
+ struct cdrom_ti ti;
+
+ // don't try to play a non-audio track
+ entry.cdte_track = track;
+ entry.cdte_format = CDROM_MSF;
+ if ( ioctl(cdfile, CDROMREADTOCENTRY, &entry) == -1 )
+ {
+ Com_DPrintf("ioctl cdromreadtocentry failed\n");
+ return;
+ }
+ if (entry.cdte_ctrl == CDROM_DATA_TRACK)
+ {
+ Com_Printf("CDAudio: track %i is not audio\n", track);
+ return;
+ }
+
+ if (playing)
+ {
+ if (playTrack == track)
+ return;
+ CDAudio_Stop();
+ }
+
+ ti.cdti_trk0 = track;
+ ti.cdti_trk1 = track;
+ ti.cdti_ind0 = 1;
+ ti.cdti_ind1 = 99;
+ if ( ioctl(cdfile, CDROMPLAYTRKIND, &ti) == -1 )
+ {
+ Com_DPrintf("ioctl cdromplaytrkind failed\n");
+ return;
+ }
+ if ( ioctl(cdfile, CDROMRESUME) == -1 )
+ Com_DPrintf("ioctl cdromresume failed\n");
+
+ playLooping = looping;
+ playTrack = track;
+ playing = true;
+
+ if (cd_volume->value == 0.0)
+ CDAudio_Pause ();
+ */
+}
+
+
+void CDAudio_Stop(void)
+{
+ if (cdfile == -1 || !enabled)
+ return;
+ if (!playing)
+ return;
+
+ Com_DPrintf("CDAudio_Stop: PORTME\n");
+
+ /*
+ if ( ioctl(cdfile, CDROMSTOP) == -1 )
+ Com_DPrintf("ioctl cdromstop failed (%d)\n", errno);
+
+ wasPlaying = false;
+ playing = false;
+ */
+}
+
+void CDAudio_Resume(void)
+{
+ if (cdfile == -1 || !enabled)
+ return;
+ if (!cdValid)
+ return;
+ if (!wasPlaying)
+ return;
+
+ Com_DPrintf("CDAudio_Stop: PORTME\n");
+
+ /*
+ if ( ioctl(cdfile, CDROMRESUME) == -1 )
+ Com_DPrintf("ioctl cdromresume failed\n");
+ playing = true;
+ */
+}
+
+static void CD_f (void)
+{
+ char *command;
+ int n, ret;
+
+ if (Cmd_Argc() < 2)
+ return;
+
+ command = Cmd_Argv (1);
+
+ if (cistrcmp(command, "on") == 0)
+ {
+ enabled = true;
+ return;
+ }
+
+ if (cistrcmp(command, "off") == 0)
+ {
+ if (playing)
+ CDAudio_Stop();
+ enabled = false;
+ return;
+ }
+
+ if (cistrcmp(command, "reset") == 0)
+ {
+ enabled = true;
+ if (playing)
+ CDAudio_Stop();
+ for (n = 0; n < 100; n++)
+ remap[n] = n;
+ CDAudio_GetAudioDiskInfo();
+ return;
+ }
+
+ if (cistrcmp(command, "remap") == 0)
+ {
+ ret = Cmd_Argc() - 2;
+ if (ret <= 0)
+ {
+ for (n = 1; n < 100; n++)
+ if (remap[n] != n)
+ Com_Printf(" %u -> %u\n", n, remap[n]);
+ return;
+ }
+ for (n = 1; n <= ret; n++)
+ remap[n] = atoi(Cmd_Argv (n+1));
+ return;
+ }
+
+ if (cistrcmp(command, "close") == 0)
+ {
+ CDAudio_CloseDoor();
+ return;
+ }
+
+ if (!cdValid)
+ {
+ CDAudio_GetAudioDiskInfo();
+ if (!cdValid)
+ {
+ Com_Printf("No CD in player.\n");
+ return;
+ }
+ }
+
+ if (cistrcmp(command, "play") == 0)
+ {
+ CDAudio_Play((byte)atoi(Cmd_Argv (2)), false);
+ return;
+ }
+
+ if (cistrcmp(command, "loop") == 0)
+ {
+ CDAudio_Play((byte)atoi(Cmd_Argv (2)), true);
+ return;
+ }
+
+ if (cistrcmp(command, "stop") == 0)
+ {
+ CDAudio_Stop();
+ return;
+ }
+
+ if (cistrcmp(command, "pause") == 0)
+ {
+ CDAudio_Pause();
+ return;
+ }
+
+ if (cistrcmp(command, "resume") == 0)
+ {
+ CDAudio_Resume();
+ return;
+ }
+
+ if (cistrcmp(command, "eject") == 0)
+ {
+ if (playing)
+ CDAudio_Stop();
+ CDAudio_Eject();
+ cdValid = false;
+ return;
+ }
+
+ if (cistrcmp(command, "info") == 0)
+ {
+ Com_Printf("%u tracks\n", maxTrack);
+ if (playing)
+ Com_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack);
+ else if (wasPlaying)
+ Com_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack);
+ Com_Printf("Volume is %f\n", cdvolume);
+ return;
+ }
+}
+
+void CDAudio_Update(void)
+{
+ if (cdfile == -1 || !enabled)
+ return;
+ if (cd_volume && cd_volume->value != cdvolume)
+ {
+ if (cdvolume)
+ {
+ Cvar_SetValue ("cd_volume", 0.0);
+ cdvolume = cd_volume->value;
+ CDAudio_Pause ();
+ }
+ else
+ {
+ Cvar_SetValue ("cd_volume", 1.0);
+ cdvolume = cd_volume->value;
+ CDAudio_Resume ();
+ }
+ }
+
+ Com_DPrintf("CDAudio_Stop: PORTME\n");
+
+ /*
+ struct cdrom_subchnl subchnl;
+ static time_t lastchk;
+
+ if (playing && lastchk < time(NULL)) {
+ lastchk = time(NULL) + 2; //two seconds between chks
+ subchnl.cdsc_format = CDROM_MSF;
+ if (ioctl(cdfile, CDROMSUBCHNL, &subchnl) == -1 ) {
+ Com_DPrintf("ioctl cdromsubchnl failed\n");
+ playing = false;
+ return;
+ }
+ if (subchnl.cdsc_audiostatus != CDROM_AUDIO_PLAY &&
+ subchnl.cdsc_audiostatus != CDROM_AUDIO_PAUSED) {
+ playing = false;
+ if (playLooping)
+ CDAudio_Play(playTrack, true);
+ }
+ }
+ */
+}
+
+int CDAudio_Init(void)
+{
+ int i;
+ cvar_t *cv;
+
+ cv = Cvar_Get ("nocdaudio", "0", CVAR_NOSET);
+ if (cv->value)
+ return -1;
+
+ cd_nocd = Cvar_Get ("cd_nocd", "0", CVAR_ARCHIVE );
+ if ( cd_nocd->value)
+ return -1;
+
+ cd_volume = Cvar_Get ("cd_volume", "1", CVAR_ARCHIVE);
+
+ cd_dev = Cvar_Get("cd_dev", "/dev/cdrom", CVAR_ARCHIVE);
+
+ if((cdfile = open(cd_dev->string, OREAD)) < 0){
+ fprint(2, "CDAudio_Init: %r\n");
+ Com_Printf("CDAudio_Init: failed to open \"%s\"\n", cd_dev->string);
+ cdfile = -1;
+ return -1;
+ }
+
+ for (i = 0; i < 100; i++)
+ remap[i] = i;
+ initialized = true;
+ enabled = true;
+
+ if (CDAudio_GetAudioDiskInfo())
+ {
+ Com_Printf("CDAudio_Init: No CD in player.\n");
+ cdValid = false;
+ }
+
+ Cmd_AddCommand ("cd", CD_f);
+
+ Com_Printf("CD Audio Initialized\n");
+
+ return 0;
+}
+
+void CDAudio_Activate (qboolean active)
+{
+ if (active)
+ CDAudio_Resume ();
+ else
+ CDAudio_Pause ();
+}
+
+void CDAudio_Shutdown(void)
+{
+ if (!initialized)
+ return;
+ CDAudio_Stop();
+ close(cdfile);
+ cdfile = -1;
+}
--- /dev/null
+++ b/cl_cin.c
@@ -1,0 +1,633 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+typedef struct
+{
+ byte *data;
+ int count;
+} cblock_t;
+
+typedef struct
+{
+ qboolean restart_sound;
+ int s_rate;
+ int s_width;
+ int s_channels;
+
+ int width;
+ int height;
+ byte *pic;
+ byte *pic_pending;
+
+ // order 1 huffman stuff
+ int *hnodes1; // [256][256][2];
+ int numhnodes1[256];
+
+ int h_used[512];
+ int h_count[512];
+} cinematics_t;
+
+cinematics_t cin;
+
+/*
+=================================================================
+
+PCX LOADING
+
+=================================================================
+*/
+
+
+/*
+==============
+SCR_LoadPCX
+==============
+*/
+void SCR_LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
+{
+ byte *raw;
+ pcx_t *pcx;
+ int x, y;
+ int len;
+ int dataByte, runLength;
+ byte *out, *pix;
+
+ *pic = NULL;
+
+ //
+ // load the file
+ //
+ len = FS_LoadFile (filename, (void **)&raw);
+ if (!raw)
+ return; // Com_Printf ("Bad pcx file %s\n", filename);
+
+ //
+ // parse the PCX file
+ //
+ pcx = (pcx_t *)raw;
+ raw = &pcx->data;
+
+ if (pcx->manufacturer != 0x0a
+ || pcx->version != 5
+ || pcx->encoding != 1
+ || pcx->bits_per_pixel != 8
+ || pcx->xmax >= 640
+ || pcx->ymax >= 480)
+ {
+ Com_Printf ("Bad pcx file %s\n", filename);
+ return;
+ }
+
+ out = Z_Malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
+
+ *pic = out;
+
+ pix = out;
+
+ if (palette)
+ {
+ *palette = Z_Malloc(768);
+ memcpy (*palette, (byte *)pcx + len - 768, 768);
+ }
+
+ if (width)
+ *width = pcx->xmax+1;
+ if (height)
+ *height = pcx->ymax+1;
+
+ for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
+ {
+ for (x=0 ; x<=pcx->xmax ; )
+ {
+ dataByte = *raw++;
+
+ if((dataByte & 0xC0) == 0xC0)
+ {
+ runLength = dataByte & 0x3F;
+ dataByte = *raw++;
+ }
+ else
+ runLength = 1;
+
+ while(runLength-- > 0)
+ pix[x++] = dataByte;
+ }
+
+ }
+
+ if ( raw - (byte *)pcx > len)
+ {
+ Com_Printf ("PCX file %s was malformed", filename);
+ Z_Free (*pic);
+ *pic = NULL;
+ }
+
+ FS_FreeFile (pcx);
+}
+
+//=============================================================
+
+/*
+==================
+SCR_StopCinematic
+==================
+*/
+void SCR_StopCinematic (void)
+{
+ cl.cinematictime = 0; // done
+ if (cin.pic)
+ {
+ Z_Free (cin.pic);
+ cin.pic = NULL;
+ }
+ if (cin.pic_pending)
+ {
+ Z_Free (cin.pic_pending);
+ cin.pic_pending = NULL;
+ }
+ if (cl.cinematicpalette_active)
+ {
+ re.CinematicSetPalette(NULL);
+ cl.cinematicpalette_active = false;
+ }
+ if (cl.cinematic_file)
+ {
+ fclose (cl.cinematic_file);
+ cl.cinematic_file = NULL;
+ }
+ if (cin.hnodes1)
+ {
+ Z_Free (cin.hnodes1);
+ cin.hnodes1 = NULL;
+ }
+
+ // switch back down to 11 khz sound if necessary
+ if (cin.restart_sound)
+ {
+ cin.restart_sound = false;
+ CL_Snd_Restart_f ();
+ }
+
+}
+
+/*
+====================
+SCR_FinishCinematic
+
+Called when either the cinematic completes, or it is aborted
+====================
+*/
+void SCR_FinishCinematic (void)
+{
+ // tell the server to advance to the next map / cinematic
+ MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+ SZ_Print (&cls.netchan.message, va("nextserver %i\n", cl.servercount));
+}
+
+//==========================================================================
+
+/*
+==================
+SmallestNode1
+==================
+*/
+int SmallestNode1 (int numhnodes)
+{
+ int i;
+ int best, bestnode;
+
+ best = 99999999;
+ bestnode = -1;
+ for (i=0 ; i<numhnodes ; i++)
+ {
+ if (cin.h_used[i])
+ continue;
+ if (!cin.h_count[i])
+ continue;
+ if (cin.h_count[i] < best)
+ {
+ best = cin.h_count[i];
+ bestnode = i;
+ }
+ }
+
+ if (bestnode == -1)
+ return -1;
+
+ cin.h_used[bestnode] = true;
+ return bestnode;
+}
+
+
+/*
+==================
+Huff1TableInit
+
+Reads the 64k counts table and initializes the node trees
+==================
+*/
+void Huff1TableInit (void)
+{
+ int prev;
+ int j;
+ int *node, *nodebase;
+ byte counts[256];
+ int numhnodes;
+
+ cin.hnodes1 = Z_Malloc (256*256*2*4);
+ memset (cin.hnodes1, 0, 256*256*2*4);
+
+ for (prev=0 ; prev<256 ; prev++)
+ {
+ memset (cin.h_count,0,sizeof(cin.h_count));
+ memset (cin.h_used,0,sizeof(cin.h_used));
+
+ // read a row of counts
+ FS_Read (counts, sizeof(counts), cl.cinematic_file);
+ for (j=0 ; j<256 ; j++)
+ cin.h_count[j] = counts[j];
+
+ // build the nodes
+ numhnodes = 256;
+ nodebase = cin.hnodes1 + prev*256*2;
+
+ while (numhnodes != 511)
+ {
+ node = nodebase + (numhnodes-256)*2;
+
+ // pick two lowest counts
+ node[0] = SmallestNode1 (numhnodes);
+ if (node[0] == -1)
+ break; // no more
+
+ node[1] = SmallestNode1 (numhnodes);
+ if (node[1] == -1)
+ break;
+
+ cin.h_count[numhnodes] = cin.h_count[node[0]] + cin.h_count[node[1]];
+ numhnodes++;
+ }
+
+ cin.numhnodes1[prev] = numhnodes-1;
+ }
+}
+
+/*
+==================
+Huff1Decompress
+==================
+*/
+cblock_t Huff1Decompress (cblock_t in)
+{
+ byte *input;
+ byte *out_p;
+ int nodenum;
+ int count;
+ cblock_t out;
+ int inbyte;
+ int *hnodes, *hnodesbase;
+//int i;
+
+ // get decompressed count
+ count = in.data[0] + (in.data[1]<<8) + (in.data[2]<<16) + (in.data[3]<<24);
+ input = in.data + 4;
+ out_p = out.data = Z_Malloc (count);
+
+ // read bits
+
+ hnodesbase = cin.hnodes1 - 256*2; // nodes 0-255 aren't stored
+
+ hnodes = hnodesbase;
+ nodenum = cin.numhnodes1[0];
+ while (count)
+ {
+ inbyte = *input++;
+ //-----------
+ if (nodenum < 256)
+ {
+ hnodes = hnodesbase + (nodenum<<9);
+ *out_p++ = nodenum;
+ if (!--count)
+ break;
+ nodenum = cin.numhnodes1[nodenum];
+ }
+ nodenum = hnodes[nodenum*2 + (inbyte&1)];
+ inbyte >>=1;
+ //-----------
+ if (nodenum < 256)
+ {
+ hnodes = hnodesbase + (nodenum<<9);
+ *out_p++ = nodenum;
+ if (!--count)
+ break;
+ nodenum = cin.numhnodes1[nodenum];
+ }
+ nodenum = hnodes[nodenum*2 + (inbyte&1)];
+ inbyte >>=1;
+ //-----------
+ if (nodenum < 256)
+ {
+ hnodes = hnodesbase + (nodenum<<9);
+ *out_p++ = nodenum;
+ if (!--count)
+ break;
+ nodenum = cin.numhnodes1[nodenum];
+ }
+ nodenum = hnodes[nodenum*2 + (inbyte&1)];
+ inbyte >>=1;
+ //-----------
+ if (nodenum < 256)
+ {
+ hnodes = hnodesbase + (nodenum<<9);
+ *out_p++ = nodenum;
+ if (!--count)
+ break;
+ nodenum = cin.numhnodes1[nodenum];
+ }
+ nodenum = hnodes[nodenum*2 + (inbyte&1)];
+ inbyte >>=1;
+ //-----------
+ if (nodenum < 256)
+ {
+ hnodes = hnodesbase + (nodenum<<9);
+ *out_p++ = nodenum;
+ if (!--count)
+ break;
+ nodenum = cin.numhnodes1[nodenum];
+ }
+ nodenum = hnodes[nodenum*2 + (inbyte&1)];
+ inbyte >>=1;
+ //-----------
+ if (nodenum < 256)
+ {
+ hnodes = hnodesbase + (nodenum<<9);
+ *out_p++ = nodenum;
+ if (!--count)
+ break;
+ nodenum = cin.numhnodes1[nodenum];
+ }
+ nodenum = hnodes[nodenum*2 + (inbyte&1)];
+ inbyte >>=1;
+ //-----------
+ if (nodenum < 256)
+ {
+ hnodes = hnodesbase + (nodenum<<9);
+ *out_p++ = nodenum;
+ if (!--count)
+ break;
+ nodenum = cin.numhnodes1[nodenum];
+ }
+ nodenum = hnodes[nodenum*2 + (inbyte&1)];
+ inbyte >>=1;
+ //-----------
+ if (nodenum < 256)
+ {
+ hnodes = hnodesbase + (nodenum<<9);
+ *out_p++ = nodenum;
+ if (!--count)
+ break;
+ nodenum = cin.numhnodes1[nodenum];
+ }
+ nodenum = hnodes[nodenum*2 + (inbyte&1)];
+ }
+
+ if (input - in.data != in.count && input - in.data != in.count+1)
+ {
+ Com_Printf ("Decompression overread by %i", (input - in.data) - in.count);
+ }
+ out.count = out_p - out.data;
+
+ return out;
+}
+
+/*
+==================
+SCR_ReadNextFrame
+==================
+*/
+byte *SCR_ReadNextFrame (void)
+{
+ int r;
+ int command;
+ byte samples[22050/14*4];
+ byte compressed[0x20000];
+ int size;
+ byte *pic;
+ cblock_t in, huf1;
+ int start, end, count;
+
+ // read the next frame
+ r = fread (&command, 4, 1, cl.cinematic_file);
+ if (r == 0) // we'll give it one more chance
+ r = fread (&command, 4, 1, cl.cinematic_file);
+
+ if (r != 1)
+ return NULL;
+ command = LittleLong(command);
+ if (command == 2)
+ return NULL; // last frame marker
+
+ if (command == 1)
+ { // read palette
+ FS_Read (cl.cinematicpalette, sizeof(cl.cinematicpalette), cl.cinematic_file);
+ cl.cinematicpalette_active=0; // dubious.... exposes an edge case
+ }
+
+ // decompress the next frame
+ FS_Read (&size, 4, cl.cinematic_file);
+ size = LittleLong(size);
+ if (size > sizeof(compressed) || size < 1)
+ Com_Error (ERR_DROP, "Bad compressed frame size");
+ FS_Read (compressed, size, cl.cinematic_file);
+
+ // read sound
+ start = cl.cinematicframe*cin.s_rate/14;
+ end = (cl.cinematicframe+1)*cin.s_rate/14;
+ count = end - start;
+
+ FS_Read (samples, count*cin.s_width*cin.s_channels, cl.cinematic_file);
+
+ S_RawSamples (count, cin.s_rate, cin.s_width, cin.s_channels, samples);
+
+ in.data = compressed;
+ in.count = size;
+
+ huf1 = Huff1Decompress (in);
+
+ pic = huf1.data;
+
+ cl.cinematicframe++;
+
+ return pic;
+}
+
+
+/*
+==================
+SCR_RunCinematic
+
+==================
+*/
+void SCR_RunCinematic (void)
+{
+ int frame;
+
+ if (cl.cinematictime <= 0)
+ {
+ SCR_StopCinematic ();
+ return;
+ }
+
+ if (cl.cinematicframe == -1)
+ return; // static image
+
+ if (cls.key_dest != key_game)
+ { // pause if menu or console is up
+ cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14;
+ return;
+ }
+
+ frame = (cls.realtime - cl.cinematictime)*14.0/1000;
+ if (frame <= cl.cinematicframe)
+ return;
+ if (frame > cl.cinematicframe+1)
+ {
+ Com_Printf ("Dropped frame: %i > %i\n", frame, cl.cinematicframe+1);
+ cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14;
+ }
+ if (cin.pic)
+ Z_Free (cin.pic);
+ cin.pic = cin.pic_pending;
+ cin.pic_pending = NULL;
+ cin.pic_pending = SCR_ReadNextFrame ();
+ if (!cin.pic_pending)
+ {
+ SCR_StopCinematic ();
+ SCR_FinishCinematic ();
+ cl.cinematictime = 1; // hack to get the black screen behind loading
+ SCR_BeginLoadingPlaque ();
+ cl.cinematictime = 0;
+ return;
+ }
+}
+
+/*
+==================
+SCR_DrawCinematic
+
+Returns true if a cinematic is active, meaning the view rendering
+should be skipped
+==================
+*/
+qboolean SCR_DrawCinematic (void)
+{
+ if (cl.cinematictime <= 0)
+ {
+ return false;
+ }
+
+ if (cls.key_dest == key_menu)
+ { // blank screen and pause if menu is up
+ re.CinematicSetPalette(NULL);
+ cl.cinematicpalette_active = false;
+ return true;
+ }
+
+ if (!cl.cinematicpalette_active)
+ {
+ re.CinematicSetPalette((uchar *)cl.cinematicpalette);
+ cl.cinematicpalette_active = true;
+ }
+
+ if (!cin.pic)
+ return true;
+
+ re.DrawStretchRaw (0, 0, vid.width, vid.height, cin.width, cin.height, cin.pic);
+
+ return true;
+}
+
+/*
+==================
+SCR_PlayCinematic
+
+==================
+*/
+void SCR_PlayCinematic (char *arg)
+{
+ int width, height;
+ byte *palette;
+ char name[MAX_OSPATH], *dot;
+ int old_khz;
+
+ // make sure CD isn't playing music
+ CDAudio_Stop();
+
+ cl.cinematicframe = 0;
+ dot = strstr (arg, ".");
+ if (dot && !strcmp (dot, ".pcx"))
+ { // static pcx image
+ Com_sprintf (name, sizeof(name), "pics/%s", arg);
+ SCR_LoadPCX (name, &cin.pic, &palette, &cin.width, &cin.height);
+ cl.cinematicframe = -1;
+ cl.cinematictime = 1;
+ SCR_EndLoadingPlaque ();
+ cls.state = ca_active;
+ if (!cin.pic)
+ {
+ Com_Printf ("%s not found.\n", name);
+ cl.cinematictime = 0;
+ }
+ else
+ {
+ memcpy (cl.cinematicpalette, palette, sizeof(cl.cinematicpalette));
+ Z_Free (palette);
+ }
+ return;
+ }
+
+ Com_sprintf (name, sizeof(name), "video/%s", arg);
+ FS_FOpenFile (name, &cl.cinematic_file);
+ if (!cl.cinematic_file)
+ {
+// Com_Error (ERR_DROP, "Cinematic %s not found.\n", name);
+ SCR_FinishCinematic ();
+ cl.cinematictime = 0; // done
+ return;
+ }
+
+ SCR_EndLoadingPlaque ();
+
+ cls.state = ca_active;
+
+ FS_Read (&width, 4, cl.cinematic_file);
+ FS_Read (&height, 4, cl.cinematic_file);
+ cin.width = LittleLong(width);
+ cin.height = LittleLong(height);
+
+ FS_Read (&cin.s_rate, 4, cl.cinematic_file);
+ cin.s_rate = LittleLong(cin.s_rate);
+ FS_Read (&cin.s_width, 4, cl.cinematic_file);
+ cin.s_width = LittleLong(cin.s_width);
+ FS_Read (&cin.s_channels, 4, cl.cinematic_file);
+ cin.s_channels = LittleLong(cin.s_channels);
+
+ Huff1TableInit ();
+
+ // switch up to 22 khz sound if necessary
+ old_khz = Cvar_VariableValue ("s_khz");
+ if (old_khz != cin.s_rate/1000)
+ {
+ cin.restart_sound = true;
+ Cvar_SetValue ("s_khz", cin.s_rate/1000);
+ CL_Snd_Restart_f ();
+ Cvar_SetValue ("s_khz", old_khz);
+ }
+
+ cl.cinematicframe = 0;
+ cin.pic = SCR_ReadNextFrame ();
+ cl.cinematictime = Sys_Milliseconds ();
+}
--- /dev/null
+++ b/cl_ents.c
@@ -1,0 +1,1479 @@
+// cl_ents.c -- entity parsing and management
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+
+extern model_t *cl_mod_powerscreen;
+int vidref_val;
+
+/*
+=========================================================================
+
+FRAME PARSING
+
+=========================================================================
+*/
+
+/* the following are commented out in release
+
+typedef struct
+{
+ int modelindex;
+ int num; // entity number
+ int effects;
+ vec3_t origin;
+ vec3_t oldorigin;
+ vec3_t angles;
+ qboolean present;
+} projectile_t;
+
+#define MAX_PROJECTILES 64
+projectile_t cl_projectiles[MAX_PROJECTILES];
+
+void CL_ClearProjectiles (void)
+{
+ int i;
+
+ for (i = 0; i < MAX_PROJECTILES; i++) {
+// if (cl_projectiles[i].present)
+// Com_DPrintf("PROJ: %d CLEARED\n", cl_projectiles[i].num);
+ cl_projectiles[i].present = false;
+ }
+}
+
+*/
+
+/*
+=====================
+CL_ParseProjectiles
+
+Flechettes are passed as efficient temporary entities
+=====================
+*/
+/*
+void CL_ParseProjectiles (void)
+{
+ int i, c, j;
+ byte bits[8];
+ byte b;
+ projectile_t pr;
+ int lastempty = -1;
+ qboolean old = false;
+
+ c = MSG_ReadByte (&net_message);
+ for (i=0 ; i<c ; i++)
+ {
+ bits[0] = MSG_ReadByte (&net_message);
+ bits[1] = MSG_ReadByte (&net_message);
+ bits[2] = MSG_ReadByte (&net_message);
+ bits[3] = MSG_ReadByte (&net_message);
+ bits[4] = MSG_ReadByte (&net_message);
+ pr.origin[0] = ( ( bits[0] + ((bits[1]&15)<<8) ) <<1) - 4096;
+ pr.origin[1] = ( ( (bits[1]>>4) + (bits[2]<<4) ) <<1) - 4096;
+ pr.origin[2] = ( ( bits[3] + ((bits[4]&15)<<8) ) <<1) - 4096;
+ VectorCopy(pr.origin, pr.oldorigin);
+
+ if (bits[4] & 64)
+ pr.effects = EF_BLASTER;
+ else
+ pr.effects = 0;
+
+ if (bits[4] & 128) {
+ old = true;
+ bits[0] = MSG_ReadByte (&net_message);
+ bits[1] = MSG_ReadByte (&net_message);
+ bits[2] = MSG_ReadByte (&net_message);
+ bits[3] = MSG_ReadByte (&net_message);
+ bits[4] = MSG_ReadByte (&net_message);
+ pr.oldorigin[0] = ( ( bits[0] + ((bits[1]&15)<<8) ) <<1) - 4096;
+ pr.oldorigin[1] = ( ( (bits[1]>>4) + (bits[2]<<4) ) <<1) - 4096;
+ pr.oldorigin[2] = ( ( bits[3] + ((bits[4]&15)<<8) ) <<1) - 4096;
+ }
+
+ bits[0] = MSG_ReadByte (&net_message);
+ bits[1] = MSG_ReadByte (&net_message);
+ bits[2] = MSG_ReadByte (&net_message);
+
+ pr.angles[0] = 360*bits[0]/256;
+ pr.angles[1] = 360*bits[1]/256;
+ pr.modelindex = bits[2];
+
+ b = MSG_ReadByte (&net_message);
+ pr.num = (b & 0x7f);
+ if (b & 128) // extra entity number byte
+ pr.num |= (MSG_ReadByte (&net_message) << 7);
+
+ pr.present = true;
+
+ // find if this projectile already exists from previous frame
+ for (j = 0; j < MAX_PROJECTILES; j++) {
+ if (cl_projectiles[j].modelindex) {
+ if (cl_projectiles[j].num == pr.num) {
+ // already present, set up oldorigin for interpolation
+ if (!old)
+ VectorCopy(cl_projectiles[j].origin, pr.oldorigin);
+ cl_projectiles[j] = pr;
+ break;
+ }
+ } else
+ lastempty = j;
+ }
+
+ // not present previous frame, add it
+ if (j == MAX_PROJECTILES) {
+ if (lastempty != -1) {
+ cl_projectiles[lastempty] = pr;
+ }
+ }
+ }
+}
+*/
+
+/*
+=============
+CL_LinkProjectiles
+
+=============
+*/
+/*
+void CL_AddProjectiles (void)
+{
+ int i, j;
+ projectile_t *pr;
+ entity_t ent;
+
+ memset (&ent, 0, sizeof(ent));
+
+ for (i=0, pr=cl_projectiles ; i < MAX_PROJECTILES ; i++, pr++)
+ {
+ // grab an entity to fill in
+ if (pr->modelindex < 1)
+ continue;
+ if (!pr->present) {
+ pr->modelindex = 0;
+ continue; // not present this frame (it was in the previous frame)
+ }
+
+ ent.model = cl.model_draw[pr->modelindex];
+
+ // interpolate origin
+ for (j=0 ; j<3 ; j++)
+ {
+ ent.origin[j] = ent.oldorigin[j] = pr->oldorigin[j] + cl.lerpfrac *
+ (pr->origin[j] - pr->oldorigin[j]);
+
+ }
+
+ if (pr->effects & EF_BLASTER)
+ CL_BlasterTrail (pr->oldorigin, ent.origin);
+ V_AddLight (pr->origin, 200, 1, 1, 0);
+
+ VectorCopy (pr->angles, ent.angles);
+ V_AddEntity (&ent);
+ }
+}
+*/
+
+/*
+=================
+CL_ParseEntityBits
+
+Returns the entity number and the header bits
+=================
+*/
+int bitcounts[32]; /// just for protocol profiling
+int CL_ParseEntityBits (int *bits)
+{
+ unsigned b, total;
+ int i;
+ int number;
+
+ total = MSG_ReadByte (&net_message);
+ if (total & U_MOREBITS1)
+ {
+ b = MSG_ReadByte (&net_message);
+ total |= b<<8;
+ }
+ if (total & U_MOREBITS2)
+ {
+ b = MSG_ReadByte (&net_message);
+ total |= b<<16;
+ }
+ if (total & U_MOREBITS3)
+ {
+ b = MSG_ReadByte (&net_message);
+ total |= b<<24;
+ }
+
+ // count the bits for net profiling
+ for (i=0 ; i<32 ; i++)
+ if (total&(1<<i))
+ bitcounts[i]++;
+
+ if (total & U_NUMBER16)
+ number = MSG_ReadShort (&net_message);
+ else
+ number = MSG_ReadByte (&net_message);
+
+ *bits = total;
+
+ return number;
+}
+
+/*
+==================
+CL_ParseDelta
+
+Can go from either a baseline or a previous packet_entity
+==================
+*/
+void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int number, int bits)
+{
+ // set everything to the state we are delta'ing from
+ *to = *from;
+
+ VectorCopy (from->origin, to->old_origin);
+ to->number = number;
+
+ if (bits & U_MODEL)
+ to->modelindex = MSG_ReadByte (&net_message);
+ if (bits & U_MODEL2)
+ to->modelindex2 = MSG_ReadByte (&net_message);
+ if (bits & U_MODEL3)
+ to->modelindex3 = MSG_ReadByte (&net_message);
+ if (bits & U_MODEL4)
+ to->modelindex4 = MSG_ReadByte (&net_message);
+
+ if (bits & U_FRAME8)
+ to->frame = MSG_ReadByte (&net_message);
+ if (bits & U_FRAME16)
+ to->frame = MSG_ReadShort (&net_message);
+
+ if ((bits & U_SKIN8) && (bits & U_SKIN16)) //used for laser colors
+ to->skinnum = MSG_ReadLong(&net_message);
+ else if (bits & U_SKIN8)
+ to->skinnum = MSG_ReadByte(&net_message);
+ else if (bits & U_SKIN16)
+ to->skinnum = MSG_ReadShort(&net_message);
+
+ if ( (bits & (U_EFFECTS8|U_EFFECTS16)) == (U_EFFECTS8|U_EFFECTS16) )
+ to->effects = MSG_ReadLong(&net_message);
+ else if (bits & U_EFFECTS8)
+ to->effects = MSG_ReadByte(&net_message);
+ else if (bits & U_EFFECTS16)
+ to->effects = MSG_ReadShort(&net_message);
+
+ if ( (bits & (U_RENDERFX8|U_RENDERFX16)) == (U_RENDERFX8|U_RENDERFX16) )
+ to->renderfx = MSG_ReadLong(&net_message);
+ else if (bits & U_RENDERFX8)
+ to->renderfx = MSG_ReadByte(&net_message);
+ else if (bits & U_RENDERFX16)
+ to->renderfx = MSG_ReadShort(&net_message);
+
+ if (bits & U_ORIGIN1)
+ to->origin[0] = MSG_ReadCoord (&net_message);
+ if (bits & U_ORIGIN2)
+ to->origin[1] = MSG_ReadCoord (&net_message);
+ if (bits & U_ORIGIN3)
+ to->origin[2] = MSG_ReadCoord (&net_message);
+
+ if (bits & U_ANGLE1)
+ to->angles[0] = MSG_ReadAngle(&net_message);
+ if (bits & U_ANGLE2)
+ to->angles[1] = MSG_ReadAngle(&net_message);
+ if (bits & U_ANGLE3)
+ to->angles[2] = MSG_ReadAngle(&net_message);
+
+ if (bits & U_OLDORIGIN)
+ MSG_ReadPos (&net_message, to->old_origin);
+
+ if (bits & U_SOUND)
+ to->sound = MSG_ReadByte (&net_message);
+
+ if (bits & U_EVENT)
+ to->event = MSG_ReadByte (&net_message);
+ else
+ to->event = 0;
+
+ if (bits & U_SOLID)
+ to->solid = MSG_ReadShort (&net_message);
+}
+
+/*
+==================
+CL_DeltaEntity
+
+Parses deltas from the given base and adds the resulting entity
+to the current frame
+==================
+*/
+void CL_DeltaEntity (frame_t *frame, int newnum, entity_state_t *old, int bits)
+{
+ centity_t *ent;
+ entity_state_t *state;
+
+ ent = &cl_entities[newnum];
+
+ state = &cl_parse_entities[cl.parse_entities & (MAX_PARSE_ENTITIES-1)];
+ cl.parse_entities++;
+ frame->num_entities++;
+
+ CL_ParseDelta (old, state, newnum, bits);
+
+ // some data changes will force no lerping
+ if (state->modelindex != ent->current.modelindex
+ || state->modelindex2 != ent->current.modelindex2
+ || state->modelindex3 != ent->current.modelindex3
+ || state->modelindex4 != ent->current.modelindex4
+ || abs(state->origin[0] - ent->current.origin[0]) > 512
+ || abs(state->origin[1] - ent->current.origin[1]) > 512
+ || abs(state->origin[2] - ent->current.origin[2]) > 512
+ || state->event == EV_PLAYER_TELEPORT
+ || state->event == EV_OTHER_TELEPORT
+ )
+ {
+ ent->serverframe = -99;
+ }
+
+ if (ent->serverframe != cl.frame.serverframe - 1)
+ { // wasn't in last update, so initialize some things
+ ent->trailcount = 1024; // for diminishing rocket / grenade trails
+ // duplicate the current state so lerping doesn't hurt anything
+ ent->prev = *state;
+ if (state->event == EV_OTHER_TELEPORT)
+ {
+ VectorCopy (state->origin, ent->prev.origin);
+ VectorCopy (state->origin, ent->lerp_origin);
+ }
+ else
+ {
+ VectorCopy (state->old_origin, ent->prev.origin);
+ VectorCopy (state->old_origin, ent->lerp_origin);
+ }
+ }
+ else
+ { // shuffle the last state to previous
+ ent->prev = ent->current;
+ }
+
+ ent->serverframe = cl.frame.serverframe;
+ ent->current = *state;
+}
+
+/*
+==================
+CL_ParsePacketEntities
+
+An svc_packetentities has just been parsed, deal with the
+rest of the data stream.
+==================
+*/
+void CL_ParsePacketEntities (frame_t *oldframe, frame_t *newframe)
+{
+ int newnum;
+ int bits;
+ entity_state_t *oldstate = nil;
+ int oldindex, oldnum;
+
+ newframe->parse_entities = cl.parse_entities;
+ newframe->num_entities = 0;
+
+ // delta from the entities present in oldframe
+ oldindex = 0;
+ if (!oldframe)
+ oldnum = 99999;
+ else
+ {
+ if (oldindex >= oldframe->num_entities)
+ oldnum = 99999;
+ else
+ {
+ oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
+ oldnum = oldstate->number;
+ }
+ }
+
+ while (1)
+ {
+ newnum = CL_ParseEntityBits (&bits);
+ if (newnum >= MAX_EDICTS)
+ Com_Error (ERR_DROP,"CL_ParsePacketEntities: bad number:%i", newnum);
+
+ if (net_message.readcount > net_message.cursize)
+ Com_Error (ERR_DROP,"CL_ParsePacketEntities: end of message");
+
+ if (!newnum)
+ break;
+
+ while (oldnum < newnum)
+ { // one or more entities from the old packet are unchanged
+ if (cl_shownet->value == 3)
+ Com_Printf (" unchanged: %i\n", oldnum);
+ CL_DeltaEntity (newframe, oldnum, oldstate, 0);
+
+ oldindex++;
+
+ if (oldindex >= oldframe->num_entities)
+ oldnum = 99999;
+ else
+ {
+ oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
+ oldnum = oldstate->number;
+ }
+ }
+
+ if (bits & U_REMOVE)
+ { // the entity present in oldframe is not in the current frame
+ if (cl_shownet->value == 3)
+ Com_Printf (" remove: %i\n", newnum);
+ if (oldnum != newnum)
+ Com_Printf ("U_REMOVE: oldnum != newnum\n");
+
+ oldindex++;
+
+ if (oldindex >= oldframe->num_entities)
+ oldnum = 99999;
+ else
+ {
+ oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
+ oldnum = oldstate->number;
+ }
+ continue;
+ }
+
+ if (oldnum == newnum)
+ { // delta from previous state
+ if (cl_shownet->value == 3)
+ Com_Printf (" delta: %i\n", newnum);
+ CL_DeltaEntity (newframe, newnum, oldstate, bits);
+
+ oldindex++;
+
+ if (oldindex >= oldframe->num_entities)
+ oldnum = 99999;
+ else
+ {
+ oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
+ oldnum = oldstate->number;
+ }
+ continue;
+ }
+
+ if (oldnum > newnum)
+ { // delta from baseline
+ if (cl_shownet->value == 3)
+ Com_Printf (" baseline: %i\n", newnum);
+ CL_DeltaEntity (newframe, newnum, &cl_entities[newnum].baseline, bits);
+ continue;
+ }
+
+ }
+
+ // any remaining entities in the old frame are copied over
+ while (oldnum != 99999)
+ { // one or more entities from the old packet are unchanged
+ if (cl_shownet->value == 3)
+ Com_Printf (" unchanged: %i\n", oldnum);
+ CL_DeltaEntity (newframe, oldnum, oldstate, 0);
+
+ oldindex++;
+
+ if (oldindex >= oldframe->num_entities)
+ oldnum = 99999;
+ else
+ {
+ oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
+ oldnum = oldstate->number;
+ }
+ }
+}
+
+
+
+/*
+===================
+CL_ParsePlayerstate
+===================
+*/
+void CL_ParsePlayerstate (frame_t *oldframe, frame_t *newframe)
+{
+ int flags;
+ player_state_t *state;
+ int i;
+ int statbits;
+
+ state = &newframe->playerstate;
+
+ // clear to old value before delta parsing
+ if (oldframe)
+ *state = oldframe->playerstate;
+ else
+ memset (state, 0, sizeof(*state));
+
+ flags = MSG_ReadShort (&net_message);
+
+ //
+ // parse the pmove_state_t
+ //
+ if (flags & PS_M_TYPE)
+ state->pmove.pm_type = MSG_ReadByte (&net_message);
+
+ if (flags & PS_M_ORIGIN)
+ {
+ state->pmove.origin[0] = MSG_ReadShort (&net_message);
+ state->pmove.origin[1] = MSG_ReadShort (&net_message);
+ state->pmove.origin[2] = MSG_ReadShort (&net_message);
+ }
+
+ if (flags & PS_M_VELOCITY)
+ {
+ state->pmove.velocity[0] = MSG_ReadShort (&net_message);
+ state->pmove.velocity[1] = MSG_ReadShort (&net_message);
+ state->pmove.velocity[2] = MSG_ReadShort (&net_message);
+ }
+
+ if (flags & PS_M_TIME)
+ state->pmove.pm_time = MSG_ReadByte (&net_message);
+
+ if (flags & PS_M_FLAGS)
+ state->pmove.pm_flags = MSG_ReadByte (&net_message);
+
+ if (flags & PS_M_GRAVITY)
+ state->pmove.gravity = MSG_ReadShort (&net_message);
+
+ if (flags & PS_M_DELTA_ANGLES)
+ {
+ state->pmove.delta_angles[0] = MSG_ReadShort (&net_message);
+ state->pmove.delta_angles[1] = MSG_ReadShort (&net_message);
+ state->pmove.delta_angles[2] = MSG_ReadShort (&net_message);
+ }
+
+ if (cl.attractloop)
+ state->pmove.pm_type = PM_FREEZE; // demo playback
+
+ //
+ // parse the rest of the player_state_t
+ //
+ if (flags & PS_VIEWOFFSET)
+ {
+ state->viewoffset[0] = MSG_ReadChar (&net_message) * 0.25;
+ state->viewoffset[1] = MSG_ReadChar (&net_message) * 0.25;
+ state->viewoffset[2] = MSG_ReadChar (&net_message) * 0.25;
+ }
+
+ if (flags & PS_VIEWANGLES)
+ {
+ state->viewangles[0] = MSG_ReadAngle16 (&net_message);
+ state->viewangles[1] = MSG_ReadAngle16 (&net_message);
+ state->viewangles[2] = MSG_ReadAngle16 (&net_message);
+ }
+
+ if (flags & PS_KICKANGLES)
+ {
+ state->kick_angles[0] = MSG_ReadChar (&net_message) * 0.25;
+ state->kick_angles[1] = MSG_ReadChar (&net_message) * 0.25;
+ state->kick_angles[2] = MSG_ReadChar (&net_message) * 0.25;
+ }
+
+ if (flags & PS_WEAPONINDEX)
+ {
+ state->gunindex = MSG_ReadByte (&net_message);
+ }
+
+ if (flags & PS_WEAPONFRAME)
+ {
+ state->gunframe = MSG_ReadByte (&net_message);
+ state->gunoffset[0] = MSG_ReadChar (&net_message)*0.25;
+ state->gunoffset[1] = MSG_ReadChar (&net_message)*0.25;
+ state->gunoffset[2] = MSG_ReadChar (&net_message)*0.25;
+ state->gunangles[0] = MSG_ReadChar (&net_message)*0.25;
+ state->gunangles[1] = MSG_ReadChar (&net_message)*0.25;
+ state->gunangles[2] = MSG_ReadChar (&net_message)*0.25;
+ }
+
+ if (flags & PS_BLEND)
+ {
+ state->blend[0] = MSG_ReadByte (&net_message)/255.0;
+ state->blend[1] = MSG_ReadByte (&net_message)/255.0;
+ state->blend[2] = MSG_ReadByte (&net_message)/255.0;
+ state->blend[3] = MSG_ReadByte (&net_message)/255.0;
+ }
+
+ if (flags & PS_FOV)
+ state->fov = MSG_ReadByte (&net_message);
+
+ if (flags & PS_RDFLAGS)
+ state->rdflags = MSG_ReadByte (&net_message);
+
+ // parse stats
+ statbits = MSG_ReadLong (&net_message);
+ for (i=0 ; i<MAX_STATS ; i++)
+ if (statbits & (1<<i) )
+ state->stats[i] = MSG_ReadShort(&net_message);
+}
+
+
+/*
+==================
+CL_FireEntityEvents
+
+==================
+*/
+void CL_FireEntityEvents (frame_t *frame)
+{
+ entity_state_t *s1;
+ int pnum, num;
+
+ for (pnum = 0 ; pnum<frame->num_entities ; pnum++)
+ {
+ num = (frame->parse_entities + pnum)&(MAX_PARSE_ENTITIES-1);
+ s1 = &cl_parse_entities[num];
+ if (s1->event)
+ CL_EntityEvent (s1);
+
+ // EF_TELEPORTER acts like an event, but is not cleared each frame
+ if (s1->effects & EF_TELEPORTER)
+ CL_TeleporterParticles (s1);
+ }
+}
+
+
+/*
+================
+CL_ParseFrame
+================
+*/
+void CL_ParseFrame (void)
+{
+ int cmd;
+ int len;
+ frame_t *old;
+
+ memset (&cl.frame, 0, sizeof(cl.frame));
+
+/*
+ CL_ClearProjectiles(); // clear projectiles for new frame
+*/
+
+ cl.frame.serverframe = MSG_ReadLong (&net_message);
+ cl.frame.deltaframe = MSG_ReadLong (&net_message);
+ cl.frame.servertime = cl.frame.serverframe*100;
+
+ // BIG HACK to let old demos continue to work
+ if (cls.serverProtocol != 26)
+ cl.surpressCount = MSG_ReadByte (&net_message);
+
+ if (cl_shownet->value == 3)
+ Com_Printf (" frame:%i delta:%i\n", cl.frame.serverframe,
+ cl.frame.deltaframe);
+
+ // If the frame is delta compressed from data that we
+ // no longer have available, we must suck up the rest of
+ // the frame, but not use it, then ask for a non-compressed
+ // message
+ if (cl.frame.deltaframe <= 0)
+ {
+ cl.frame.valid = true; // uncompressed frame
+ old = NULL;
+ cls.demowaiting = false; // we can start recording now
+ }
+ else
+ {
+ old = &cl.frames[cl.frame.deltaframe & UPDATE_MASK];
+ if (!old->valid)
+ { // should never happen
+ Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
+ }
+ if (old->serverframe != cl.frame.deltaframe)
+ { // The frame that the server did the delta from
+ // is too old, so we can't reconstruct it properly.
+ Com_Printf ("Delta frame too old.\n");
+ }
+ else if (cl.parse_entities - old->parse_entities > MAX_PARSE_ENTITIES-128)
+ {
+ Com_Printf ("Delta parse_entities too old.\n");
+ }
+ else
+ cl.frame.valid = true; // valid delta parse
+ }
+
+ // clamp time
+ if (cl.time > cl.frame.servertime)
+ cl.time = cl.frame.servertime;
+ else if (cl.time < cl.frame.servertime - 100)
+ cl.time = cl.frame.servertime - 100;
+
+ // read areabits
+ len = MSG_ReadByte (&net_message);
+ MSG_ReadData (&net_message, cl.frame.areabits, len);
+
+ // read playerinfo
+ cmd = MSG_ReadByte (&net_message);
+ SHOWNET(svc_strings[cmd]);
+ if (cmd != svc_playerinfo)
+ Com_Error (ERR_DROP, "CL_ParseFrame: not playerinfo");
+ CL_ParsePlayerstate (old, &cl.frame);
+
+ // read packet entities
+ cmd = MSG_ReadByte (&net_message);
+ SHOWNET(svc_strings[cmd]);
+ if (cmd != svc_packetentities)
+ Com_Error (ERR_DROP, "CL_ParseFrame: not packetentities");
+ CL_ParsePacketEntities (old, &cl.frame);
+
+/*
+ if (cmd == svc_packetentities2)
+ CL_ParseProjectiles();
+*/
+
+ // save the frame off in the backup array for later delta comparisons
+ cl.frames[cl.frame.serverframe & UPDATE_MASK] = cl.frame;
+
+ if (cl.frame.valid)
+ {
+ // getting a valid frame message ends the connection process
+ if (cls.state != ca_active)
+ {
+ cls.state = ca_active;
+ cl.force_refdef = true;
+ cl.predicted_origin[0] = cl.frame.playerstate.pmove.origin[0]*0.125;
+ cl.predicted_origin[1] = cl.frame.playerstate.pmove.origin[1]*0.125;
+ cl.predicted_origin[2] = cl.frame.playerstate.pmove.origin[2]*0.125;
+ VectorCopy (cl.frame.playerstate.viewangles, cl.predicted_angles);
+ if (cls.disable_servercount != cl.servercount
+ && cl.refresh_prepped)
+ SCR_EndLoadingPlaque (); // get rid of loading plaque
+ }
+ cl.sound_prepped = true; // can start mixing ambient sounds
+
+ // fire entity events
+ CL_FireEntityEvents (&cl.frame);
+ CL_CheckPredictionError ();
+ }
+}
+
+/*
+==========================================================================
+
+INTERPOLATE BETWEEN FRAMES TO GET RENDERING PARMS
+
+==========================================================================
+*/
+
+model_t *
+S_RegisterSexedModel(entity_state_t *ent, char *base)
+{
+ int n;
+ char *p;
+ model_t *mdl;
+ char model[MAX_QPATH];
+ char buffer[MAX_QPATH];
+
+ // determine what model the client is using
+ model[0] = 0;
+ n = CS_PLAYERSKINS + ent->number - 1;
+ if (cl.configstrings[n][0])
+ {
+ p = strchr(cl.configstrings[n], '\\');
+ if (p)
+ {
+ p += 1;
+ strcpy(model, p);
+ p = strchr(model, '/');
+ if (p)
+ *p = 0;
+ }
+ }
+ // if we can't figure it out, they're male
+ if (!model[0])
+ strcpy(model, "male");
+
+ Com_sprintf (buffer, sizeof(buffer), "players/%s/%s", model, base+1);
+ mdl = re.RegisterModel(buffer);
+ if (!mdl) {
+ // not found, try default weapon model
+ Com_sprintf (buffer, sizeof(buffer), "players/%s/weapon.md2", model);
+ mdl = re.RegisterModel(buffer);
+ if (!mdl) {
+ // no, revert to the male model
+ Com_sprintf (buffer, sizeof(buffer), "players/%s/%s", "male", base+1);
+ mdl = re.RegisterModel(buffer);
+ if (!mdl) {
+ // last try, default male weapon.md2
+ Com_sprintf (buffer, sizeof(buffer), "players/male/weapon.md2");
+ mdl = re.RegisterModel(buffer);
+ }
+ }
+ }
+
+ return mdl;
+}
+
+/*
+===============
+CL_AddPacketEntities
+
+===============
+*/
+void CL_AddPacketEntities (frame_t *frame)
+{
+ entity_t ent;
+ entity_state_t *s1;
+ float autorotate;
+ int i;
+ int pnum;
+ centity_t *cent;
+ int autoanim;
+ clientinfo_t *ci;
+ unsigned int effects, renderfx;
+
+ // bonus items rotate at a fixed rate
+ autorotate = anglemod(cl.time/10);
+
+ // brush models can auto animate their frames
+ autoanim = 2*cl.time/1000;
+
+ memset (&ent, 0, sizeof(ent));
+
+ for (pnum = 0 ; pnum<frame->num_entities ; pnum++)
+ {
+ s1 = &cl_parse_entities[(frame->parse_entities+pnum)&(MAX_PARSE_ENTITIES-1)];
+
+ cent = &cl_entities[s1->number];
+
+ effects = s1->effects;
+ renderfx = s1->renderfx;
+
+ // set frame
+ if (effects & EF_ANIM01)
+ ent.frame = autoanim & 1;
+ else if (effects & EF_ANIM23)
+ ent.frame = 2 + (autoanim & 1);
+ else if (effects & EF_ANIM_ALL)
+ ent.frame = autoanim;
+ else if (effects & EF_ANIM_ALLFAST)
+ ent.frame = cl.time / 100;
+ else
+ ent.frame = s1->frame;
+
+ // quad and pent can do different things on client
+ if (effects & EF_PENT)
+ {
+ effects &= ~EF_PENT;
+ effects |= EF_COLOR_SHELL;
+ renderfx |= RF_SHELL_RED;
+ }
+
+ if (effects & EF_QUAD)
+ {
+ effects &= ~EF_QUAD;
+ effects |= EF_COLOR_SHELL;
+ renderfx |= RF_SHELL_BLUE;
+ }
+//======
+// PMM
+ if (effects & EF_DOUBLE)
+ {
+ effects &= ~EF_DOUBLE;
+ effects |= EF_COLOR_SHELL;
+ renderfx |= RF_SHELL_DOUBLE;
+ }
+
+ if (effects & EF_HALF_DAMAGE)
+ {
+ effects &= ~EF_HALF_DAMAGE;
+ effects |= EF_COLOR_SHELL;
+ renderfx |= RF_SHELL_HALF_DAM;
+ }
+// pmm
+//======
+ ent.oldframe = cent->prev.frame;
+ ent.backlerp = 1.0 - cl.lerpfrac;
+
+ if (renderfx & (RF_FRAMELERP|RF_BEAM))
+ { // step origin discretely, because the frames
+ // do the animation properly
+ VectorCopy (cent->current.origin, ent.origin);
+ VectorCopy (cent->current.old_origin, ent.oldorigin);
+ }
+ else
+ { // interpolate origin
+ for (i=0 ; i<3 ; i++)
+ {
+ ent.origin[i] = ent.oldorigin[i] = cent->prev.origin[i] + cl.lerpfrac *
+ (cent->current.origin[i] - cent->prev.origin[i]);
+ }
+ }
+
+ // create a new entity
+
+ // tweak the color of beams
+ if ( renderfx & RF_BEAM )
+ { // the four beam colors are encoded in 32 bits of skinnum (hack)
+ ent.alpha = 0.30;
+ ent.skinnum = (s1->skinnum >> ((rand() % 4)*8)) & 0xff;
+ ent.model = NULL;
+ }
+ else
+ {
+ // set skin
+ if (s1->modelindex == 255)
+ { // use custom player skin
+ ent.skinnum = 0;
+ ci = &cl.clientinfo[s1->skinnum & 0xff];
+ ent.skin = ci->skin;
+ ent.model = ci->model;
+ if (!ent.skin || !ent.model)
+ {
+ ent.skin = cl.baseclientinfo.skin;
+ ent.model = cl.baseclientinfo.model;
+ }
+
+//============
+//PGM
+ if (renderfx & RF_USE_DISGUISE)
+ {
+ if(!strncmp((char *)ent.skin, "players/male", 12))
+ {
+ ent.skin = re.RegisterSkin ("players/male/disguise.pcx");
+ ent.model = re.RegisterModel ("players/male/tris.md2");
+ }
+ else if(!strncmp((char *)ent.skin, "players/female", 14))
+ {
+ ent.skin = re.RegisterSkin ("players/female/disguise.pcx");
+ ent.model = re.RegisterModel ("players/female/tris.md2");
+ }
+ else if(!strncmp((char *)ent.skin, "players/cyborg", 14))
+ {
+ ent.skin = re.RegisterSkin ("players/cyborg/disguise.pcx");
+ ent.model = re.RegisterModel ("players/cyborg/tris.md2");
+ }
+ }
+//PGM
+//============
+ }
+ else
+ {
+ ent.skinnum = s1->skinnum;
+ ent.skin = NULL;
+ ent.model = cl.model_draw[s1->modelindex];
+ }
+ }
+
+ // only used for black hole model right now, FIXME: do better
+ if (renderfx == RF_TRANSLUCENT)
+ ent.alpha = 0.70;
+
+ // render effects (fullbright, translucent, etc)
+ if ((effects & EF_COLOR_SHELL))
+ ent.flags = 0; // renderfx go on color shell entity
+ else
+ ent.flags = renderfx;
+
+ // calculate angles
+ if (effects & EF_ROTATE)
+ { // some bonus items auto-rotate
+ ent.angles[0] = 0;
+ ent.angles[1] = autorotate;
+ ent.angles[2] = 0;
+ }
+ // RAFAEL
+ else if (effects & EF_SPINNINGLIGHTS)
+ {
+ ent.angles[0] = 0;
+ ent.angles[1] = anglemod(cl.time/2) + s1->angles[1];
+ ent.angles[2] = 180;
+ {
+ vec3_t forward;
+ vec3_t start;
+
+ AngleVectors (ent.angles, forward, NULL, NULL);
+ VectorMA (ent.origin, 64, forward, start);
+ V_AddLight (start, 100, 1, 0, 0);
+ }
+ }
+ else
+ { // interpolate angles
+ float a1, a2;
+
+ for (i=0 ; i<3 ; i++)
+ {
+ a1 = cent->current.angles[i];
+ a2 = cent->prev.angles[i];
+ ent.angles[i] = LerpAngle (a2, a1, cl.lerpfrac);
+ }
+ }
+
+ if (s1->number == cl.playernum+1)
+ {
+ ent.flags |= RF_VIEWERMODEL; // only draw from mirrors
+ // FIXME: still pass to refresh
+
+ if (effects & EF_FLAG1)
+ V_AddLight (ent.origin, 225, 1.0, 0.1, 0.1);
+ else if (effects & EF_FLAG2)
+ V_AddLight (ent.origin, 225, 0.1, 0.1, 1.0);
+ else if (effects & EF_TAGTRAIL) //PGM
+ V_AddLight (ent.origin, 225, 1.0, 1.0, 0.0); //PGM
+ else if (effects & EF_TRACKERTRAIL) //PGM
+ V_AddLight (ent.origin, 225, -1.0, -1.0, -1.0); //PGM
+
+ continue;
+ }
+
+ // if set to invisible, skip
+ if (!s1->modelindex)
+ continue;
+
+ if (effects & EF_BFG)
+ {
+ ent.flags |= RF_TRANSLUCENT;
+ ent.alpha = 0.30;
+ }
+
+ // RAFAEL
+ if (effects & EF_PLASMA)
+ {
+ ent.flags |= RF_TRANSLUCENT;
+ ent.alpha = 0.6;
+ }
+
+ if (effects & EF_SPHERETRANS)
+ {
+ ent.flags |= RF_TRANSLUCENT;
+ // PMM - *sigh* yet more EF overloading
+ if (effects & EF_TRACKERTRAIL)
+ ent.alpha = 0.6;
+ else
+ ent.alpha = 0.3;
+ }
+//pmm
+
+ // add to refresh list
+ V_AddEntity (&ent);
+
+ // color shells generate a seperate entity for the main model
+ if (effects & EF_COLOR_SHELL)
+ {
+ ent.flags = renderfx | RF_TRANSLUCENT;
+ ent.alpha = 0.30;
+ V_AddEntity (&ent);
+ }
+
+ ent.skin = NULL; // never use a custom skin on others
+ ent.skinnum = 0;
+ ent.flags = 0;
+ ent.alpha = 0;
+
+ // duplicate for linked models
+ if (s1->modelindex2)
+ {
+ if (s1->modelindex2 == 255)
+ { // custom weapon
+ ci = &cl.clientinfo[s1->skinnum & 0xff];
+ i = (s1->skinnum >> 8); // 0 is default weapon model
+ if (!cl_vwep->value || i > MAX_CLIENTWEAPONMODELS - 1)
+ i = 0;
+ ent.model = ci->weaponmodel[i];
+ if (!ent.model) {
+ if (i != 0)
+ ent.model = ci->weaponmodel[0];
+ if (!ent.model)
+ ent.model = cl.baseclientinfo.weaponmodel[0];
+ }
+ }
+ //PGM - hack to allow translucent linked models (defender sphere's shell)
+ // set the high bit 0x80 on modelindex2 to enable translucency
+ else if(s1->modelindex2 & 0x80)
+ {
+ ent.model = cl.model_draw[s1->modelindex2 & 0x7F];
+ ent.alpha = 0.32;
+ ent.flags = RF_TRANSLUCENT;
+ }
+ //PGM
+ else
+ ent.model = cl.model_draw[s1->modelindex2];
+ V_AddEntity (&ent);
+
+ //PGM - make sure these get reset.
+ ent.flags = 0;
+ ent.alpha = 0;
+ //PGM
+ }
+ if (s1->modelindex3)
+ {
+ ent.model = cl.model_draw[s1->modelindex3];
+ V_AddEntity (&ent);
+ }
+ if (s1->modelindex4)
+ {
+ ent.model = cl.model_draw[s1->modelindex4];
+ V_AddEntity (&ent);
+ }
+
+ if ( effects & EF_POWERSCREEN )
+ {
+ ent.model = cl_mod_powerscreen;
+ ent.oldframe = 0;
+ ent.frame = 0;
+ ent.flags |= (RF_TRANSLUCENT | RF_SHELL_GREEN);
+ ent.alpha = 0.30;
+ V_AddEntity (&ent);
+ }
+
+ // add automatic particle trails
+ if ( (effects&~EF_ROTATE) )
+ {
+ if (effects & EF_ROCKET)
+ {
+ CL_RocketTrail (cent->lerp_origin, ent.origin, cent);
+ V_AddLight (ent.origin, 200, 1, 1, 0);
+ }
+ // PGM - Do not reorder EF_BLASTER and EF_HYPERBLASTER.
+ // EF_BLASTER | EF_TRACKER is a special case for EF_BLASTER2... Cheese!
+ else if (effects & EF_BLASTER)
+ {
+// CL_BlasterTrail (cent->lerp_origin, ent.origin);
+//PGM
+ if (effects & EF_TRACKER) // lame... problematic?
+ {
+ CL_BlasterTrail2 (cent->lerp_origin, ent.origin);
+ V_AddLight (ent.origin, 200, 0, 1, 0);
+ }
+ else
+ {
+ CL_BlasterTrail (cent->lerp_origin, ent.origin);
+ V_AddLight (ent.origin, 200, 1, 1, 0);
+ }
+//PGM
+ }
+ else if (effects & EF_HYPERBLASTER)
+ {
+ if (effects & EF_TRACKER) // PGM overloaded for blaster2.
+ V_AddLight (ent.origin, 200, 0, 1, 0); // PGM
+ else // PGM
+ V_AddLight (ent.origin, 200, 1, 1, 0);
+ }
+ else if (effects & EF_GIB)
+ {
+ CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
+ }
+ else if (effects & EF_GRENADE)
+ {
+ CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
+ }
+ else if (effects & EF_FLIES)
+ {
+ CL_FlyEffect (cent, ent.origin);
+ }
+ else if (effects & EF_BFG)
+ {
+ static int bfg_lightramp[6] = {300, 400, 600, 300, 150, 75};
+
+ if (effects & EF_ANIM_ALLFAST)
+ {
+ CL_BfgParticles (&ent);
+ i = 200;
+ }
+ else
+ {
+ i = bfg_lightramp[s1->frame];
+ }
+ V_AddLight (ent.origin, i, 0, 1, 0);
+ }
+ // RAFAEL
+ else if (effects & EF_TRAP)
+ {
+ ent.origin[2] += 32;
+ CL_TrapParticles (&ent);
+ i = (rand()%100) + 100;
+ V_AddLight (ent.origin, i, 1, 0.8, 0.1);
+ }
+ else if (effects & EF_FLAG1)
+ {
+ CL_FlagTrail (cent->lerp_origin, ent.origin, 242);
+ V_AddLight (ent.origin, 225, 1, 0.1, 0.1);
+ }
+ else if (effects & EF_FLAG2)
+ {
+ CL_FlagTrail (cent->lerp_origin, ent.origin, 115);
+ V_AddLight (ent.origin, 225, 0.1, 0.1, 1);
+ }
+//======
+//ROGUE
+ else if (effects & EF_TAGTRAIL)
+ {
+ CL_TagTrail (cent->lerp_origin, ent.origin, 220);
+ V_AddLight (ent.origin, 225, 1.0, 1.0, 0.0);
+ }
+ else if (effects & EF_TRACKERTRAIL)
+ {
+ if (effects & EF_TRACKER)
+ {
+ float intensity;
+
+ intensity = 50 + (500 * (sin(cl.time/500.0) + 1.0));
+ // FIXME - check out this effect in rendition
+ if(vidref_val == VIDREF_GL)
+ V_AddLight (ent.origin, intensity, -1.0, -1.0, -1.0);
+ else
+ V_AddLight (ent.origin, -1.0 * intensity, 1.0, 1.0, 1.0);
+ }
+ else
+ {
+ CL_Tracker_Shell (cent->lerp_origin);
+ V_AddLight (ent.origin, 155, -1.0, -1.0, -1.0);
+ }
+ }
+ else if (effects & EF_TRACKER)
+ {
+ CL_TrackerTrail (cent->lerp_origin, ent.origin, 0);
+ // FIXME - check out this effect in rendition
+ if(vidref_val == VIDREF_GL)
+ V_AddLight (ent.origin, 200, -1, -1, -1);
+ else
+ V_AddLight (ent.origin, -200, 1, 1, 1);
+ }
+//ROGUE
+//======
+ // RAFAEL
+ else if (effects & EF_GREENGIB)
+ {
+ CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
+ }
+ // RAFAEL
+ else if (effects & EF_IONRIPPER)
+ {
+ CL_IonripperTrail (cent->lerp_origin, ent.origin);
+ V_AddLight (ent.origin, 100, 1, 0.5, 0.5);
+ }
+ // RAFAEL
+ else if (effects & EF_BLUEHYPERBLASTER)
+ {
+ V_AddLight (ent.origin, 200, 0, 0, 1);
+ }
+ // RAFAEL
+ else if (effects & EF_PLASMA)
+ {
+ if (effects & EF_ANIM_ALLFAST)
+ {
+ CL_BlasterTrail (cent->lerp_origin, ent.origin);
+ }
+ V_AddLight (ent.origin, 130, 1, 0.5, 0.5);
+ }
+ }
+
+ VectorCopy (ent.origin, cent->lerp_origin);
+ }
+}
+
+
+
+/*
+==============
+CL_AddViewWeapon
+==============
+*/
+void CL_AddViewWeapon (player_state_t *ps, player_state_t *ops)
+{
+ entity_t gun; // view model
+ int i;
+
+ // allow the gun to be completely removed
+ if (!cl_gun->value)
+ return;
+
+ // don't draw gun if in wide angle view
+ if (ps->fov > 90)
+ return;
+
+ memset (&gun, 0, sizeof(gun));
+
+ if (gun_model)
+ gun.model = gun_model; // development tool
+ else
+ gun.model = cl.model_draw[ps->gunindex];
+ if (!gun.model)
+ return;
+
+ // set up gun position
+ for (i=0 ; i<3 ; i++)
+ {
+ gun.origin[i] = cl.refdef.vieworg[i] + ops->gunoffset[i]
+ + cl.lerpfrac * (ps->gunoffset[i] - ops->gunoffset[i]);
+ gun.angles[i] = cl.refdef.viewangles[i] + LerpAngle (ops->gunangles[i],
+ ps->gunangles[i], cl.lerpfrac);
+ }
+
+ if (gun_frame)
+ {
+ gun.frame = gun_frame; // development tool
+ gun.oldframe = gun_frame; // development tool
+ }
+ else
+ {
+ gun.frame = ps->gunframe;
+ if (gun.frame == 0)
+ gun.oldframe = 0; // just changed weapons, don't lerp from old
+ else
+ gun.oldframe = ops->gunframe;
+ }
+
+ gun.flags = RF_MINLIGHT | RF_DEPTHHACK | RF_WEAPONMODEL;
+ gun.backlerp = 1.0 - cl.lerpfrac;
+ VectorCopy (gun.origin, gun.oldorigin); // don't lerp at all
+ V_AddEntity (&gun);
+}
+
+
+/*
+===============
+CL_CalcViewValues
+
+Sets cl.refdef view values
+===============
+*/
+void CL_CalcViewValues (void)
+{
+ int i;
+ float lerp, backlerp;
+ frame_t *oldframe;
+ player_state_t *ps, *ops;
+
+ // find the previous frame to interpolate from
+ ps = &cl.frame.playerstate;
+ i = (cl.frame.serverframe - 1) & UPDATE_MASK;
+ oldframe = &cl.frames[i];
+ if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid)
+ oldframe = &cl.frame; // previous frame was dropped or involid
+ ops = &oldframe->playerstate;
+
+ // see if the player entity was teleported this frame
+ if ( fabs(ops->pmove.origin[0] - ps->pmove.origin[0]) > 256*8
+ || abs(ops->pmove.origin[1] - ps->pmove.origin[1]) > 256*8
+ || abs(ops->pmove.origin[2] - ps->pmove.origin[2]) > 256*8)
+ ops = ps; // don't interpolate
+
+ lerp = cl.lerpfrac;
+
+ // calculate the origin
+ if ((cl_predict->value) && !(cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
+ { // use predicted values
+ unsigned delta;
+
+ backlerp = 1.0 - lerp;
+ for (i=0 ; i<3 ; i++)
+ {
+ cl.refdef.vieworg[i] = cl.predicted_origin[i] + ops->viewoffset[i]
+ + cl.lerpfrac * (ps->viewoffset[i] - ops->viewoffset[i])
+ - backlerp * cl.prediction_error[i];
+ }
+
+ // smooth out stair climbing
+ delta = cls.realtime - cl.predicted_step_time;
+ if (delta < 100)
+ cl.refdef.vieworg[2] -= cl.predicted_step * (100 - delta) * 0.01;
+ }
+ else
+ { // just use interpolated values
+ for (i=0 ; i<3 ; i++)
+ cl.refdef.vieworg[i] = ops->pmove.origin[i]*0.125 + ops->viewoffset[i]
+ + lerp * (ps->pmove.origin[i]*0.125 + ps->viewoffset[i]
+ - (ops->pmove.origin[i]*0.125 + ops->viewoffset[i]) );
+ }
+
+ // if not running a demo or on a locked frame, add the local angle movement
+ if ( cl.frame.playerstate.pmove.pm_type < PM_DEAD )
+ { // use predicted values
+ for (i=0 ; i<3 ; i++)
+ cl.refdef.viewangles[i] = cl.predicted_angles[i];
+ }
+ else
+ { // just use interpolated values
+ for (i=0 ; i<3 ; i++)
+ cl.refdef.viewangles[i] = LerpAngle (ops->viewangles[i], ps->viewangles[i], lerp);
+ }
+
+ for (i=0 ; i<3 ; i++)
+ cl.refdef.viewangles[i] += LerpAngle (ops->kick_angles[i], ps->kick_angles[i], lerp);
+
+ AngleVectors (cl.refdef.viewangles, cl.v_forward, cl.v_right, cl.v_up);
+
+ // interpolate field of view
+ cl.refdef.fov_x = ops->fov + lerp * (ps->fov - ops->fov);
+
+ // don't interpolate blend color
+ for (i=0 ; i<4 ; i++)
+ cl.refdef.blend[i] = ps->blend[i];
+
+ // add the weapon
+ CL_AddViewWeapon (ps, ops);
+}
+
+/*
+===============
+CL_AddEntities
+
+Emits all entities, particles, and lights to the refresh
+===============
+*/
+void CL_AddEntities (void)
+{
+ if (cls.state != ca_active)
+ return;
+
+ if (cl.time > cl.frame.servertime)
+ {
+ if (cl_showclamp->value)
+ Com_Printf ("high clamp %i\n", cl.time - cl.frame.servertime);
+ cl.time = cl.frame.servertime;
+ cl.lerpfrac = 1.0;
+ }
+ else if (cl.time < cl.frame.servertime - 100)
+ {
+ if (cl_showclamp->value)
+ Com_Printf ("low clamp %i\n", cl.frame.servertime-100 - cl.time);
+ cl.time = cl.frame.servertime - 100;
+ cl.lerpfrac = 0;
+ }
+ else
+ cl.lerpfrac = 1.0 - (cl.frame.servertime - cl.time) * 0.01;
+
+ if (cl_timedemo->value)
+ cl.lerpfrac = 1.0;
+
+// CL_AddPacketEntities (&cl.frame);
+// CL_AddTEnts ();
+// CL_AddParticles ();
+// CL_AddDLights ();
+// CL_AddLightStyles ();
+
+ CL_CalcViewValues ();
+ // PMM - moved this here so the heat beam has the right values for the vieworg, and can lock the beam to the gun
+ CL_AddPacketEntities (&cl.frame);
+/*
+ CL_AddProjectiles ();
+*/
+ CL_AddTEnts ();
+ CL_AddParticles ();
+ CL_AddDLights ();
+ CL_AddLightStyles ();
+}
+
+/* the sound code makes callbacks to the client for entitiy position
+ * information, so entities can be dynamically re-spatialized */
+void CL_GetEntitySoundOrigin (int ent, vec3_t org)
+{
+ centity_t *old;
+
+ if (ent < 0 || ent >= MAX_EDICTS)
+ Com_Error (ERR_DROP, "CL_GetEntitySoundOrigin: bad ent");
+ old = &cl_entities[ent];
+ VectorCopy (old->lerp_origin, org);
+
+ // FIXME: bmodel issues...
+}
--- /dev/null
+++ b/cl_fx.c
@@ -1,0 +1,2266 @@
+// cl_fx.c -- entity effects parsing and management
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+void CL_LogoutEffect (vec3_t org, int type);
+void CL_ItemRespawnParticles (vec3_t org);
+
+static vec3_t avelocities [NUMVERTEXNORMALS];
+
+extern model_t *cl_mod_smoke;
+extern model_t *cl_mod_flash;
+
+/*
+==============================================================
+
+LIGHT STYLE MANAGEMENT
+
+==============================================================
+*/
+
+typedef struct
+{
+ int length;
+ float value[3];
+ float map[MAX_QPATH];
+} clightstyle_t;
+
+clightstyle_t cl_lightstyle[MAX_LIGHTSTYLES];
+int lastofs;
+
+/*
+================
+CL_ClearLightStyles
+================
+*/
+void CL_ClearLightStyles (void)
+{
+ memset (cl_lightstyle, 0, sizeof(cl_lightstyle));
+ lastofs = -1;
+}
+
+/*
+================
+CL_RunLightStyles
+================
+*/
+void CL_RunLightStyles (void)
+{
+ int ofs;
+ int i;
+ clightstyle_t *ls;
+
+ ofs = cl.time / 100;
+ if (ofs == lastofs)
+ return;
+ lastofs = ofs;
+
+ for (i=0,ls=cl_lightstyle ; i<MAX_LIGHTSTYLES ; i++, ls++)
+ {
+ if (!ls->length)
+ {
+ ls->value[0] = ls->value[1] = ls->value[2] = 1.0;
+ continue;
+ }
+ if (ls->length == 1)
+ ls->value[0] = ls->value[1] = ls->value[2] = ls->map[0];
+ else
+ ls->value[0] = ls->value[1] = ls->value[2] = ls->map[ofs%ls->length];
+ }
+}
+
+
+void CL_SetLightstyle (int i)
+{
+ char *s;
+ int j, k;
+
+ s = cl.configstrings[i+CS_LIGHTS];
+
+ j = strlen (s);
+ if (j >= MAX_QPATH)
+ Com_Error (ERR_DROP, "svc_lightstyle length=%i", j);
+
+ cl_lightstyle[i].length = j;
+
+ for (k=0 ; k<j ; k++)
+ cl_lightstyle[i].map[k] = (float)(s[k]-'a')/(float)('m'-'a');
+}
+
+/*
+================
+CL_AddLightStyles
+================
+*/
+void CL_AddLightStyles (void)
+{
+ int i;
+ clightstyle_t *ls;
+
+ for (i=0,ls=cl_lightstyle ; i<MAX_LIGHTSTYLES ; i++, ls++)
+ V_AddLightStyle (i, ls->value[0], ls->value[1], ls->value[2]);
+}
+
+/*
+==============================================================
+
+DLIGHT MANAGEMENT
+
+==============================================================
+*/
+
+cdlight_t cl_dlights[MAX_DLIGHTS];
+
+/*
+================
+CL_ClearDlights
+================
+*/
+void CL_ClearDlights (void)
+{
+ memset (cl_dlights, 0, sizeof(cl_dlights));
+}
+
+/*
+===============
+CL_AllocDlight
+
+===============
+*/
+cdlight_t *CL_AllocDlight (int key)
+{
+ int i;
+ cdlight_t *dl;
+
+// first look for an exact key match
+ if (key)
+ {
+ dl = cl_dlights;
+ for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
+ {
+ if (dl->key == key)
+ {
+ memset (dl, 0, sizeof(*dl));
+ dl->key = key;
+ return dl;
+ }
+ }
+ }
+
+// then look for anything else
+ dl = cl_dlights;
+ for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
+ {
+ if (dl->die < cl.time)
+ {
+ memset (dl, 0, sizeof(*dl));
+ dl->key = key;
+ return dl;
+ }
+ }
+
+ dl = &cl_dlights[0];
+ memset (dl, 0, sizeof(*dl));
+ dl->key = key;
+ return dl;
+}
+
+/*
+===============
+CL_NewDlight
+===============
+*/
+void CL_NewDlight (int key, float x, float y, float z, float radius, float time)
+{
+ cdlight_t *dl;
+
+ dl = CL_AllocDlight (key);
+ dl->origin[0] = x;
+ dl->origin[1] = y;
+ dl->origin[2] = z;
+ dl->radius = radius;
+ dl->die = cl.time + time;
+}
+
+
+/*
+===============
+CL_RunDLights
+
+===============
+*/
+void CL_RunDLights (void)
+{
+ int i;
+ cdlight_t *dl;
+
+ dl = cl_dlights;
+ for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
+ {
+ if (!dl->radius)
+ continue;
+
+ if (dl->die < cl.time)
+ {
+ dl->radius = 0;
+ return;
+ }
+ dl->radius -= cls.frametime*dl->decay;
+ if (dl->radius < 0)
+ dl->radius = 0;
+ }
+}
+
+/*
+==============
+CL_ParseMuzzleFlash
+==============
+*/
+void CL_ParseMuzzleFlash (void)
+{
+ vec3_t fv, rv;
+ cdlight_t *dl;
+ int i, weapon;
+ centity_t *pl;
+ int silenced;
+ float volume;
+ char soundname[64];
+
+ i = MSG_ReadShort (&net_message);
+ if (i < 1 || i >= MAX_EDICTS)
+ Com_Error (ERR_DROP, "CL_ParseMuzzleFlash: bad entity");
+
+ weapon = MSG_ReadByte (&net_message);
+ silenced = weapon & MZ_SILENCED;
+ weapon &= ~MZ_SILENCED;
+
+ pl = &cl_entities[i];
+
+ dl = CL_AllocDlight (i);
+ VectorCopy (pl->current.origin, dl->origin);
+ AngleVectors (pl->current.angles, fv, rv, NULL);
+ VectorMA (dl->origin, 18, fv, dl->origin);
+ VectorMA (dl->origin, 16, rv, dl->origin);
+ if (silenced)
+ dl->radius = 100 + (rand()&31);
+ else
+ dl->radius = 200 + (rand()&31);
+ dl->minlight = 32;
+ dl->die = cl.time; // + 0.1;
+
+ if (silenced)
+ volume = 0.2;
+ else
+ volume = 1;
+
+ switch (weapon)
+ {
+ case MZ_BLASTER:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_BLUEHYPERBLASTER:
+ dl->color[0] = 0;dl->color[1] = 0;dl->color[2] = 1;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_HYPERBLASTER:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_MACHINEGUN:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
+ break;
+ case MZ_SHOTGUN:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/shotgf1b.wav"), volume, ATTN_NORM, 0);
+ S_StartSound (NULL, i, CHAN_AUTO, S_RegisterSound("weapons/shotgr1b.wav"), volume, ATTN_NORM, 0.1);
+ break;
+ case MZ_SSHOTGUN:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/sshotf1b.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_CHAINGUN1:
+ dl->radius = 200 + (rand()&31);
+ dl->color[0] = 1;dl->color[1] = 0.25;dl->color[2] = 0;
+ Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
+ break;
+ case MZ_CHAINGUN2:
+ dl->radius = 225 + (rand()&31);
+ dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0;
+ dl->die = cl.time + 0.1; // long delay
+ Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
+ Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.05);
+ break;
+ case MZ_CHAINGUN3:
+ dl->radius = 250 + (rand()&31);
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ dl->die = cl.time + 0.1; // long delay
+ Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
+ Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.033);
+ Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.066);
+ break;
+ case MZ_RAILGUN:
+ dl->color[0] = 0.5;dl->color[1] = 0.5;dl->color[2] = 1.0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/railgf1a.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_ROCKET:
+ dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/rocklf1a.wav"), volume, ATTN_NORM, 0);
+ S_StartSound (NULL, i, CHAN_AUTO, S_RegisterSound("weapons/rocklr1b.wav"), volume, ATTN_NORM, 0.1);
+ break;
+ case MZ_GRENADE:
+ dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), volume, ATTN_NORM, 0);
+ S_StartSound (NULL, i, CHAN_AUTO, S_RegisterSound("weapons/grenlr1b.wav"), volume, ATTN_NORM, 0.1);
+ break;
+ case MZ_BFG:
+ dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/bfg__f1y.wav"), volume, ATTN_NORM, 0);
+ break;
+
+ case MZ_LOGIN:
+ dl->color[0] = 0;dl->color[1] = 1; dl->color[2] = 0;
+ dl->die = cl.time + 1.0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
+ CL_LogoutEffect (pl->current.origin, weapon);
+ break;
+ case MZ_LOGOUT:
+ dl->color[0] = 1;dl->color[1] = 0; dl->color[2] = 0;
+ dl->die = cl.time + 1.0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
+ CL_LogoutEffect (pl->current.origin, weapon);
+ break;
+ case MZ_RESPAWN:
+ dl->color[0] = 1;dl->color[1] = 1; dl->color[2] = 0;
+ dl->die = cl.time + 1.0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
+ CL_LogoutEffect (pl->current.origin, weapon);
+ break;
+ // RAFAEL
+ case MZ_PHALANX:
+ dl->color[0] = 1;dl->color[1] = 0.5; dl->color[2] = 0.5;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/plasshot.wav"), volume, ATTN_NORM, 0);
+ break;
+ // RAFAEL
+ case MZ_IONRIPPER:
+ dl->color[0] = 1;dl->color[1] = 0.5; dl->color[2] = 0.5;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/rippfire.wav"), volume, ATTN_NORM, 0);
+ break;
+
+// ======================
+// PGM
+ case MZ_ETF_RIFLE:
+ dl->color[0] = 0.9;dl->color[1] = 0.7;dl->color[2] = 0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/nail1.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_SHOTGUN2:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/shotg2.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_HEATBEAM:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ dl->die = cl.time + 100;
+// S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/bfg__l1a.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_BLASTER2:
+ dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0;
+ // FIXME - different sound for blaster2 ??
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_TRACKER:
+ // negative flashes handled the same in gl/soft until CL_AddDLights
+ dl->color[0] = -1;dl->color[1] = -1;dl->color[2] = -1;
+ S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/disint2.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_NUKE1:
+ dl->color[0] = 1;dl->color[1] = 0;dl->color[2] = 0;
+ dl->die = cl.time + 100;
+ break;
+ case MZ_NUKE2:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ dl->die = cl.time + 100;
+ break;
+ case MZ_NUKE4:
+ dl->color[0] = 0;dl->color[1] = 0;dl->color[2] = 1;
+ dl->die = cl.time + 100;
+ break;
+ case MZ_NUKE8:
+ dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 1;
+ dl->die = cl.time + 100;
+ break;
+// PGM
+// ======================
+ }
+}
+
+
+/*
+==============
+CL_ParseMuzzleFlash2
+==============
+*/
+void CL_ParseMuzzleFlash2 (void)
+{
+ int ent;
+ vec3_t origin;
+ int flash_number;
+ cdlight_t *dl;
+ vec3_t forward, right;
+ char soundname[64];
+
+ ent = MSG_ReadShort (&net_message);
+ if (ent < 1 || ent >= MAX_EDICTS)
+ Com_Error (ERR_DROP, "CL_ParseMuzzleFlash2: bad entity");
+
+ flash_number = MSG_ReadByte (&net_message);
+
+ // locate the origin
+ AngleVectors (cl_entities[ent].current.angles, forward, right, NULL);
+ origin[0] = cl_entities[ent].current.origin[0] + forward[0] * monster_flash_offset[flash_number][0] + right[0] * monster_flash_offset[flash_number][1];
+ origin[1] = cl_entities[ent].current.origin[1] + forward[1] * monster_flash_offset[flash_number][0] + right[1] * monster_flash_offset[flash_number][1];
+ origin[2] = cl_entities[ent].current.origin[2] + forward[2] * monster_flash_offset[flash_number][0] + right[2] * monster_flash_offset[flash_number][1] + monster_flash_offset[flash_number][2];
+
+ dl = CL_AllocDlight (ent);
+ VectorCopy (origin, dl->origin);
+ dl->radius = 200 + (rand()&31);
+ dl->minlight = 32;
+ dl->die = cl.time; // + 0.1;
+
+ switch (flash_number)
+ {
+ case MZ2_INFANTRY_MACHINEGUN_1:
+ case MZ2_INFANTRY_MACHINEGUN_2:
+ case MZ2_INFANTRY_MACHINEGUN_3:
+ case MZ2_INFANTRY_MACHINEGUN_4:
+ case MZ2_INFANTRY_MACHINEGUN_5:
+ case MZ2_INFANTRY_MACHINEGUN_6:
+ case MZ2_INFANTRY_MACHINEGUN_7:
+ case MZ2_INFANTRY_MACHINEGUN_8:
+ case MZ2_INFANTRY_MACHINEGUN_9:
+ case MZ2_INFANTRY_MACHINEGUN_10:
+ case MZ2_INFANTRY_MACHINEGUN_11:
+ case MZ2_INFANTRY_MACHINEGUN_12:
+ case MZ2_INFANTRY_MACHINEGUN_13:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ CL_ParticleEffect (origin, vec3_origin, 0, 40);
+ CL_SmokeAndFlash(origin);
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_SOLDIER_MACHINEGUN_1:
+ case MZ2_SOLDIER_MACHINEGUN_2:
+ case MZ2_SOLDIER_MACHINEGUN_3:
+ case MZ2_SOLDIER_MACHINEGUN_4:
+ case MZ2_SOLDIER_MACHINEGUN_5:
+ case MZ2_SOLDIER_MACHINEGUN_6:
+ case MZ2_SOLDIER_MACHINEGUN_7:
+ case MZ2_SOLDIER_MACHINEGUN_8:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ CL_ParticleEffect (origin, vec3_origin, 0, 40);
+ CL_SmokeAndFlash(origin);
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck3.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_GUNNER_MACHINEGUN_1:
+ case MZ2_GUNNER_MACHINEGUN_2:
+ case MZ2_GUNNER_MACHINEGUN_3:
+ case MZ2_GUNNER_MACHINEGUN_4:
+ case MZ2_GUNNER_MACHINEGUN_5:
+ case MZ2_GUNNER_MACHINEGUN_6:
+ case MZ2_GUNNER_MACHINEGUN_7:
+ case MZ2_GUNNER_MACHINEGUN_8:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ CL_ParticleEffect (origin, vec3_origin, 0, 40);
+ CL_SmokeAndFlash(origin);
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("gunner/gunatck2.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_ACTOR_MACHINEGUN_1:
+ case MZ2_SUPERTANK_MACHINEGUN_1:
+ case MZ2_SUPERTANK_MACHINEGUN_2:
+ case MZ2_SUPERTANK_MACHINEGUN_3:
+ case MZ2_SUPERTANK_MACHINEGUN_4:
+ case MZ2_SUPERTANK_MACHINEGUN_5:
+ case MZ2_SUPERTANK_MACHINEGUN_6:
+ case MZ2_TURRET_MACHINEGUN: // PGM
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+
+ CL_ParticleEffect (origin, vec3_origin, 0, 40);
+ CL_SmokeAndFlash(origin);
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_BOSS2_MACHINEGUN_L1:
+ case MZ2_BOSS2_MACHINEGUN_L2:
+ case MZ2_BOSS2_MACHINEGUN_L3:
+ case MZ2_BOSS2_MACHINEGUN_L4:
+ case MZ2_BOSS2_MACHINEGUN_L5:
+ case MZ2_CARRIER_MACHINEGUN_L1: // PMM
+ case MZ2_CARRIER_MACHINEGUN_L2: // PMM
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+
+ CL_ParticleEffect (origin, vec3_origin, 0, 40);
+ CL_SmokeAndFlash(origin);
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NONE, 0);
+ break;
+
+ case MZ2_SOLDIER_BLASTER_1:
+ case MZ2_SOLDIER_BLASTER_2:
+ case MZ2_SOLDIER_BLASTER_3:
+ case MZ2_SOLDIER_BLASTER_4:
+ case MZ2_SOLDIER_BLASTER_5:
+ case MZ2_SOLDIER_BLASTER_6:
+ case MZ2_SOLDIER_BLASTER_7:
+ case MZ2_SOLDIER_BLASTER_8:
+ case MZ2_TURRET_BLASTER: // PGM
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck2.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_FLYER_BLASTER_1:
+ case MZ2_FLYER_BLASTER_2:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("flyer/flyatck3.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_MEDIC_BLASTER_1:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("medic/medatck1.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_HOVER_BLASTER_1:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("hover/hovatck1.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_FLOAT_BLASTER_1:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("floater/fltatck1.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_SOLDIER_SHOTGUN_1:
+ case MZ2_SOLDIER_SHOTGUN_2:
+ case MZ2_SOLDIER_SHOTGUN_3:
+ case MZ2_SOLDIER_SHOTGUN_4:
+ case MZ2_SOLDIER_SHOTGUN_5:
+ case MZ2_SOLDIER_SHOTGUN_6:
+ case MZ2_SOLDIER_SHOTGUN_7:
+ case MZ2_SOLDIER_SHOTGUN_8:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ CL_SmokeAndFlash(origin);
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck1.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_TANK_BLASTER_1:
+ case MZ2_TANK_BLASTER_2:
+ case MZ2_TANK_BLASTER_3:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_TANK_MACHINEGUN_1:
+ case MZ2_TANK_MACHINEGUN_2:
+ case MZ2_TANK_MACHINEGUN_3:
+ case MZ2_TANK_MACHINEGUN_4:
+ case MZ2_TANK_MACHINEGUN_5:
+ case MZ2_TANK_MACHINEGUN_6:
+ case MZ2_TANK_MACHINEGUN_7:
+ case MZ2_TANK_MACHINEGUN_8:
+ case MZ2_TANK_MACHINEGUN_9:
+ case MZ2_TANK_MACHINEGUN_10:
+ case MZ2_TANK_MACHINEGUN_11:
+ case MZ2_TANK_MACHINEGUN_12:
+ case MZ2_TANK_MACHINEGUN_13:
+ case MZ2_TANK_MACHINEGUN_14:
+ case MZ2_TANK_MACHINEGUN_15:
+ case MZ2_TANK_MACHINEGUN_16:
+ case MZ2_TANK_MACHINEGUN_17:
+ case MZ2_TANK_MACHINEGUN_18:
+ case MZ2_TANK_MACHINEGUN_19:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ CL_ParticleEffect (origin, vec3_origin, 0, 40);
+ CL_SmokeAndFlash(origin);
+ Com_sprintf(soundname, sizeof(soundname), "tank/tnkatk2%c.wav", 'a' + rand() % 5);
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound(soundname), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_CHICK_ROCKET_1:
+ case MZ2_TURRET_ROCKET: // PGM
+ dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("chick/chkatck2.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_TANK_ROCKET_1:
+ case MZ2_TANK_ROCKET_2:
+ case MZ2_TANK_ROCKET_3:
+ dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck1.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_SUPERTANK_ROCKET_1:
+ case MZ2_SUPERTANK_ROCKET_2:
+ case MZ2_SUPERTANK_ROCKET_3:
+ case MZ2_BOSS2_ROCKET_1:
+ case MZ2_BOSS2_ROCKET_2:
+ case MZ2_BOSS2_ROCKET_3:
+ case MZ2_BOSS2_ROCKET_4:
+ case MZ2_CARRIER_ROCKET_1:
+// case MZ2_CARRIER_ROCKET_2:
+// case MZ2_CARRIER_ROCKET_3:
+// case MZ2_CARRIER_ROCKET_4:
+ dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/rocket.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_GUNNER_GRENADE_1:
+ case MZ2_GUNNER_GRENADE_2:
+ case MZ2_GUNNER_GRENADE_3:
+ case MZ2_GUNNER_GRENADE_4:
+ dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("gunner/gunatck3.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_GLADIATOR_RAILGUN_1:
+ // PMM
+ case MZ2_CARRIER_RAILGUN:
+ case MZ2_WIDOW_RAIL:
+ // pmm
+ dl->color[0] = 0.5;dl->color[1] = 0.5;dl->color[2] = 1.0;
+ break;
+
+// --- Xian's shit starts ---
+ case MZ2_MAKRON_BFG:
+ dl->color[0] = 0.5;dl->color[1] = 1 ;dl->color[2] = 0.5;
+ //S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("makron/bfg_fire.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_MAKRON_BLASTER_1:
+ case MZ2_MAKRON_BLASTER_2:
+ case MZ2_MAKRON_BLASTER_3:
+ case MZ2_MAKRON_BLASTER_4:
+ case MZ2_MAKRON_BLASTER_5:
+ case MZ2_MAKRON_BLASTER_6:
+ case MZ2_MAKRON_BLASTER_7:
+ case MZ2_MAKRON_BLASTER_8:
+ case MZ2_MAKRON_BLASTER_9:
+ case MZ2_MAKRON_BLASTER_10:
+ case MZ2_MAKRON_BLASTER_11:
+ case MZ2_MAKRON_BLASTER_12:
+ case MZ2_MAKRON_BLASTER_13:
+ case MZ2_MAKRON_BLASTER_14:
+ case MZ2_MAKRON_BLASTER_15:
+ case MZ2_MAKRON_BLASTER_16:
+ case MZ2_MAKRON_BLASTER_17:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("makron/blaster.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_JORG_MACHINEGUN_L1:
+ case MZ2_JORG_MACHINEGUN_L2:
+ case MZ2_JORG_MACHINEGUN_L3:
+ case MZ2_JORG_MACHINEGUN_L4:
+ case MZ2_JORG_MACHINEGUN_L5:
+ case MZ2_JORG_MACHINEGUN_L6:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ CL_ParticleEffect (origin, vec3_origin, 0, 40);
+ CL_SmokeAndFlash(origin);
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("boss3/xfire.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_JORG_MACHINEGUN_R1:
+ case MZ2_JORG_MACHINEGUN_R2:
+ case MZ2_JORG_MACHINEGUN_R3:
+ case MZ2_JORG_MACHINEGUN_R4:
+ case MZ2_JORG_MACHINEGUN_R5:
+ case MZ2_JORG_MACHINEGUN_R6:
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ CL_ParticleEffect (origin, vec3_origin, 0, 40);
+ CL_SmokeAndFlash(origin);
+ break;
+
+ case MZ2_JORG_BFG_1:
+ dl->color[0] = 0.5;dl->color[1] = 1 ;dl->color[2] = 0.5;
+ break;
+
+ case MZ2_BOSS2_MACHINEGUN_R1:
+ case MZ2_BOSS2_MACHINEGUN_R2:
+ case MZ2_BOSS2_MACHINEGUN_R3:
+ case MZ2_BOSS2_MACHINEGUN_R4:
+ case MZ2_BOSS2_MACHINEGUN_R5:
+ case MZ2_CARRIER_MACHINEGUN_R1: // PMM
+ case MZ2_CARRIER_MACHINEGUN_R2: // PMM
+
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+
+ CL_ParticleEffect (origin, vec3_origin, 0, 40);
+ CL_SmokeAndFlash(origin);
+ break;
+
+// ======
+// ROGUE
+ case MZ2_STALKER_BLASTER:
+ case MZ2_DAEDALUS_BLASTER:
+ case MZ2_MEDIC_BLASTER_2:
+ case MZ2_WIDOW_BLASTER:
+ case MZ2_WIDOW_BLASTER_SWEEP1:
+ case MZ2_WIDOW_BLASTER_SWEEP2:
+ case MZ2_WIDOW_BLASTER_SWEEP3:
+ case MZ2_WIDOW_BLASTER_SWEEP4:
+ case MZ2_WIDOW_BLASTER_SWEEP5:
+ case MZ2_WIDOW_BLASTER_SWEEP6:
+ case MZ2_WIDOW_BLASTER_SWEEP7:
+ case MZ2_WIDOW_BLASTER_SWEEP8:
+ case MZ2_WIDOW_BLASTER_SWEEP9:
+ case MZ2_WIDOW_BLASTER_100:
+ case MZ2_WIDOW_BLASTER_90:
+ case MZ2_WIDOW_BLASTER_80:
+ case MZ2_WIDOW_BLASTER_70:
+ case MZ2_WIDOW_BLASTER_60:
+ case MZ2_WIDOW_BLASTER_50:
+ case MZ2_WIDOW_BLASTER_40:
+ case MZ2_WIDOW_BLASTER_30:
+ case MZ2_WIDOW_BLASTER_20:
+ case MZ2_WIDOW_BLASTER_10:
+ case MZ2_WIDOW_BLASTER_0:
+ case MZ2_WIDOW_BLASTER_10L:
+ case MZ2_WIDOW_BLASTER_20L:
+ case MZ2_WIDOW_BLASTER_30L:
+ case MZ2_WIDOW_BLASTER_40L:
+ case MZ2_WIDOW_BLASTER_50L:
+ case MZ2_WIDOW_BLASTER_60L:
+ case MZ2_WIDOW_BLASTER_70L:
+ case MZ2_WIDOW_RUN_1:
+ case MZ2_WIDOW_RUN_2:
+ case MZ2_WIDOW_RUN_3:
+ case MZ2_WIDOW_RUN_4:
+ case MZ2_WIDOW_RUN_5:
+ case MZ2_WIDOW_RUN_6:
+ case MZ2_WIDOW_RUN_7:
+ case MZ2_WIDOW_RUN_8:
+ dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_WIDOW_DISRUPTOR:
+ dl->color[0] = -1;dl->color[1] = -1;dl->color[2] = -1;
+ S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("weapons/disint2.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_WIDOW_PLASMABEAM:
+ case MZ2_WIDOW2_BEAMER_1:
+ case MZ2_WIDOW2_BEAMER_2:
+ case MZ2_WIDOW2_BEAMER_3:
+ case MZ2_WIDOW2_BEAMER_4:
+ case MZ2_WIDOW2_BEAMER_5:
+ case MZ2_WIDOW2_BEAM_SWEEP_1:
+ case MZ2_WIDOW2_BEAM_SWEEP_2:
+ case MZ2_WIDOW2_BEAM_SWEEP_3:
+ case MZ2_WIDOW2_BEAM_SWEEP_4:
+ case MZ2_WIDOW2_BEAM_SWEEP_5:
+ case MZ2_WIDOW2_BEAM_SWEEP_6:
+ case MZ2_WIDOW2_BEAM_SWEEP_7:
+ case MZ2_WIDOW2_BEAM_SWEEP_8:
+ case MZ2_WIDOW2_BEAM_SWEEP_9:
+ case MZ2_WIDOW2_BEAM_SWEEP_10:
+ case MZ2_WIDOW2_BEAM_SWEEP_11:
+ dl->radius = 300 + (rand()&100);
+ dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
+ dl->die = cl.time + 200;
+ break;
+// ROGUE
+// ======
+
+// --- Xian's shit ends ---
+
+ }
+}
+
+
+/*
+===============
+CL_AddDLights
+
+===============
+*/
+void CL_AddDLights (void)
+{
+ int i;
+ cdlight_t *dl;
+
+ dl = cl_dlights;
+
+//=====
+//PGM
+ if(vidref_val == VIDREF_GL)
+ {
+ for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
+ {
+ if (!dl->radius)
+ continue;
+ V_AddLight (dl->origin, dl->radius,
+ dl->color[0], dl->color[1], dl->color[2]);
+ }
+ }
+ else
+ {
+ for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
+ {
+ if (!dl->radius)
+ continue;
+
+ // negative light in software. only black allowed
+ if ((dl->color[0] < 0) || (dl->color[1] < 0) || (dl->color[2] < 0))
+ {
+ dl->radius = -(dl->radius);
+ dl->color[0] = 1;
+ dl->color[1] = 1;
+ dl->color[2] = 1;
+ }
+ V_AddLight (dl->origin, dl->radius,
+ dl->color[0], dl->color[1], dl->color[2]);
+ }
+ }
+//PGM
+//=====
+}
+
+
+
+/*
+==============================================================
+
+PARTICLE MANAGEMENT
+
+==============================================================
+*/
+
+cparticle_t *active_particles, *free_particles;
+
+cparticle_t particles[MAX_PARTICLES];
+int cl_numparticles = MAX_PARTICLES;
+
+
+/*
+===============
+CL_ClearParticles
+===============
+*/
+void CL_ClearParticles (void)
+{
+ int i;
+
+ free_particles = &particles[0];
+ active_particles = NULL;
+
+ for (i=0 ;i<cl_numparticles ; i++)
+ particles[i].next = &particles[i+1];
+ particles[cl_numparticles-1].next = NULL;
+}
+
+
+/*
+===============
+CL_ParticleEffect
+
+Wall impact puffs
+===============
+*/
+void CL_ParticleEffect (vec3_t org, vec3_t dir, int color, int count)
+{
+ int i, j;
+ cparticle_t *p;
+ float d;
+
+ for (i=0 ; i<count ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = color + (rand()&7);
+
+ d = rand()&31;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+ p->vel[j] = crand()*20;
+ }
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+ }
+}
+
+
+/*
+===============
+CL_ParticleEffect2
+===============
+*/
+void CL_ParticleEffect2 (vec3_t org, vec3_t dir, int color, int count)
+{
+ int i, j;
+ cparticle_t *p;
+ float d;
+
+ for (i=0 ; i<count ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = color;
+
+ d = rand()&7;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+ p->vel[j] = crand()*20;
+ }
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+ }
+}
+
+
+// RAFAEL
+/*
+===============
+CL_ParticleEffect3
+===============
+*/
+void CL_ParticleEffect3 (vec3_t org, vec3_t dir, int color, int count)
+{
+ int i, j;
+ cparticle_t *p;
+ float d;
+
+ for (i=0 ; i<count ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = color;
+
+ d = rand()&7;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+ p->vel[j] = crand()*20;
+ }
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = PARTICLE_GRAVITY;
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+ }
+}
+
+/*
+===============
+CL_TeleporterParticles
+===============
+*/
+void CL_TeleporterParticles (entity_state_t *ent)
+{
+ int i, j;
+ cparticle_t *p;
+
+ for (i=0 ; i<8 ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = 0xdb;
+
+ for (j=0 ; j<2 ; j++)
+ {
+ p->org[j] = ent->origin[j] - 16 + (rand()&31);
+ p->vel[j] = crand()*14;
+ }
+
+ p->org[2] = ent->origin[2] - 8 + (rand()&7);
+ p->vel[2] = 80 + (rand()&7);
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ p->alpha = 1.0;
+
+ p->alphavel = -0.5;
+ }
+}
+
+
+/*
+===============
+CL_LogoutEffect
+
+===============
+*/
+void CL_LogoutEffect (vec3_t org, int type)
+{
+ int i, j;
+ cparticle_t *p;
+
+ for (i=0 ; i<500 ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+
+ if (type == MZ_LOGIN)
+ p->color = 0xd0 + (rand()&7); // green
+ else if (type == MZ_LOGOUT)
+ p->color = 0x40 + (rand()&7); // red
+ else
+ p->color = 0xe0 + (rand()&7); // yellow
+
+ p->org[0] = org[0] - 16 + qfrand()*32;
+ p->org[1] = org[1] - 16 + qfrand()*32;
+ p->org[2] = org[2] - 24 + qfrand()*56;
+
+ for (j=0 ; j<3 ; j++)
+ p->vel[j] = crand()*20;
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (1.0 + qfrand()*0.3);
+ }
+}
+
+
+/*
+===============
+CL_ItemRespawnParticles
+
+===============
+*/
+void CL_ItemRespawnParticles (vec3_t org)
+{
+ int i, j;
+ cparticle_t *p;
+
+ for (i=0 ; i<64 ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+
+ p->color = 0xd4 + (rand()&3); // green
+
+ p->org[0] = org[0] + crand()*8;
+ p->org[1] = org[1] + crand()*8;
+ p->org[2] = org[2] + crand()*8;
+
+ for (j=0 ; j<3 ; j++)
+ p->vel[j] = crand()*8;
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY*0.2;
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (1.0 + qfrand()*0.3);
+ }
+}
+
+
+/*
+===============
+CL_ExplosionParticles
+===============
+*/
+void CL_ExplosionParticles (vec3_t org)
+{
+ int i, j;
+ cparticle_t *p;
+
+ for (i=0 ; i<256 ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = 0xe0 + (rand()&7);
+
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + ((rand()%32)-16);
+ p->vel[j] = (rand()%384)-192;
+ }
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ p->alpha = 1.0;
+
+ p->alphavel = -0.8 / (0.5 + qfrand()*0.3);
+ }
+}
+
+
+/*
+===============
+CL_BigTeleportParticles
+===============
+*/
+void CL_BigTeleportParticles (vec3_t org)
+{
+ int i;
+ cparticle_t *p;
+ float angle, dist;
+ static int colortable[4] = {2*8,13*8,21*8,18*8};
+
+ for (i=0 ; i<4096 ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+
+ p->color = colortable[rand()&3];
+
+ angle = M_PI*2*(rand()&1023)/1023.0;
+ dist = rand()&31;
+ p->org[0] = org[0] + cos(angle)*dist;
+ p->vel[0] = cos(angle)*(70+(rand()&63));
+ p->accel[0] = -cos(angle)*100;
+
+ p->org[1] = org[1] + sin(angle)*dist;
+ p->vel[1] = sin(angle)*(70+(rand()&63));
+ p->accel[1] = -sin(angle)*100;
+
+ p->org[2] = org[2] + 8 + (rand()%90);
+ p->vel[2] = -100 + (rand()&31);
+ p->accel[2] = PARTICLE_GRAVITY*4;
+ p->alpha = 1.0;
+
+ p->alphavel = -0.3 / (0.5 + qfrand()*0.3);
+ }
+}
+
+
+/*
+===============
+CL_BlasterParticles
+
+Wall impact puffs
+===============
+*/
+void CL_BlasterParticles (vec3_t org, vec3_t dir)
+{
+ int i, j;
+ cparticle_t *p;
+ float d;
+ int count;
+
+ count = 40;
+ for (i=0 ; i<count ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = 0xe0 + (rand()&7);
+
+ d = rand()&15;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+ p->vel[j] = dir[j] * 30 + crand()*40;
+ }
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+ }
+}
+
+
+/*
+===============
+CL_BlasterTrail
+
+===============
+*/
+void CL_BlasterTrail (vec3_t start, vec3_t end)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ int dec;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = 5;
+ VectorScale (vec, 5, vec);
+
+ // FIXME: this is a really silly way to have a loop
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (0.3+qfrand()*0.2);
+ p->color = 0xe0;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand();
+ p->vel[j] = crand()*5;
+ p->accel[j] = 0;
+ }
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+/*
+===============
+CL_QuadTrail
+
+===============
+*/
+void CL_QuadTrail (vec3_t start, vec3_t end)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ int dec;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = 5;
+ VectorScale (vec, 5, vec);
+
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (0.8+qfrand()*0.2);
+ p->color = 115;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*16;
+ p->vel[j] = crand()*5;
+ p->accel[j] = 0;
+ }
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+/*
+===============
+CL_FlagTrail
+
+===============
+*/
+void CL_FlagTrail (vec3_t start, vec3_t end, float color)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ int dec;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = 5;
+ VectorScale (vec, 5, vec);
+
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (0.8+qfrand()*0.2);
+ p->color = color;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*16;
+ p->vel[j] = crand()*5;
+ p->accel[j] = 0;
+ }
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+/*
+===============
+CL_DiminishingTrail
+
+===============
+*/
+void CL_DiminishingTrail (vec3_t start, vec3_t end, centity_t *old, int flags)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ float dec;
+ float orgscale;
+ float velscale;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = 0.5;
+ VectorScale (vec, dec, vec);
+
+ if (old->trailcount > 900)
+ {
+ orgscale = 4;
+ velscale = 15;
+ }
+ else if (old->trailcount > 800)
+ {
+ orgscale = 2;
+ velscale = 10;
+ }
+ else
+ {
+ orgscale = 1;
+ velscale = 5;
+ }
+
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+
+ // drop less particles as it flies
+ if ((rand()&1023) < old->trailcount)
+ {
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ if (flags & EF_GIB)
+ {
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (1+qfrand()*0.4);
+ p->color = 0xe8 + (rand()&7);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*orgscale;
+ p->vel[j] = crand()*velscale;
+ p->accel[j] = 0;
+ }
+ p->vel[2] -= PARTICLE_GRAVITY;
+ }
+ else if (flags & EF_GREENGIB)
+ {
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (1+qfrand()*0.4);
+ p->color = 0xdb + (rand()&7);
+ for (j=0; j< 3; j++)
+ {
+ p->org[j] = move[j] + crand()*orgscale;
+ p->vel[j] = crand()*velscale;
+ p->accel[j] = 0;
+ }
+ p->vel[2] -= PARTICLE_GRAVITY;
+ }
+ else
+ {
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (1+qfrand()*0.2);
+ p->color = 4 + (rand()&7);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*orgscale;
+ p->vel[j] = crand()*velscale;
+ }
+ p->accel[2] = 20;
+ }
+ }
+
+ old->trailcount -= 5;
+ if (old->trailcount < 100)
+ old->trailcount = 100;
+ VectorAdd (move, vec, move);
+ }
+}
+
+void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up)
+{
+ float d;
+
+ // this rotate and negat guarantees a vector
+ // not colinear with the original
+ right[1] = -forward[0];
+ right[2] = forward[1];
+ right[0] = forward[2];
+
+ d = DotProduct (right, forward);
+ VectorMA (right, -d, forward, right);
+ VectorNormalize (right);
+ CrossProduct (right, forward, up);
+}
+
+/*
+===============
+CL_RocketTrail
+
+===============
+*/
+void CL_RocketTrail (vec3_t start, vec3_t end, centity_t *old)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ float dec;
+
+ // smoke
+ CL_DiminishingTrail (start, end, old, EF_ROCKET);
+
+ // fire
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = 1;
+ VectorScale (vec, dec, vec);
+
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+
+ if ( (rand()&7) == 0)
+ {
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ VectorClear (p->accel);
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (1+qfrand()*0.2);
+ p->color = 0xdc + (rand()&3);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*5;
+ p->vel[j] = crand()*20;
+ }
+ p->accel[2] = -PARTICLE_GRAVITY;
+ }
+ VectorAdd (move, vec, move);
+ }
+}
+
+/*
+===============
+CL_RailTrail
+
+===============
+*/
+void CL_RailTrail (vec3_t start, vec3_t end)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ float dec;
+ vec3_t right, up;
+ int i;
+ float d, c, s;
+ vec3_t dir;
+ byte clr = 0x74;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ MakeNormalVectors (vec, right, up);
+
+ for (i=0 ; i<len ; i++)
+ {
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ VectorClear (p->accel);
+
+ d = i * 0.1;
+ c = cos(d);
+ s = sin(d);
+
+ VectorScale (right, c, dir);
+ VectorMA (dir, s, up, dir);
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (1+qfrand()*0.2);
+ p->color = clr + (rand()&7);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + dir[j]*3;
+ p->vel[j] = dir[j]*6;
+ }
+
+ VectorAdd (move, vec, move);
+ }
+
+ dec = 0.75;
+ VectorScale (vec, dec, vec);
+ VectorCopy (start, move);
+
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ VectorClear (p->accel);
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (0.6+qfrand()*0.2);
+ p->color = 0x0 + rand()&15;
+
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*3;
+ p->vel[j] = crand()*3;
+ p->accel[j] = 0;
+ }
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+// RAFAEL
+/*
+===============
+CL_IonripperTrail
+===============
+*/
+void CL_IonripperTrail (vec3_t start, vec3_t ent)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ int dec;
+ int left = 0;
+
+ VectorCopy (start, move);
+ VectorSubtract (ent, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = 5;
+ VectorScale (vec, 5, vec);
+
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+ p->alpha = 0.5;
+ p->alphavel = -1.0 / (0.3 + qfrand() * 0.2);
+ p->color = 0xe4 + (rand()&3);
+
+ for (j=0; j<3; j++)
+ {
+ p->org[j] = move[j];
+ p->accel[j] = 0;
+ }
+ if (left)
+ {
+ left = 0;
+ p->vel[0] = 10;
+ }
+ else
+ {
+ left = 1;
+ p->vel[0] = -10;
+ }
+
+ p->vel[1] = 0;
+ p->vel[2] = 0;
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+
+/*
+===============
+CL_BubbleTrail
+
+===============
+*/
+void CL_BubbleTrail (vec3_t start, vec3_t end)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int i, j;
+ cparticle_t *p;
+ float dec;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = 32;
+ VectorScale (vec, dec, vec);
+
+ for (i=0 ; i<len ; i+=dec)
+ {
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ VectorClear (p->accel);
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (1+qfrand()*0.2);
+ p->color = 4 + (rand()&7);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*2;
+ p->vel[j] = crand()*5;
+ }
+ p->vel[2] += 6;
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+
+/*
+===============
+CL_FlyParticles
+===============
+*/
+
+#define BEAMLENGTH 16
+
+void CL_FlyParticles (vec3_t origin, int count)
+{
+ int i;
+ cparticle_t *p;
+ float angle;
+ float sp, sy, cp, cy;
+ vec3_t forward;
+ float dist;
+ float ltime;
+
+
+ if (count > NUMVERTEXNORMALS)
+ count = NUMVERTEXNORMALS;
+
+ if (!avelocities[0][0])
+ {
+ for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
+ avelocities[0][i] = (rand()&255) * 0.01;
+ }
+
+
+ ltime = (float)cl.time / 1000.0;
+ for (i=0 ; i<count ; i+=2)
+ {
+ angle = ltime * avelocities[i][0];
+ sy = sin(angle);
+ cy = cos(angle);
+ angle = ltime * avelocities[i][1];
+ sp = sin(angle);
+ cp = cos(angle);
+ /*
+ angle = ltime * avelocities[i][2];
+ sr = sin(angle);
+ cr = cos(angle);
+ */
+
+ forward[0] = cp*cy;
+ forward[1] = cp*sy;
+ forward[2] = -sp;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+
+ dist = sin(ltime + i)*64;
+ p->org[0] = origin[0] + bytedirs[i][0]*dist + forward[0]*BEAMLENGTH;
+ p->org[1] = origin[1] + bytedirs[i][1]*dist + forward[1]*BEAMLENGTH;
+ p->org[2] = origin[2] + bytedirs[i][2]*dist + forward[2]*BEAMLENGTH;
+
+ VectorClear (p->vel);
+ VectorClear (p->accel);
+
+ p->color = 0;
+ p->colorvel = 0;
+
+ p->alpha = 1;
+ p->alphavel = -100;
+ }
+}
+
+void CL_FlyEffect (centity_t *ent, vec3_t origin)
+{
+ int n;
+ int count;
+ int starttime;
+
+ if (ent->fly_stoptime < cl.time)
+ {
+ starttime = cl.time;
+ ent->fly_stoptime = cl.time + 60000;
+ }
+ else
+ {
+ starttime = ent->fly_stoptime - 60000;
+ }
+
+ n = cl.time - starttime;
+ if (n < 20000)
+ count = n * 162 / 20000.0;
+ else
+ {
+ n = ent->fly_stoptime - cl.time;
+ if (n < 20000)
+ count = n * 162 / 20000.0;
+ else
+ count = 162;
+ }
+
+ CL_FlyParticles (origin, count);
+}
+
+
+/*
+===============
+CL_BfgParticles
+===============
+*/
+
+void CL_BfgParticles (entity_t *ent)
+{
+ int i;
+ cparticle_t *p;
+ float angle;
+ float sp, sy, cp, cy;
+ vec3_t forward;
+ float dist;
+ vec3_t v;
+ float ltime;
+
+ if (!avelocities[0][0])
+ {
+ for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
+ avelocities[0][i] = (rand()&255) * 0.01;
+ }
+
+
+ ltime = (float)cl.time / 1000.0;
+ for (i=0 ; i<NUMVERTEXNORMALS ; i++)
+ {
+ angle = ltime * avelocities[i][0];
+ sy = sin(angle);
+ cy = cos(angle);
+ angle = ltime * avelocities[i][1];
+ sp = sin(angle);
+ cp = cos(angle);
+ /*
+ angle = ltime * avelocities[i][2];
+ sr = sin(angle);
+ cr = cos(angle);
+ */
+
+ forward[0] = cp*cy;
+ forward[1] = cp*sy;
+ forward[2] = -sp;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+
+ dist = sin(ltime + i)*64;
+ p->org[0] = ent->origin[0] + bytedirs[i][0]*dist + forward[0]*BEAMLENGTH;
+ p->org[1] = ent->origin[1] + bytedirs[i][1]*dist + forward[1]*BEAMLENGTH;
+ p->org[2] = ent->origin[2] + bytedirs[i][2]*dist + forward[2]*BEAMLENGTH;
+
+ VectorClear (p->vel);
+ VectorClear (p->accel);
+
+ VectorSubtract (p->org, ent->origin, v);
+ dist = VectorLength(v) / 90.0;
+ p->color = floor (0xd0 + dist * 7);
+ p->colorvel = 0;
+
+ p->alpha = 1.0 - dist;
+ p->alphavel = -100;
+ }
+}
+
+
+/*
+===============
+CL_TrapParticles
+===============
+*/
+// RAFAEL
+void CL_TrapParticles (entity_t *ent)
+{
+ vec3_t move;
+ vec3_t vec;
+ vec3_t start, end;
+ float len;
+ int j;
+ cparticle_t *p;
+ int dec;
+
+ ent->origin[2]-=14;
+ VectorCopy (ent->origin, start);
+ VectorCopy (ent->origin, end);
+ end[2]+=64;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = 5;
+ VectorScale (vec, 5, vec);
+
+ // FIXME: this is a really silly way to have a loop
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (0.3+qfrand()*0.2);
+ p->color = 0xe0;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand();
+ p->vel[j] = crand()*15;
+ p->accel[j] = 0;
+ }
+ p->accel[2] = PARTICLE_GRAVITY;
+
+ VectorAdd (move, vec, move);
+ }
+
+ {
+
+
+ int i, j, k;
+ cparticle_t *p;
+ float vel;
+ vec3_t dir;
+ vec3_t org;
+
+
+ ent->origin[2]+=14;
+ VectorCopy (ent->origin, org);
+
+
+ for (i=-2 ; i<=2 ; i+=4)
+ for (j=-2 ; j<=2 ; j+=4)
+ for (k=-2 ; k<=4 ; k+=4)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = 0xe0 + (rand()&3);
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (0.3 + (rand()&7) * 0.02);
+
+ p->org[0] = org[0] + i + ((rand()&23) * crand());
+ p->org[1] = org[1] + j + ((rand()&23) * crand());
+ p->org[2] = org[2] + k + ((rand()&23) * crand());
+
+ dir[0] = j * 8;
+ dir[1] = i * 8;
+ dir[2] = k * 8;
+
+ VectorNormalize (dir);
+ vel = 50 + rand()&63;
+ VectorScale (dir, vel, p->vel);
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ }
+ }
+}
+
+
+/*
+===============
+CL_BFGExplosionParticles
+===============
+*/
+//FIXME combined with CL_ExplosionParticles
+void CL_BFGExplosionParticles (vec3_t org)
+{
+ int i, j;
+ cparticle_t *p;
+
+ for (i=0 ; i<256 ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = 0xd0 + (rand()&7);
+
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + ((rand()%32)-16);
+ p->vel[j] = (rand()%384)-192;
+ }
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ p->alpha = 1.0;
+
+ p->alphavel = -0.8 / (0.5 + qfrand()*0.3);
+ }
+}
+
+
+/*
+===============
+CL_TeleportParticles
+
+===============
+*/
+void CL_TeleportParticles (vec3_t org)
+{
+ int i, j, k;
+ cparticle_t *p;
+ float vel;
+ vec3_t dir;
+
+ for (i=-16 ; i<=16 ; i+=4)
+ for (j=-16 ; j<=16 ; j+=4)
+ for (k=-16 ; k<=32 ; k+=4)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = 7 + (rand()&7);
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (0.3 + (rand()&7) * 0.02);
+
+ p->org[0] = org[0] + i + (rand()&3);
+ p->org[1] = org[1] + j + (rand()&3);
+ p->org[2] = org[2] + k + (rand()&3);
+
+ dir[0] = j*8;
+ dir[1] = i*8;
+ dir[2] = k*8;
+
+ VectorNormalize (dir);
+ vel = 50 + (rand()&63);
+ VectorScale (dir, vel, p->vel);
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ }
+}
+
+
+/*
+===============
+CL_AddParticles
+===============
+*/
+void CL_AddParticles (void)
+{
+ cparticle_t *p, *next;
+ float alpha;
+ float time = 0, time2;
+ vec3_t org;
+ int color;
+ cparticle_t *active, *tail;
+
+ active = NULL;
+ tail = NULL;
+
+ for (p=active_particles ; p ; p=next)
+ {
+ next = p->next;
+
+ // PMM - added INSTANT_PARTICLE handling for heat beam
+ if (p->alphavel != INSTANT_PARTICLE)
+ {
+ time = (cl.time - p->time)*0.001;
+ alpha = p->alpha + time*p->alphavel;
+ if (alpha <= 0)
+ { // faded out
+ p->next = free_particles;
+ free_particles = p;
+ continue;
+ }
+ }
+ else
+ {
+ alpha = p->alpha;
+ }
+
+ p->next = NULL;
+ if (!tail)
+ active = tail = p;
+ else
+ {
+ tail->next = p;
+ tail = p;
+ }
+
+ if (alpha > 1.0)
+ alpha = 1;
+ color = p->color;
+
+ time2 = time*time;
+
+ org[0] = p->org[0] + p->vel[0]*time + p->accel[0]*time2;
+ org[1] = p->org[1] + p->vel[1]*time + p->accel[1]*time2;
+ org[2] = p->org[2] + p->vel[2]*time + p->accel[2]*time2;
+
+ V_AddParticle (org, color, alpha);
+ // PMM
+ if (p->alphavel == INSTANT_PARTICLE)
+ {
+ p->alphavel = 0.0;
+ p->alpha = 0.0;
+ }
+ }
+
+ active_particles = active;
+}
+
+
+/*
+==============
+CL_EntityEvent
+
+An entity has just been parsed that has an event value
+
+the female events are there for backwards compatability
+==============
+*/
+struct sfx_t *cl_sfx_footsteps[4];
+
+void CL_EntityEvent (entity_state_t *ent)
+{
+ switch (ent->event)
+ {
+ case EV_ITEM_RESPAWN:
+ S_StartSound (NULL, ent->number, CHAN_WEAPON, S_RegisterSound("items/respawn1.wav"), 1, ATTN_IDLE, 0);
+ CL_ItemRespawnParticles (ent->origin);
+ break;
+ case EV_PLAYER_TELEPORT:
+ S_StartSound (NULL, ent->number, CHAN_WEAPON, S_RegisterSound("misc/tele1.wav"), 1, ATTN_IDLE, 0);
+ CL_TeleportParticles (ent->origin);
+ break;
+ case EV_FOOTSTEP:
+ if (cl_footsteps->value)
+ S_StartSound (NULL, ent->number, CHAN_BODY, cl_sfx_footsteps[rand()&3], 1, ATTN_NORM, 0);
+ break;
+ case EV_FALLSHORT:
+ S_StartSound (NULL, ent->number, CHAN_AUTO, S_RegisterSound ("player/land1.wav"), 1, ATTN_NORM, 0);
+ break;
+ case EV_FALL:
+ S_StartSound (NULL, ent->number, CHAN_AUTO, S_RegisterSound ("*fall2.wav"), 1, ATTN_NORM, 0);
+ break;
+ case EV_FALLFAR:
+ S_StartSound (NULL, ent->number, CHAN_AUTO, S_RegisterSound ("*fall1.wav"), 1, ATTN_NORM, 0);
+ break;
+ }
+}
+
+
+/*
+==============
+CL_ClearEffects
+
+==============
+*/
+void CL_ClearEffects (void)
+{
+ CL_ClearParticles ();
+ CL_ClearDlights ();
+ CL_ClearLightStyles ();
+}
--- /dev/null
+++ b/cl_input.c
@@ -1,0 +1,526 @@
+// cl.input.c -- builds an intended movement command to send to the server
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+cvar_t *cl_nodelta;
+
+unsigned frame_msec;
+unsigned old_sys_frame_time;
+
+/*
+===============================================================================
+
+KEY BUTTONS
+
+Continuous button event tracking is complicated by the fact that two different
+input sources (say, mouse button 1 and the control key) can both press the
+same button, but the button should only be released when both of the
+pressing key have been released.
+
+When a key event issues a button command (+forward, +attack, etc), it appends
+its key number as a parameter to the command so it can be matched up with
+the release.
+
+state bit 0 is the current state of the key
+state bit 1 is edge triggered on the up to down transition
+state bit 2 is edge triggered on the down to up transition
+
+
+Key_Event (int key, qboolean down, unsigned time);
+
+ +mlook src time
+
+===============================================================================
+*/
+
+
+kbutton_t in_klook;
+kbutton_t in_left, in_right, in_forward, in_back;
+kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright;
+kbutton_t in_strafe, in_speed, in_use, in_attack;
+kbutton_t in_up, in_down;
+
+int in_impulse;
+
+
+void KeyDown (kbutton_t *b)
+{
+ int k;
+ char *c;
+
+ c = Cmd_Argv(1);
+ if (c[0])
+ k = atoi(c);
+ else
+ k = -1; // typed manually at the console for continuous down
+
+ if (k == b->down[0] || k == b->down[1])
+ return; // repeating key
+
+ if (!b->down[0])
+ b->down[0] = k;
+ else if (!b->down[1])
+ b->down[1] = k;
+ else
+ {
+ Com_Printf ("Three keys down for a button!\n");
+ return;
+ }
+
+ if (b->state & 1)
+ return; // still down
+
+ // save timestamp
+ c = Cmd_Argv(2);
+ b->downtime = atoi(c);
+ if (!b->downtime)
+ b->downtime = sys_frame_time - 100;
+
+ b->state |= 1 + 2; // down + impulse down
+}
+
+void KeyUp (kbutton_t *b)
+{
+ int k;
+ char *c;
+ unsigned uptime;
+
+ c = Cmd_Argv(1);
+ if (c[0])
+ k = atoi(c);
+ else
+ { // typed manually at the console, assume for unsticking, so clear all
+ b->down[0] = b->down[1] = 0;
+ b->state = 4; // impulse up
+ return;
+ }
+
+ if (b->down[0] == k)
+ b->down[0] = 0;
+ else if (b->down[1] == k)
+ b->down[1] = 0;
+ else
+ return; // key up without coresponding down (menu pass through)
+ if (b->down[0] || b->down[1])
+ return; // some other key is still holding it down
+
+ if (!(b->state & 1))
+ return; // still up (this should not happen)
+
+ // save timestamp
+ c = Cmd_Argv(2);
+ uptime = atoi(c);
+ if (uptime)
+ b->msec += uptime - b->downtime;
+ else
+ b->msec += 10;
+
+ b->state &= ~1; // now up
+ b->state |= 4; // impulse up
+}
+
+void IN_KLookDown (void) {KeyDown(&in_klook);}
+void IN_KLookUp (void) {KeyUp(&in_klook);}
+void IN_UpDown(void) {KeyDown(&in_up);}
+void IN_UpUp(void) {KeyUp(&in_up);}
+void IN_DownDown(void) {KeyDown(&in_down);}
+void IN_DownUp(void) {KeyUp(&in_down);}
+void IN_LeftDown(void) {KeyDown(&in_left);}
+void IN_LeftUp(void) {KeyUp(&in_left);}
+void IN_RightDown(void) {KeyDown(&in_right);}
+void IN_RightUp(void) {KeyUp(&in_right);}
+void IN_ForwardDown(void) {KeyDown(&in_forward);}
+void IN_ForwardUp(void) {KeyUp(&in_forward);}
+void IN_BackDown(void) {KeyDown(&in_back);}
+void IN_BackUp(void) {KeyUp(&in_back);}
+void IN_LookupDown(void) {KeyDown(&in_lookup);}
+void IN_LookupUp(void) {KeyUp(&in_lookup);}
+void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
+void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
+void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
+void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
+void IN_MoverightDown(void) {KeyDown(&in_moveright);}
+void IN_MoverightUp(void) {KeyUp(&in_moveright);}
+
+void IN_SpeedDown(void) {KeyDown(&in_speed);}
+void IN_SpeedUp(void) {KeyUp(&in_speed);}
+void IN_StrafeDown(void) {KeyDown(&in_strafe);}
+void IN_StrafeUp(void) {KeyUp(&in_strafe);}
+
+void IN_AttackDown(void) {KeyDown(&in_attack);}
+void IN_AttackUp(void) {KeyUp(&in_attack);}
+
+void IN_UseDown (void) {KeyDown(&in_use);}
+void IN_UseUp (void) {KeyUp(&in_use);}
+
+void IN_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));}
+
+/*
+===============
+CL_KeyState
+
+Returns the fraction of the frame that the key was down
+===============
+*/
+float CL_KeyState (kbutton_t *key)
+{
+ float val;
+ int msec;
+
+ key->state &= 1; // clear impulses
+
+ msec = key->msec;
+ key->msec = 0;
+
+ if (key->state)
+ { // still down
+ msec += sys_frame_time - key->downtime;
+ key->downtime = sys_frame_time;
+ }
+
+/*
+ if (msec)
+ {
+ Com_Printf ("%i ", msec);
+ }
+*/
+
+ val = (float)msec / frame_msec;
+ if (val < 0)
+ val = 0;
+ if (val > 1)
+ val = 1;
+
+ return val;
+}
+
+
+
+
+//==========================================================================
+
+cvar_t *cl_upspeed;
+cvar_t *cl_forwardspeed;
+cvar_t *cl_sidespeed;
+
+cvar_t *cl_yawspeed;
+cvar_t *cl_pitchspeed;
+
+cvar_t *cl_run;
+
+cvar_t *cl_anglespeedkey;
+
+
+/*
+================
+CL_AdjustAngles
+
+Moves the local angle positions
+================
+*/
+void CL_AdjustAngles (void)
+{
+ float speed;
+ float up, down;
+
+ if (in_speed.state & 1)
+ speed = cls.frametime * cl_anglespeedkey->value;
+ else
+ speed = cls.frametime;
+
+ if (!(in_strafe.state & 1))
+ {
+ cl.viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right);
+ cl.viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left);
+ }
+ if (in_klook.state & 1)
+ {
+ cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_forward);
+ cl.viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_back);
+ }
+
+ up = CL_KeyState (&in_lookup);
+ down = CL_KeyState(&in_lookdown);
+
+ cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * up;
+ cl.viewangles[PITCH] += speed*cl_pitchspeed->value * down;
+}
+
+/*
+================
+CL_BaseMove
+
+Send the intended movement message to the server
+================
+*/
+void CL_BaseMove (usercmd_t *cmd)
+{
+ CL_AdjustAngles ();
+
+ memset (cmd, 0, sizeof(*cmd));
+
+ VectorCopy (cl.viewangles, cmd->angles);
+ if (in_strafe.state & 1)
+ {
+ cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_right);
+ cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_left);
+ }
+
+ cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_moveright);
+ cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_moveleft);
+
+ cmd->upmove += cl_upspeed->value * CL_KeyState (&in_up);
+ cmd->upmove -= cl_upspeed->value * CL_KeyState (&in_down);
+
+ if (! (in_klook.state & 1) )
+ {
+ cmd->forwardmove += cl_forwardspeed->value * CL_KeyState (&in_forward);
+ cmd->forwardmove -= cl_forwardspeed->value * CL_KeyState (&in_back);
+ }
+
+//
+// adjust for speed key / running
+//
+ if ( (in_speed.state & 1) ^ (int)(cl_run->value) )
+ {
+ cmd->forwardmove *= 2;
+ cmd->sidemove *= 2;
+ cmd->upmove *= 2;
+ }
+}
+
+void CL_ClampPitch (void)
+{
+ float pitch;
+
+ pitch = SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]);
+ if (pitch > 180)
+ pitch -= 360;
+ if (cl.viewangles[PITCH] + pitch > 89)
+ cl.viewangles[PITCH] = 89 - pitch;
+ if (cl.viewangles[PITCH] + pitch < -89)
+ cl.viewangles[PITCH] = -89 - pitch;
+}
+
+/*
+==============
+CL_FinishMove
+==============
+*/
+void CL_FinishMove (usercmd_t *cmd)
+{
+ int ms;
+ int i;
+
+//
+// figure button bits
+//
+ if ( in_attack.state & 3 )
+ cmd->buttons |= BUTTON_ATTACK;
+ in_attack.state &= ~2;
+
+ if (in_use.state & 3)
+ cmd->buttons |= BUTTON_USE;
+ in_use.state &= ~2;
+
+ if (anykeydown && cls.key_dest == key_game)
+ cmd->buttons |= BUTTON_ANY;
+
+ // send milliseconds of time to apply the move
+ ms = cls.frametime * 1000;
+ if (ms > 250)
+ ms = 100; // time was unreasonable
+ cmd->msec = ms;
+
+ CL_ClampPitch ();
+ for (i=0 ; i<3 ; i++)
+ cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);
+
+ cmd->impulse = in_impulse;
+ in_impulse = 0;
+
+// send the ambient light level at the player's current position
+ cmd->lightlevel = (byte)cl_lightlevel->value;
+}
+
+/*
+=================
+CL_CreateCmd
+=================
+*/
+usercmd_t CL_CreateCmd (void)
+{
+ usercmd_t cmd;
+
+ frame_msec = sys_frame_time - old_sys_frame_time;
+ if (frame_msec < 1)
+ frame_msec = 1;
+ if (frame_msec > 200)
+ frame_msec = 200;
+
+ // get basic movement from keyboard
+ CL_BaseMove (&cmd);
+
+ // allow mice or other external controllers to add to the move
+ IN_Move (&cmd);
+
+ CL_FinishMove (&cmd);
+
+ old_sys_frame_time = sys_frame_time;
+
+//cmd.impulse = cls.framecount;
+
+ return cmd;
+}
+
+
+void IN_CenterView (void)
+{
+ cl.viewangles[PITCH] = -SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]);
+}
+
+/*
+============
+CL_InitInput
+============
+*/
+void CL_InitInput (void)
+{
+ Cmd_AddCommand ("centerview",IN_CenterView);
+
+ Cmd_AddCommand ("+moveup",IN_UpDown);
+ Cmd_AddCommand ("-moveup",IN_UpUp);
+ Cmd_AddCommand ("+movedown",IN_DownDown);
+ Cmd_AddCommand ("-movedown",IN_DownUp);
+ Cmd_AddCommand ("+left",IN_LeftDown);
+ Cmd_AddCommand ("-left",IN_LeftUp);
+ Cmd_AddCommand ("+right",IN_RightDown);
+ Cmd_AddCommand ("-right",IN_RightUp);
+ Cmd_AddCommand ("+forward",IN_ForwardDown);
+ Cmd_AddCommand ("-forward",IN_ForwardUp);
+ Cmd_AddCommand ("+back",IN_BackDown);
+ Cmd_AddCommand ("-back",IN_BackUp);
+ Cmd_AddCommand ("+lookup", IN_LookupDown);
+ Cmd_AddCommand ("-lookup", IN_LookupUp);
+ Cmd_AddCommand ("+lookdown", IN_LookdownDown);
+ Cmd_AddCommand ("-lookdown", IN_LookdownUp);
+ Cmd_AddCommand ("+strafe", IN_StrafeDown);
+ Cmd_AddCommand ("-strafe", IN_StrafeUp);
+ Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
+ Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
+ Cmd_AddCommand ("+moveright", IN_MoverightDown);
+ Cmd_AddCommand ("-moveright", IN_MoverightUp);
+ Cmd_AddCommand ("+speed", IN_SpeedDown);
+ Cmd_AddCommand ("-speed", IN_SpeedUp);
+ Cmd_AddCommand ("+attack", IN_AttackDown);
+ Cmd_AddCommand ("-attack", IN_AttackUp);
+ Cmd_AddCommand ("+use", IN_UseDown);
+ Cmd_AddCommand ("-use", IN_UseUp);
+ Cmd_AddCommand ("impulse", IN_Impulse);
+ Cmd_AddCommand ("+klook", IN_KLookDown);
+ Cmd_AddCommand ("-klook", IN_KLookUp);
+
+ cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0);
+}
+
+
+
+/*
+=================
+CL_SendCmd
+=================
+*/
+void CL_SendCmd (void)
+{
+ sizebuf_t buf;
+ byte data[128];
+ int i;
+ usercmd_t *cmd, *oldcmd;
+ usercmd_t nullcmd;
+ int checksumIndex;
+
+ // build a command even if not connected
+
+ // save this command off for prediction
+ i = cls.netchan.outgoing_sequence & (CMD_BACKUP-1);
+ cmd = &cl.cmds[i];
+ cl.cmd_time[i] = cls.realtime; // for netgraph ping calculation
+
+ *cmd = CL_CreateCmd ();
+
+ cl.cmd = *cmd;
+
+ if (cls.state == ca_disconnected || cls.state == ca_connecting)
+ return;
+
+ if ( cls.state == ca_connected)
+ {
+ if (cls.netchan.message.cursize || curtime - cls.netchan.last_sent > 1000 )
+ Netchan_Transmit (&cls.netchan, 0, buf.data);
+ return;
+ }
+
+ // send a userinfo update if needed
+ if (userinfo_modified)
+ {
+ CL_FixUpGender();
+ userinfo_modified = false;
+ MSG_WriteByte (&cls.netchan.message, clc_userinfo);
+ MSG_WriteString (&cls.netchan.message, Cvar_Userinfo() );
+ }
+
+ SZ_Init (&buf, data, sizeof(data));
+
+ if (cmd->buttons && cl.cinematictime > 0 && !cl.attractloop
+ && cls.realtime - cl.cinematictime > 1000)
+ { // skip the rest of the cinematic
+ SCR_FinishCinematic ();
+ }
+
+ // begin a client move command
+ MSG_WriteByte (&buf, clc_move);
+
+ // save the position for a checksum byte
+ checksumIndex = buf.cursize;
+ MSG_WriteByte (&buf, 0);
+
+ // let the server know what the last frame we
+ // got was, so the next message can be delta compressed
+ if (cl_nodelta->value || !cl.frame.valid || cls.demowaiting)
+ MSG_WriteLong (&buf, -1); // no compression
+ else
+ MSG_WriteLong (&buf, cl.frame.serverframe);
+
+ // send this and the previous cmds in the message, so
+ // if the last packet was dropped, it can be recovered
+ i = (cls.netchan.outgoing_sequence-2) & (CMD_BACKUP-1);
+ cmd = &cl.cmds[i];
+ memset (&nullcmd, 0, sizeof(nullcmd));
+ MSG_WriteDeltaUsercmd (&buf, &nullcmd, cmd);
+ oldcmd = cmd;
+
+ i = (cls.netchan.outgoing_sequence-1) & (CMD_BACKUP-1);
+ cmd = &cl.cmds[i];
+ MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
+ oldcmd = cmd;
+
+ i = (cls.netchan.outgoing_sequence) & (CMD_BACKUP-1);
+ cmd = &cl.cmds[i];
+ MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
+
+ // calculate a checksum over the move commands
+ buf.data[checksumIndex] = COM_BlockSequenceCRCByte(
+ buf.data + checksumIndex + 1, buf.cursize - checksumIndex - 1,
+ cls.netchan.outgoing_sequence);
+
+ //
+ // deliver the message
+ //
+ Netchan_Transmit (&cls.netchan, buf.cursize, buf.data);
+}
+
+
--- /dev/null
+++ b/cl_inv.c
@@ -1,0 +1,127 @@
+// cl_inv.c -- client inventory screen
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/*
+================
+CL_ParseInventory
+================
+*/
+void CL_ParseInventory (void)
+{
+ int i;
+
+ for (i=0 ; i<MAX_ITEMS ; i++)
+ cl.inventory[i] = MSG_ReadShort (&net_message);
+}
+
+
+/*
+================
+Inv_DrawString
+================
+*/
+void Inv_DrawString (int x, int y, char *string)
+{
+ while (*string)
+ {
+ re.DrawChar (x, y, *string);
+ x+=8;
+ string++;
+ }
+}
+
+void SetStringHighBit (char *s)
+{
+ while (*s)
+ *s++ |= 128;
+}
+
+/*
+================
+CL_DrawInventory
+================
+*/
+#define DISPLAY_ITEMS 17
+
+void CL_DrawInventory (void)
+{
+ int i, j;
+ int num, selected_num, item;
+ int index[MAX_ITEMS];
+ char string[1024];
+ int x, y;
+ char binding[1024];
+ char *bind;
+ int selected;
+ int top;
+
+ selected = cl.frame.playerstate.stats[STAT_SELECTED_ITEM];
+
+ num = 0;
+ selected_num = 0;
+ for (i=0 ; i<MAX_ITEMS ; i++)
+ {
+ if (i==selected)
+ selected_num = num;
+ if (cl.inventory[i])
+ {
+ index[num] = i;
+ num++;
+ }
+ }
+
+ // determine scroll point
+ top = selected_num - DISPLAY_ITEMS/2;
+ if (num - top < DISPLAY_ITEMS)
+ top = num - DISPLAY_ITEMS;
+ if (top < 0)
+ top = 0;
+
+ x = (vid.width-256)/2;
+ y = (vid.height-240)/2;
+
+ // repaint everything next frame
+ SCR_DirtyScreen ();
+
+ re.DrawPic (x, y+8, "inventory");
+
+ y += 24;
+ x += 24;
+ Inv_DrawString (x, y, "hotkey ### item");
+ Inv_DrawString (x, y+8, "------ --- ----");
+ y += 16;
+ for (i=top ; i<num && i < top+DISPLAY_ITEMS ; i++)
+ {
+ item = index[i];
+ // search for a binding
+ Com_sprintf (binding, sizeof(binding), "use %s", cl.configstrings[CS_ITEMS+item]);
+ bind = "";
+ for (j=0 ; j<256 ; j++)
+ if (keybindings[j] && !cistrcmp (keybindings[j], binding))
+ {
+ bind = Key_KeynumToString(j);
+ break;
+ }
+
+ Com_sprintf (string, sizeof(string), "%6s %3i %s", bind, cl.inventory[item],
+ cl.configstrings[CS_ITEMS+item] );
+ if (item != selected)
+ SetStringHighBit (string);
+ else // draw a blinky cursor by the selected item
+ {
+ if ( (int)(cls.realtime*10) & 1)
+ re.DrawChar (x-8, y, 15);
+ }
+ Inv_DrawString (x, y, string);
+ y += 8;
+ }
+
+
+}
+
+
--- /dev/null
+++ b/cl_main.c
@@ -1,0 +1,1773 @@
+// cl_main.c -- client main loop
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+cvar_t *adr0;
+cvar_t *adr1;
+cvar_t *adr2;
+cvar_t *adr3;
+cvar_t *adr4;
+cvar_t *adr5;
+cvar_t *adr6;
+cvar_t *adr7;
+cvar_t *adr8;
+
+cvar_t *cl_stereo_separation;
+cvar_t *cl_stereo;
+
+cvar_t *rcon_client_password;
+cvar_t *rcon_address;
+
+cvar_t *cl_noskins;
+cvar_t *cl_autoskins;
+cvar_t *cl_footsteps;
+cvar_t *cl_timeout;
+cvar_t *cl_predict;
+//cvar_t *cl_minfps;
+cvar_t *cl_maxfps;
+cvar_t *cl_gun;
+
+cvar_t *cl_add_particles;
+cvar_t *cl_add_lights;
+cvar_t *cl_add_entities;
+cvar_t *cl_add_blend;
+
+cvar_t *cl_shownet;
+cvar_t *cl_showmiss;
+cvar_t *cl_showclamp;
+
+cvar_t *cl_paused;
+cvar_t *cl_timedemo;
+
+cvar_t *cl_lightlevel;
+
+//
+// userinfo
+//
+cvar_t *info_password;
+cvar_t *info_spectator;
+cvar_t *name;
+cvar_t *skin;
+cvar_t *rate;
+cvar_t *fov;
+cvar_t *msg;
+cvar_t *hand;
+cvar_t *gender;
+cvar_t *gender_auto;
+
+cvar_t *cl_vwep;
+
+client_static_t cls;
+client_state_t cl;
+
+centity_t cl_entities[MAX_EDICTS];
+
+entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES];
+
+extern cvar_t *allow_download;
+extern cvar_t *allow_download_players;
+extern cvar_t *allow_download_models;
+extern cvar_t *allow_download_sounds;
+extern cvar_t *allow_download_maps;
+
+//======================================================================
+
+
+/*
+====================
+CL_WriteDemoMessage
+
+Dumps the current net message, prefixed by the length
+====================
+*/
+void CL_WriteDemoMessage (void)
+{
+ int len, swlen;
+
+ // the first eight bytes are just packet sequencing stuff
+ len = net_message.cursize-8;
+ swlen = LittleLong(len);
+ fwrite (&swlen, 4, 1, cls.demofile);
+ fwrite (net_message.data+8, len, 1, cls.demofile);
+}
+
+
+/*
+====================
+CL_Stop_f
+
+stop recording a demo
+====================
+*/
+void CL_Stop_f (void)
+{
+ int len;
+
+ if (!cls.demorecording)
+ {
+ Com_Printf ("Not recording a demo.\n");
+ return;
+ }
+
+// finish up
+ len = -1;
+ fwrite (&len, 4, 1, cls.demofile);
+ fclose (cls.demofile);
+ cls.demofile = NULL;
+ cls.demorecording = false;
+ Com_Printf ("Stopped demo.\n");
+}
+
+/*
+====================
+CL_Record_f
+
+record <demoname>
+
+Begins recording a demo from the current position
+====================
+*/
+void CL_Record_f (void)
+{
+ char name[MAX_OSPATH];
+ char buf_data[MAX_MSGLEN];
+ sizebuf_t buf;
+ int i;
+ int len;
+ entity_state_t *ent;
+ entity_state_t nullstate;
+
+ if (Cmd_Argc() != 2)
+ {
+ Com_Printf ("record <demoname>\n");
+ return;
+ }
+
+ if (cls.demorecording)
+ {
+ Com_Printf ("Already recording.\n");
+ return;
+ }
+
+ if (cls.state != ca_active)
+ {
+ Com_Printf ("You must be in a level to record.\n");
+ return;
+ }
+
+ //
+ // open the demo file
+ //
+ Com_sprintf (name, sizeof(name), "%s/demos/%s.dm2", FS_Gamedir(), Cmd_Argv(1));
+
+ Com_Printf ("recording to %s.\n", name);
+ FS_CreatePath (name);
+ cls.demofile = fopen (name, "wb");
+ if (!cls.demofile)
+ {
+ Com_Printf ("ERROR: couldn't open.\n");
+ return;
+ }
+ cls.demorecording = true;
+
+ // don't start saving messages until a non-delta compressed message is received
+ cls.demowaiting = true;
+
+ //
+ // write out messages to hold the startup information
+ //
+ SZ_Init (&buf, (uchar *)buf_data, sizeof(buf_data));
+
+ // send the serverdata
+ MSG_WriteByte (&buf, svc_serverdata);
+ MSG_WriteLong (&buf, PROTOCOL_VERSION);
+ MSG_WriteLong (&buf, 0x10000 + cl.servercount);
+ MSG_WriteByte (&buf, 1); // demos are always attract loops
+ MSG_WriteString (&buf, cl.gamedir);
+ MSG_WriteShort (&buf, cl.playernum);
+
+ MSG_WriteString (&buf, cl.configstrings[CS_NAME]);
+
+ // configstrings
+ for (i=0 ; i<MAX_CONFIGSTRINGS ; i++)
+ {
+ if (cl.configstrings[i][0])
+ {
+ if (buf.cursize + strlen (cl.configstrings[i]) + 32 > buf.maxsize)
+ { // write it out
+ len = LittleLong (buf.cursize);
+ fwrite (&len, 4, 1, cls.demofile);
+ fwrite (buf.data, buf.cursize, 1, cls.demofile);
+ buf.cursize = 0;
+ }
+
+ MSG_WriteByte (&buf, svc_configstring);
+ MSG_WriteShort (&buf, i);
+ MSG_WriteString (&buf, cl.configstrings[i]);
+ }
+
+ }
+
+ // baselines
+ memset (&nullstate, 0, sizeof(nullstate));
+ for (i=0; i<MAX_EDICTS ; i++)
+ {
+ ent = &cl_entities[i].baseline;
+ if (!ent->modelindex)
+ continue;
+
+ if (buf.cursize + 64 > buf.maxsize)
+ { // write it out
+ len = LittleLong (buf.cursize);
+ fwrite (&len, 4, 1, cls.demofile);
+ fwrite (buf.data, buf.cursize, 1, cls.demofile);
+ buf.cursize = 0;
+ }
+
+ MSG_WriteByte (&buf, svc_spawnbaseline);
+ MSG_WriteDeltaEntity (&nullstate, &cl_entities[i].baseline, &buf, true, true);
+ }
+
+ MSG_WriteByte (&buf, svc_stufftext);
+ MSG_WriteString (&buf, "precache\n");
+
+ // write it to the demo file
+
+ len = LittleLong (buf.cursize);
+ fwrite (&len, 4, 1, cls.demofile);
+ fwrite (buf.data, buf.cursize, 1, cls.demofile);
+
+ // the rest of the demo file will be individual frames
+}
+
+/* adds the current command line as a clc_stringcmd to the client message.
+ * things like godmode, noclip, etc, are commands directed to the server, so
+ * when they are typed in at the console, they will need to be forwarded. */
+void Cmd_ForwardToServer (void)
+{
+ char *cmd;
+
+ cmd = Cmd_Argv(0);
+ if(cls.state <= ca_connected || *cmd == '-' || *cmd == '+'){
+ Com_Printf("Unknown command \"%s\"\n", cmd);
+ return;
+ }
+
+ MSG_WriteByte(&cls.netchan.message, clc_stringcmd);
+ SZ_Print(&cls.netchan.message, cmd);
+ if(Cmd_Argc() > 1){
+ SZ_Print(&cls.netchan.message, " ");
+ SZ_Print(&cls.netchan.message, Cmd_Args());
+ }
+}
+
+void
+CL_Setenv_f(void)
+{
+ int i, l = 0, argc;
+ char name[1024], val[1024], *env;
+
+ argc = Cmd_Argc();
+
+ if(argc > 2){
+ strncpy(name, Cmd_Argv(1), sizeof name);
+ for(i = 2; i < argc; i++){
+ strncpy(val+l, Cmd_Argv(i), sizeof(name) - l - 2);
+ val[sizeof(val)-2] = 0;
+ strcat(val, " ");
+ l = strlen(val);
+ }
+ putenv(name, val);
+ }else if(argc == 2){
+ env = getenv(Cmd_Argv(1));
+ if(env){
+ Com_Printf("%s=%s\n", Cmd_Argv(1), env);
+ free(env);
+ }else
+ Com_Printf("%s undefined\n", Cmd_Argv(1), env);
+ }
+}
+
+void
+CL_ForwardToServer_f(void)
+{
+ if(cls.state != ca_connected && cls.state != ca_active){
+ Com_Printf("Can't \"%s\", not connected\n", Cmd_Argv(0));
+ return;
+ }
+ /* don't forward the first argument */
+ if(Cmd_Argc() > 1){
+ MSG_WriteByte(&cls.netchan.message, clc_stringcmd);
+ SZ_Print(&cls.netchan.message, Cmd_Args());
+ }
+}
+
+
+/*
+==================
+CL_Pause_f
+==================
+*/
+void CL_Pause_f (void)
+{
+ // never pause in multiplayer
+ if (Cvar_VariableValue ("maxclients") > 1 || !Com_ServerState ())
+ {
+ Cvar_SetValue ("paused", 0);
+ return;
+ }
+
+ Cvar_SetValue ("paused", !cl_paused->value);
+}
+
+/*
+==================
+CL_Quit_f
+==================
+*/
+void CL_Quit_f (void)
+{
+ CL_Disconnect ();
+ Com_Quit ();
+}
+
+/*
+================
+CL_Drop
+
+Called after an ERR_DROP was thrown
+================
+*/
+void CL_Drop (void)
+{
+ if (cls.state == ca_uninitialized)
+ return;
+ if (cls.state == ca_disconnected)
+ return;
+
+ CL_Disconnect ();
+
+ // drop loading plaque unless this is the initial game start
+ if (cls.disable_servercount != -1)
+ SCR_EndLoadingPlaque (); // get rid of loading plaque
+}
+
+
+/*
+=======================
+CL_SendConnectPacket
+
+We have gotten a challenge from the server, so try and
+connect.
+======================
+*/
+void CL_SendConnectPacket (void)
+{
+ netadr_t adr;
+ int port;
+
+ if (!NET_StringToAdr (cls.servername, &adr))
+ {
+ Com_Printf ("Bad server address\n");
+ cls.connect_time = 0;
+ return;
+ }
+ if (adr.port == 0)
+ adr.port = BigShort (PORT_SERVER);
+
+ port = Cvar_VariableValue ("qport");
+ userinfo_modified = false;
+
+ Netchan_OutOfBandPrint (NS_CLIENT, adr, "connect %i %i %i \"%s\"\n",
+ PROTOCOL_VERSION, port, cls.challenge, Cvar_Userinfo() );
+}
+
+/*
+=================
+CL_CheckForResend
+
+Resend a connect message if the last one has timed out
+=================
+*/
+void CL_CheckForResend (void)
+{
+ netadr_t adr;
+
+ // if the local server is running and we aren't
+ // then connect
+ if (cls.state == ca_disconnected && Com_ServerState() )
+ {
+ cls.state = ca_connecting;
+ strncpy (cls.servername, "localhost", sizeof(cls.servername)-1);
+ // we don't need a challenge on the localhost
+ CL_SendConnectPacket ();
+ return;
+// cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
+ }
+
+ // resend if we haven't gotten a reply yet
+ if (cls.state != ca_connecting)
+ return;
+
+ if (cls.realtime - cls.connect_time < 3000)
+ return;
+
+ if (!NET_StringToAdr (cls.servername, &adr))
+ {
+ Com_Printf ("Bad server address\n");
+ cls.state = ca_disconnected;
+ return;
+ }
+ if (adr.port == 0)
+ adr.port = BigShort (PORT_SERVER);
+
+ cls.connect_time = cls.realtime; // for retransmit requests
+
+ Com_Printf ("Connecting to %s...\n", cls.servername);
+
+ Netchan_OutOfBandPrint (NS_CLIENT, adr, "getchallenge\n");
+}
+
+
+/*
+================
+CL_Connect_f
+
+================
+*/
+void CL_Connect_f (void)
+{
+ char *server;
+
+ if (Cmd_Argc() != 2)
+ {
+ Com_Printf ("usage: connect <server>\n");
+ return;
+ }
+
+ if (Com_ServerState ())
+ { // if running a local server, kill it and reissue
+ SV_Shutdown (va("Server quit\n", msg), false);
+ }
+ else
+ {
+ CL_Disconnect ();
+ }
+
+ server = Cmd_Argv (1);
+
+ NET_Config (true); // allow remote
+
+ CL_Disconnect ();
+
+ cls.state = ca_connecting;
+ strncpy (cls.servername, server, sizeof(cls.servername)-1);
+ cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
+}
+
+
+/*
+=====================
+CL_Rcon_f
+
+ Send the rest of the command line over as
+ an unconnected command.
+=====================
+*/
+void CL_Rcon_f (void)
+{
+ char message[1024];
+ int i;
+ netadr_t to;
+
+ if (!rcon_client_password->string)
+ {
+ Com_Printf ("You must set 'rcon_password' before\n"
+ "issuing an rcon command.\n");
+ return;
+ }
+
+ message[0] = (char)255;
+ message[1] = (char)255;
+ message[2] = (char)255;
+ message[3] = (char)255;
+ message[4] = 0;
+
+ NET_Config (true); // allow remote
+
+ strcat (message, "rcon ");
+
+ strcat (message, rcon_client_password->string);
+ strcat (message, " ");
+
+ for (i=1 ; i<Cmd_Argc() ; i++)
+ {
+ strcat (message, Cmd_Argv(i));
+ strcat (message, " ");
+ }
+
+ if (cls.state >= ca_connected)
+ to = cls.netchan.remote_address;
+ else
+ {
+ if (!strlen(rcon_address->string))
+ {
+ Com_Printf ("You must either be connected,\n"
+ "or set the 'rcon_address' cvar\n"
+ "to issue rcon commands\n");
+
+ return;
+ }
+ NET_StringToAdr (rcon_address->string, &to);
+ if (to.port == 0)
+ to.port = BigShort (PORT_SERVER);
+ }
+
+ NET_SendPacket (NS_CLIENT, strlen(message)+1, message, to);
+}
+
+
+/*
+=====================
+CL_ClearState
+
+=====================
+*/
+void CL_ClearState (void)
+{
+ S_StopAllSounds ();
+ CL_ClearEffects ();
+ CL_ClearTEnts ();
+
+// wipe the entire cl structure
+ memset (&cl, 0, sizeof(cl));
+ memset (cl_entities, 0, sizeof(cl_entities));
+
+ SZ_Clear (&cls.netchan.message);
+
+}
+
+/*
+=====================
+CL_Disconnect
+
+Goes from a connected state to full screen console state
+Sends a disconnect message to the server
+This is also called on Com_Error, so it shouldn't cause any errors
+=====================
+*/
+void CL_Disconnect (void)
+{
+ byte final[32];
+
+ if (cls.state == ca_disconnected)
+ return;
+
+ if (cl_timedemo && cl_timedemo->value)
+ {
+ int time;
+
+ time = Sys_Milliseconds () - cl.timedemo_start;
+ if (time > 0)
+ Com_Printf ("%i frames, %3.1f seconds: %3.1f fps\n", cl.timedemo_frames,
+ time/1000.0, cl.timedemo_frames*1000.0 / time);
+ }
+
+ VectorClear (cl.refdef.blend);
+ re.CinematicSetPalette(NULL);
+
+ M_ForceMenuOff ();
+
+ cls.connect_time = 0;
+
+ SCR_StopCinematic ();
+
+ if (cls.demorecording)
+ CL_Stop_f ();
+
+ // send a disconnect message to the server
+ final[0] = clc_stringcmd;
+ strcpy ((char *)final+1, "disconnect");
+ Netchan_Transmit (&cls.netchan, strlen((char *)final), final);
+ Netchan_Transmit (&cls.netchan, strlen((char *)final), final);
+ Netchan_Transmit (&cls.netchan, strlen((char *)final), final);
+
+ CL_ClearState ();
+
+ // stop download
+ if (cls.download) {
+ fclose(cls.download);
+ cls.download = NULL;
+ }
+
+ cls.state = ca_disconnected;
+}
+
+void CL_Disconnect_f (void)
+{
+ Com_Error (ERR_DROP, "Disconnected from server");
+}
+
+
+/*
+====================
+CL_Packet_f
+
+packet <destination> <contents>
+
+Contents allows \n escape character
+====================
+*/
+void CL_Packet_f (void)
+{
+ char send[2048];
+ int i, l;
+ char *in, *out;
+ netadr_t adr;
+
+ if (Cmd_Argc() != 3)
+ {
+ Com_Printf ("packet <destination> <contents>\n");
+ return;
+ }
+
+ NET_Config (true); // allow remote
+
+ if (!NET_StringToAdr (Cmd_Argv(1), &adr))
+ {
+ Com_Printf ("Bad address\n");
+ return;
+ }
+ if (!adr.port)
+ adr.port = BigShort (PORT_SERVER);
+
+ in = Cmd_Argv(2);
+ out = send+4;
+ send[0] = send[1] = send[2] = send[3] = (char)0xff;
+
+ l = strlen (in);
+ for (i=0 ; i<l ; i++)
+ {
+ if (in[i] == '\\' && in[i+1] == 'n')
+ {
+ *out++ = '\n';
+ i++;
+ }
+ else
+ *out++ = in[i];
+ }
+ *out = 0;
+
+ NET_SendPacket (NS_CLIENT, out-send, send, adr);
+}
+
+/*
+=================
+CL_Changing_f
+
+Just sent as a hint to the client that they should
+drop to full console
+=================
+*/
+void CL_Changing_f (void)
+{
+ //ZOID
+ //if we are downloading, we don't change! This so we don't suddenly stop downloading a map
+ if (cls.download)
+ return;
+
+ SCR_BeginLoadingPlaque ();
+ cls.state = ca_connected; // not active anymore, but not disconnected
+ Com_Printf ("\nChanging map...\n");
+}
+
+
+/*
+=================
+CL_Reconnect_f
+
+The server is changing levels
+=================
+*/
+void CL_Reconnect_f (void)
+{
+ //ZOID
+ //if we are downloading, we don't change! This so we don't suddenly stop downloading a map
+ if (cls.download)
+ return;
+
+ S_StopAllSounds ();
+ if (cls.state == ca_connected) {
+ Com_Printf ("reconnecting...\n");
+ cls.state = ca_connected;
+ MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
+ MSG_WriteString (&cls.netchan.message, "new");
+ return;
+ }
+
+ if (*cls.servername) {
+ if (cls.state >= ca_connected) {
+ CL_Disconnect();
+ cls.connect_time = cls.realtime - 1500;
+ } else
+ cls.connect_time = -99999; // fire immediately
+
+ cls.state = ca_connecting;
+ Com_Printf ("reconnecting...\n");
+ }
+}
+
+/*
+=================
+CL_ParseStatusMessage
+
+Handle a reply from a ping
+=================
+*/
+void CL_ParseStatusMessage (void)
+{
+ char *s;
+
+ s = MSG_ReadString(&net_message);
+
+ Com_Printf ("%s\n", s);
+ M_AddToServerList (net_from, s);
+}
+
+
+/*
+=================
+CL_PingServers_f
+=================
+*/
+void CL_PingServers_f (void)
+{
+ int i;
+ netadr_t adr;
+ char name[32];
+ char *adrstring;
+ cvar_t *noudp;
+ cvar_t *noipx;
+
+ NET_Config (true); // allow remote
+
+ // send a broadcast packet
+ Com_Printf ("pinging broadcast...\n");
+
+ noudp = Cvar_Get ("noudp", "0", CVAR_NOSET);
+ if (!noudp->value)
+ {
+ adr.type = NA_BROADCAST;
+ adr.port = BigShort(PORT_SERVER);
+ Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
+ }
+
+ noipx = Cvar_Get ("noipx", "0", CVAR_NOSET);
+ if (!noipx->value)
+ {
+ adr.type = NA_BROADCAST_IPX;
+ adr.port = BigShort(PORT_SERVER);
+ Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
+ }
+
+ // send a packet to each address book entry
+ for (i=0 ; i<16 ; i++)
+ {
+ Com_sprintf (name, sizeof(name), "adr%i", i);
+ adrstring = Cvar_VariableString (name);
+ if (!adrstring || !adrstring[0])
+ continue;
+
+ Com_Printf ("pinging %s...\n", adrstring);
+ if (!NET_StringToAdr (adrstring, &adr))
+ {
+ Com_Printf ("Bad address: %s\n", adrstring);
+ continue;
+ }
+ if (!adr.port)
+ adr.port = BigShort(PORT_SERVER);
+ Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
+ }
+}
+
+
+/*
+=================
+CL_Skins_f
+
+Load or download any custom player skins and models
+=================
+*/
+void CL_Skins_f (void)
+{
+ int i;
+
+ for (i=0 ; i<MAX_CLIENTS ; i++)
+ {
+ if (!cl.configstrings[CS_PLAYERSKINS+i][0])
+ continue;
+ Com_Printf ("client %i: %s\n", i, cl.configstrings[CS_PLAYERSKINS+i]);
+ SCR_UpdateScreen ();
+ Sys_SendKeyEvents (); // pump message loop
+ CL_ParseClientinfo (i);
+ }
+}
+
+
+/*
+=================
+CL_ConnectionlessPacket
+
+Responses to broadcasts, etc
+=================
+*/
+void CL_ConnectionlessPacket (void)
+{
+ char *s;
+ char *c;
+
+ MSG_BeginReading (&net_message);
+ MSG_ReadLong (&net_message); // skip the -1
+
+ s = MSG_ReadStringLine (&net_message);
+
+ Cmd_TokenizeString (s, false);
+
+ c = Cmd_Argv(0);
+
+ Com_Printf ("%s: %s\n", NET_AdrToString (net_from), c);
+
+ // server connection
+ if (!strcmp(c, "client_connect"))
+ {
+ if (cls.state == ca_connected)
+ {
+ Com_Printf ("Dup connect received. Ignored.\n");
+ return;
+ }
+ Netchan_Setup (NS_CLIENT, &cls.netchan, net_from, cls.quakePort);
+ MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
+ MSG_WriteString (&cls.netchan.message, "new");
+ cls.state = ca_connected;
+ return;
+ }
+
+ // server responding to a status broadcast
+ if (!strcmp(c, "info"))
+ {
+ CL_ParseStatusMessage ();
+ return;
+ }
+
+ // remote command from gui front end
+ if (!strcmp(c, "cmd"))
+ {
+ if (!NET_IsLocalAddress(net_from))
+ {
+ Com_Printf ("Command packet from remote host. Ignored.\n");
+ return;
+ }
+ Sys_AppActivate ();
+ s = MSG_ReadString (&net_message);
+ Cbuf_AddText (s);
+ Cbuf_AddText ("\n");
+ return;
+ }
+ // print command from somewhere
+ if (!strcmp(c, "print"))
+ {
+ s = MSG_ReadString (&net_message);
+ Com_Printf ("%s", s);
+ return;
+ }
+
+ // ping from somewhere
+ if (!strcmp(c, "ping"))
+ {
+ Netchan_OutOfBandPrint (NS_CLIENT, net_from, "ack");
+ return;
+ }
+
+ // challenge from the server we are connecting to
+ if (!strcmp(c, "challenge"))
+ {
+ cls.challenge = atoi(Cmd_Argv(1));
+ CL_SendConnectPacket ();
+ return;
+ }
+
+ // echo request from server
+ if (!strcmp(c, "echo"))
+ {
+ Netchan_OutOfBandPrint (NS_CLIENT, net_from, "%s", Cmd_Argv(1) );
+ return;
+ }
+
+ Com_Printf ("Unknown command.\n");
+}
+
+
+/*
+=================
+CL_DumpPackets
+
+A vain attempt to help bad TCP stacks that cause problems
+when they overflow
+=================
+*/
+void CL_DumpPackets (void)
+{
+ while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
+ {
+ Com_Printf ("dumnping a packet\n");
+ }
+}
+
+/*
+=================
+CL_ReadPackets
+=================
+*/
+void CL_ReadPackets (void)
+{
+ while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
+ {
+// Com_Printf ("packet\n");
+ //
+ // remote command packet
+ //
+ if (*(int *)net_message.data == -1)
+ {
+ CL_ConnectionlessPacket ();
+ continue;
+ }
+
+ if (cls.state == ca_disconnected || cls.state == ca_connecting)
+ continue; // dump it if not connected
+
+ if (net_message.cursize < 8)
+ {
+ Com_Printf ("%s: Runt packet\n",NET_AdrToString(net_from));
+ continue;
+ }
+
+ //
+ // packet from server
+ //
+ if (!NET_CompareAdr (net_from, cls.netchan.remote_address))
+ {
+ Com_DPrintf ("%s:sequenced packet without connection\n"
+ ,NET_AdrToString(net_from));
+ continue;
+ }
+ if (!Netchan_Process(&cls.netchan, &net_message))
+ continue; // wasn't accepted for some reason
+ CL_ParseServerMessage ();
+ }
+
+ //
+ // check timeout
+ //
+ if (cls.state >= ca_connected
+ && cls.realtime - cls.netchan.last_received > cl_timeout->value*1000)
+ {
+ if (++cl.timeoutcount > 5) // timeoutcount saves debugger
+ {
+ Com_Printf ("\nServer connection timed out.\n");
+ CL_Disconnect ();
+ return;
+ }
+ }
+ else
+ cl.timeoutcount = 0;
+
+}
+
+
+//=============================================================================
+
+/*
+==============
+CL_FixUpGender_f
+==============
+*/
+void CL_FixUpGender(void)
+{
+ char *p;
+ char sk[80];
+
+ if (gender_auto->value) {
+
+ if (gender->modified) {
+ // was set directly, don't override the user
+ gender->modified = false;
+ return;
+ }
+
+ strncpy(sk, skin->string, sizeof(sk) - 1);
+ if ((p = strchr(sk, '/')) != NULL)
+ *p = 0;
+ if (cistrcmp(sk, "male") == 0 || cistrcmp(sk, "cyborg") == 0)
+ Cvar_Set ("gender", "male");
+ else if (cistrcmp(sk, "female") == 0 || cistrcmp(sk, "crackhor") == 0)
+ Cvar_Set ("gender", "female");
+ else
+ Cvar_Set ("gender", "none");
+ gender->modified = false;
+ }
+}
+
+/*
+==============
+CL_Userinfo_f
+==============
+*/
+void CL_Userinfo_f (void)
+{
+ Com_Printf ("User info settings:\n");
+ Info_Print (Cvar_Userinfo());
+}
+
+/*
+=================
+CL_Snd_Restart_f
+
+Restart the sound subsystem so it can pick up
+new parameters and flush all sounds
+=================
+*/
+void CL_Snd_Restart_f (void)
+{
+ S_Shutdown ();
+ S_Init ();
+ CL_RegisterSounds ();
+}
+
+int precache_check; // for autodownload of precache items
+int precache_spawncount;
+int precache_tex;
+int precache_model_skin;
+
+byte *precache_model; // used for skin checking in alias models
+
+#define PLAYER_MULT 5
+
+// ENV_CNT is map load, ENV_CNT+1 is first env map
+#define ENV_CNT (CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT)
+#define TEXTURE_CNT (ENV_CNT+13)
+
+static char *env_suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
+
+void CL_RequestNextDownload (void)
+{
+ unsigned map_checksum; // for detecting cheater maps
+ char fn[MAX_OSPATH];
+ dmdl_t *pheader;
+
+ if (cls.state != ca_connected)
+ return;
+
+ if (!allow_download->value && precache_check < ENV_CNT)
+ precache_check = ENV_CNT;
+
+//ZOID
+ if (precache_check == CS_MODELS) { // confirm map
+ precache_check = CS_MODELS+2; // 0 isn't used
+ if (allow_download_maps->value)
+ if (!CL_CheckOrDownloadFile(cl.configstrings[CS_MODELS+1]))
+ return; // started a download
+ }
+ if (precache_check >= CS_MODELS && precache_check < CS_MODELS+MAX_MODELS) {
+ if (allow_download_models->value) {
+ while (precache_check < CS_MODELS+MAX_MODELS &&
+ cl.configstrings[precache_check][0]) {
+ if (cl.configstrings[precache_check][0] == '*' ||
+ cl.configstrings[precache_check][0] == '#') {
+ precache_check++;
+ continue;
+ }
+ if (precache_model_skin == 0) {
+ if (!CL_CheckOrDownloadFile(cl.configstrings[precache_check])) {
+ precache_model_skin = 1;
+ return; // started a download
+ }
+ precache_model_skin = 1;
+ }
+
+ // checking for skins in the model
+ if (!precache_model) {
+
+ FS_LoadFile (cl.configstrings[precache_check], (void **)&precache_model);
+ if (!precache_model) {
+ precache_model_skin = 0;
+ precache_check++;
+ continue; // couldn't load it
+ }
+ if (LittleLong(*(unsigned *)precache_model) != IDALIASHEADER) {
+ // not an alias model
+ FS_FreeFile(precache_model);
+ precache_model = 0;
+ precache_model_skin = 0;
+ precache_check++;
+ continue;
+ }
+ pheader = (dmdl_t *)precache_model;
+ if (LittleLong (pheader->version) != ALIAS_VERSION) {
+ precache_check++;
+ precache_model_skin = 0;
+ continue; // couldn't load it
+ }
+ }
+
+ pheader = (dmdl_t *)precache_model;
+
+ while (precache_model_skin - 1 < LittleLong(pheader->num_skins)) {
+ if (!CL_CheckOrDownloadFile((char *)precache_model +
+ LittleLong(pheader->ofs_skins) +
+ (precache_model_skin - 1)*MAX_SKINNAME)) {
+ precache_model_skin++;
+ return; // started a download
+ }
+ precache_model_skin++;
+ }
+ if (precache_model) {
+ FS_FreeFile(precache_model);
+ precache_model = 0;
+ }
+ precache_model_skin = 0;
+ precache_check++;
+ }
+ }
+ precache_check = CS_SOUNDS;
+ }
+ if (precache_check >= CS_SOUNDS && precache_check < CS_SOUNDS+MAX_SOUNDS) {
+ if (allow_download_sounds->value) {
+ if (precache_check == CS_SOUNDS)
+ precache_check++; // zero is blank
+ while (precache_check < CS_SOUNDS+MAX_SOUNDS &&
+ cl.configstrings[precache_check][0]) {
+ if (cl.configstrings[precache_check][0] == '*') {
+ precache_check++;
+ continue;
+ }
+ Com_sprintf(fn, sizeof(fn), "sound/%s", cl.configstrings[precache_check++]);
+ if (!CL_CheckOrDownloadFile(fn))
+ return; // started a download
+ }
+ }
+ precache_check = CS_IMAGES;
+ }
+ if (precache_check >= CS_IMAGES && precache_check < CS_IMAGES+MAX_IMAGES) {
+ if (precache_check == CS_IMAGES)
+ precache_check++; // zero is blank
+ while (precache_check < CS_IMAGES+MAX_IMAGES &&
+ cl.configstrings[precache_check][0]) {
+ Com_sprintf(fn, sizeof(fn), "pics/%s.pcx", cl.configstrings[precache_check++]);
+ if (!CL_CheckOrDownloadFile(fn))
+ return; // started a download
+ }
+ precache_check = CS_PLAYERSKINS;
+ }
+ // skins are special, since a player has three things to download:
+ // model, weapon model and skin
+ // so precache_check is now *3
+ if (precache_check >= CS_PLAYERSKINS && precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
+ if (allow_download_players->value) {
+ while (precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
+ int i, n;
+ char model[MAX_QPATH], skin[MAX_QPATH], *p;
+
+ i = (precache_check - CS_PLAYERSKINS)/PLAYER_MULT;
+ n = (precache_check - CS_PLAYERSKINS)%PLAYER_MULT;
+
+ if (!cl.configstrings[CS_PLAYERSKINS+i][0]) {
+ precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
+ continue;
+ }
+
+ if ((p = strchr(cl.configstrings[CS_PLAYERSKINS+i], '\\')) != NULL)
+ p++;
+ else
+ p = cl.configstrings[CS_PLAYERSKINS+i];
+ strcpy(model, p);
+ p = strchr(model, '/');
+ if (!p)
+ p = strchr(model, '\\');
+ if (p) {
+ *p++ = 0;
+ strcpy(skin, p);
+ } else
+ *skin = 0;
+
+ switch (n) {
+ case 0: // model
+ Com_sprintf(fn, sizeof(fn), "players/%s/tris.md2", model);
+ if (!CL_CheckOrDownloadFile(fn)) {
+ precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 1;
+ return; // started a download
+ }
+ /*FALL THROUGH*/
+
+ case 1: // weapon model
+ Com_sprintf(fn, sizeof(fn), "players/%s/weapon.md2", model);
+ if (!CL_CheckOrDownloadFile(fn)) {
+ precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 2;
+ return; // started a download
+ }
+ /*FALL THROUGH*/
+
+ case 2: // weapon skin
+ Com_sprintf(fn, sizeof(fn), "players/%s/weapon.pcx", model);
+ if (!CL_CheckOrDownloadFile(fn)) {
+ precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 3;
+ return; // started a download
+ }
+ /*FALL THROUGH*/
+
+ case 3: // skin
+ Com_sprintf(fn, sizeof(fn), "players/%s/%s.pcx", model, skin);
+ if (!CL_CheckOrDownloadFile(fn)) {
+ precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 4;
+ return; // started a download
+ }
+ /*FALL THROUGH*/
+
+ case 4: // skin_i
+ Com_sprintf(fn, sizeof(fn), "players/%s/%s_i.pcx", model, skin);
+ if (!CL_CheckOrDownloadFile(fn)) {
+ precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 5;
+ return; // started a download
+ }
+ // move on to next model
+ precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
+ }
+ }
+ }
+ // precache phase completed
+ precache_check = ENV_CNT;
+ }
+
+ if (precache_check == ENV_CNT) {
+ precache_check = ENV_CNT + 1;
+
+ CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
+
+ if (map_checksum != atoi(cl.configstrings[CS_MAPCHECKSUM])) {
+ Com_Error (ERR_DROP, "Local map version differs from server: %i != '%s'\n",
+ map_checksum, cl.configstrings[CS_MAPCHECKSUM]);
+ return;
+ }
+ }
+
+ if (precache_check > ENV_CNT && precache_check < TEXTURE_CNT) {
+ if (allow_download->value && allow_download_maps->value) {
+ while (precache_check < TEXTURE_CNT) {
+ int n = precache_check++ - ENV_CNT - 1;
+
+ if (n & 1)
+ Com_sprintf(fn, sizeof(fn), "env/%s%s.pcx",
+ cl.configstrings[CS_SKY], env_suf[n/2]);
+ else
+ Com_sprintf(fn, sizeof(fn), "env/%s%s.tga",
+ cl.configstrings[CS_SKY], env_suf[n/2]);
+ if (!CL_CheckOrDownloadFile(fn))
+ return; // started a download
+ }
+ }
+ precache_check = TEXTURE_CNT;
+ }
+
+ if (precache_check == TEXTURE_CNT) {
+ precache_check = TEXTURE_CNT+1;
+ precache_tex = 0;
+ }
+
+ // confirm existance of textures, download any that don't exist
+ if (precache_check == TEXTURE_CNT+1) {
+ // from qcommon/cmodel.c
+ extern int numtexinfo;
+ extern mapsurface_t map_surfaces[];
+
+ if (allow_download->value && allow_download_maps->value) {
+ while (precache_tex < numtexinfo) {
+ char fn[MAX_OSPATH];
+
+ sprintf(fn, "textures/%s.wal", map_surfaces[precache_tex++].rname);
+ if (!CL_CheckOrDownloadFile(fn))
+ return; // started a download
+ }
+ }
+ precache_check = TEXTURE_CNT+999;
+ }
+
+//ZOID
+ CL_RegisterSounds ();
+ CL_PrepRefresh ();
+
+ MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+ MSG_WriteString (&cls.netchan.message, va("begin %i\n", precache_spawncount) );
+}
+
+/*
+=================
+CL_Precache_f
+
+The server will send this command right
+before allowing the client into the server
+=================
+*/
+void CL_Precache_f (void)
+{
+ //Yet another hack to let old demos work
+ //the old precache sequence
+ if (Cmd_Argc() < 2) {
+ unsigned map_checksum; // for detecting cheater maps
+
+ CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
+ CL_RegisterSounds ();
+ CL_PrepRefresh ();
+ return;
+ }
+
+ precache_check = CS_MODELS;
+ precache_spawncount = atoi(Cmd_Argv(1));
+ precache_model = 0;
+ precache_model_skin = 0;
+
+ CL_RequestNextDownload();
+}
+
+
+/*
+=================
+CL_InitLocal
+=================
+*/
+void CL_InitLocal (void)
+{
+ cls.state = ca_disconnected;
+ cls.realtime = Sys_Milliseconds ();
+
+ CL_InitInput ();
+
+ adr0 = Cvar_Get( "adr0", "", CVAR_ARCHIVE );
+ adr1 = Cvar_Get( "adr1", "", CVAR_ARCHIVE );
+ adr2 = Cvar_Get( "adr2", "", CVAR_ARCHIVE );
+ adr3 = Cvar_Get( "adr3", "", CVAR_ARCHIVE );
+ adr4 = Cvar_Get( "adr4", "", CVAR_ARCHIVE );
+ adr5 = Cvar_Get( "adr5", "", CVAR_ARCHIVE );
+ adr6 = Cvar_Get( "adr6", "", CVAR_ARCHIVE );
+ adr7 = Cvar_Get( "adr7", "", CVAR_ARCHIVE );
+ adr8 = Cvar_Get( "adr8", "", CVAR_ARCHIVE );
+
+//
+// register our variables
+//
+ cl_stereo_separation = Cvar_Get( "cl_stereo_separation", "0.4", CVAR_ARCHIVE );
+ cl_stereo = Cvar_Get( "cl_stereo", "0", 0 );
+
+ cl_add_blend = Cvar_Get ("cl_blend", "1", 0);
+ cl_add_lights = Cvar_Get ("cl_lights", "1", 0);
+ cl_add_particles = Cvar_Get ("cl_particles", "1", 0);
+ cl_add_entities = Cvar_Get ("cl_entities", "1", 0);
+ cl_gun = Cvar_Get ("cl_gun", "1", 0);
+ cl_footsteps = Cvar_Get ("cl_footsteps", "1", 0);
+ cl_noskins = Cvar_Get ("cl_noskins", "0", 0);
+ cl_autoskins = Cvar_Get ("cl_autoskins", "0", 0);
+ cl_predict = Cvar_Get ("cl_predict", "1", 0);
+// cl_minfps = Cvar_Get ("cl_minfps", "5", 0);
+ cl_maxfps = Cvar_Get ("cl_maxfps", "90", 0);
+
+ cl_upspeed = Cvar_Get ("cl_upspeed", "200", 0);
+ cl_forwardspeed = Cvar_Get ("cl_forwardspeed", "200", 0);
+ cl_sidespeed = Cvar_Get ("cl_sidespeed", "200", 0);
+ cl_yawspeed = Cvar_Get ("cl_yawspeed", "140", 0);
+ cl_pitchspeed = Cvar_Get ("cl_pitchspeed", "150", 0);
+ cl_anglespeedkey = Cvar_Get ("cl_anglespeedkey", "1.5", 0);
+
+ cl_run = Cvar_Get ("cl_run", "0", CVAR_ARCHIVE);
+
+ cl_shownet = Cvar_Get ("cl_shownet", "0", 0);
+ cl_showmiss = Cvar_Get ("cl_showmiss", "0", 0);
+ cl_showclamp = Cvar_Get ("showclamp", "0", 0);
+ cl_timeout = Cvar_Get ("cl_timeout", "120", 0);
+ cl_paused = Cvar_Get ("paused", "0", 0);
+ cl_timedemo = Cvar_Get ("timedemo", "0", 0);
+
+ rcon_client_password = Cvar_Get ("rcon_password", "", 0);
+ rcon_address = Cvar_Get ("rcon_address", "", 0);
+
+ cl_lightlevel = Cvar_Get ("r_lightlevel", "0", 0);
+
+ //
+ // userinfo
+ //
+ info_password = Cvar_Get ("password", "", CVAR_USERINFO);
+ info_spectator = Cvar_Get ("spectator", "0", CVAR_USERINFO);
+ name = Cvar_Get ("name", "unnamed", CVAR_USERINFO | CVAR_ARCHIVE);
+ skin = Cvar_Get ("skin", "male/grunt", CVAR_USERINFO | CVAR_ARCHIVE);
+ rate = Cvar_Get ("rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE); // FIXME
+ msg = Cvar_Get ("msg", "1", CVAR_USERINFO | CVAR_ARCHIVE);
+ hand = Cvar_Get ("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE);
+ fov = Cvar_Get ("fov", "90", CVAR_USERINFO | CVAR_ARCHIVE);
+ gender = Cvar_Get ("gender", "male", CVAR_USERINFO | CVAR_ARCHIVE);
+ gender_auto = Cvar_Get ("gender_auto", "1", CVAR_ARCHIVE);
+ gender->modified = false; // clear this so we know when user sets it manually
+
+ cl_vwep = Cvar_Get ("cl_vwep", "1", CVAR_ARCHIVE);
+
+
+ //
+ // register our commands
+ //
+ Cmd_AddCommand ("cmd", CL_ForwardToServer_f);
+ Cmd_AddCommand ("pause", CL_Pause_f);
+ Cmd_AddCommand ("pingservers", CL_PingServers_f);
+ Cmd_AddCommand ("skins", CL_Skins_f);
+
+ Cmd_AddCommand ("userinfo", CL_Userinfo_f);
+ Cmd_AddCommand ("snd_restart", CL_Snd_Restart_f);
+
+ Cmd_AddCommand ("changing", CL_Changing_f);
+ Cmd_AddCommand ("disconnect", CL_Disconnect_f);
+ Cmd_AddCommand ("record", CL_Record_f);
+ Cmd_AddCommand ("stop", CL_Stop_f);
+
+ Cmd_AddCommand ("quit", CL_Quit_f);
+
+ Cmd_AddCommand ("connect", CL_Connect_f);
+ Cmd_AddCommand ("reconnect", CL_Reconnect_f);
+
+ Cmd_AddCommand ("rcon", CL_Rcon_f);
+
+// Cmd_AddCommand ("packet", CL_Packet_f); // this is dangerous to leave in
+
+ Cmd_AddCommand ("setenv", CL_Setenv_f );
+
+ Cmd_AddCommand ("precache", CL_Precache_f);
+
+ Cmd_AddCommand ("download", CL_Download_f);
+
+ //
+ // forward to server commands
+ //
+ // the only thing this does is allow command completion
+ // to work -- all unknown commands are automatically
+ // forwarded to the server
+ Cmd_AddCommand ("wave", NULL);
+ Cmd_AddCommand ("inven", NULL);
+ Cmd_AddCommand ("kill", NULL);
+ Cmd_AddCommand ("use", NULL);
+ Cmd_AddCommand ("drop", NULL);
+ Cmd_AddCommand ("say", NULL);
+ Cmd_AddCommand ("say_team", NULL);
+ Cmd_AddCommand ("info", NULL);
+ Cmd_AddCommand ("prog", NULL);
+ Cmd_AddCommand ("give", NULL);
+ Cmd_AddCommand ("god", NULL);
+ Cmd_AddCommand ("notarget", NULL);
+ Cmd_AddCommand ("noclip", NULL);
+ Cmd_AddCommand ("invuse", NULL);
+ Cmd_AddCommand ("invprev", NULL);
+ Cmd_AddCommand ("invnext", NULL);
+ Cmd_AddCommand ("invdrop", NULL);
+ Cmd_AddCommand ("weapnext", NULL);
+ Cmd_AddCommand ("weapprev", NULL);
+}
+
+
+
+/*
+===============
+CL_WriteConfiguration
+
+Writes key bindings and archived cvars to config.cfg
+===============
+*/
+void CL_WriteConfiguration (void)
+{
+ FILE *f;
+ char path[MAX_QPATH];
+
+ if (cls.state == ca_uninitialized)
+ return;
+
+ Com_sprintf (path, sizeof(path),"%s/config.cfg",FS_Gamedir());
+ f = fopen (path, "w");
+ if (!f)
+ {
+ Com_Printf ("Couldn't write config.cfg.\n");
+ return;
+ }
+
+ fprintf (f, "// generated by quake, do not modify\n");
+ Key_WriteBindings (f);
+ fclose (f);
+
+ Cvar_WriteVariables (path);
+}
+
+
+/*
+==================
+CL_FixCvarCheats
+
+==================
+*/
+
+typedef struct
+{
+ char *name;
+ char *value;
+ cvar_t *var;
+} cheatvar_t;
+
+cheatvar_t cheatvars[] = {
+ {"timescale", "1"},
+ {"timedemo", "0"},
+ {"r_drawworld", "1"},
+ {"cl_testlights", "0"},
+ {"r_fullbright", "0"},
+ {"r_drawflat", "0"},
+ {"paused", "0"},
+ {"fixedtime", "0"},
+ {"sw_draworder", "0"},
+ {"gl_lightmap", "0"},
+ {"gl_saturatelighting", "0"},
+ {NULL, NULL}
+};
+
+int numcheatvars;
+
+void CL_FixCvarCheats (void)
+{
+ int i;
+ cheatvar_t *var;
+
+ if ( !strcmp(cl.configstrings[CS_MAXCLIENTS], "1")
+ || !cl.configstrings[CS_MAXCLIENTS][0] )
+ return; // single player can cheat
+
+ // find all the cvars if we haven't done it yet
+ if (!numcheatvars)
+ {
+ while (cheatvars[numcheatvars].name)
+ {
+ cheatvars[numcheatvars].var = Cvar_Get (cheatvars[numcheatvars].name,
+ cheatvars[numcheatvars].value, 0);
+ numcheatvars++;
+ }
+ }
+
+ // make sure they are all set to the proper values
+ for (i=0, var = cheatvars ; i<numcheatvars ; i++, var++)
+ {
+ if ( strcmp (var->var->string, var->value) )
+ {
+ Cvar_Set (var->name, var->value);
+ }
+ }
+}
+
+//============================================================================
+
+/*
+==================
+CL_SendCommand
+
+==================
+*/
+void CL_SendCommand (void)
+{
+ // get new key events
+ Sys_SendKeyEvents ();
+
+ // allow mice or other external controllers to add commands
+ IN_Commands ();
+
+ // process console commands
+ Cbuf_Execute ();
+
+ // fix any cheating cvars
+ CL_FixCvarCheats ();
+
+ // send intentions now
+ CL_SendCmd ();
+
+ // resend a connection request if necessary
+ CL_CheckForResend ();
+}
+
+
+/*
+==================
+CL_Frame
+
+==================
+*/
+void CL_Frame (int msec)
+{
+ static int extratime;
+ static int lasttimecalled;
+
+ if (dedicated->value)
+ return;
+
+ extratime += msec;
+
+ if (!cl_timedemo->value)
+ {
+ if (cls.state == ca_connected && extratime < 100)
+ return; // don't flood packets out while connecting
+ if (extratime < 1000/cl_maxfps->value)
+ return; // framerate is too high
+ }
+
+ // let the mouse activate or deactivate
+ IN_Frame ();
+
+ // decide the simulation time
+ cls.frametime = extratime/1000.0;
+ cl.time += extratime;
+ cls.realtime = curtime;
+
+ extratime = 0;
+/*
+ if (cls.frametime > (1.0 / cl_minfps->value))
+ cls.frametime = (1.0 / cl_minfps->value);
+*/
+ if (cls.frametime > (1.0 / 5))
+ cls.frametime = (1.0 / 5);
+
+ // if in the debugger last frame, don't timeout
+ if (msec > 5000)
+ cls.netchan.last_received = Sys_Milliseconds ();
+
+ // fetch results from server
+ CL_ReadPackets ();
+
+ // send a new command message to the server
+ CL_SendCommand ();
+
+ // predict all unacknowledged movements
+ CL_PredictMovement ();
+
+ // allow rendering DLL change
+ VID_CheckChanges ();
+ if (!cl.refresh_prepped && cls.state == ca_active)
+ CL_PrepRefresh ();
+
+ // update the screen
+ if (host_speeds->value)
+ time_before_ref = Sys_Milliseconds ();
+ SCR_UpdateScreen ();
+ if (host_speeds->value)
+ time_after_ref = Sys_Milliseconds ();
+
+ // update audio
+ S_Update (cl.refdef.vieworg, cl.v_forward, cl.v_right, cl.v_up);
+
+ CDAudio_Update();
+
+ // advance local effects for next frame
+ CL_RunDLights ();
+ CL_RunLightStyles ();
+ SCR_RunCinematic ();
+ SCR_RunConsole ();
+
+ cls.framecount++;
+
+ if ( log_stats->value )
+ {
+ if ( cls.state == ca_active )
+ {
+ if ( !lasttimecalled )
+ {
+ lasttimecalled = Sys_Milliseconds();
+ if ( log_stats_file )
+ fprintf( log_stats_file, "0\n" );
+ }
+ else
+ {
+ int now = Sys_Milliseconds();
+
+ if ( log_stats_file )
+ fprintf( log_stats_file, "%d\n", now - lasttimecalled );
+ lasttimecalled = now;
+ }
+ }
+ }
+}
+
+
+//============================================================================
+
+/*
+====================
+CL_Init
+====================
+*/
+void CL_Init (void)
+{
+ IN_Init();
+
+ if(dedicated->value)
+ return; // nothing running on the client
+
+ // all archived variables will now be loaded
+
+ Con_Init ();
+ S_Init ();
+ VID_Init ();
+
+ V_Init ();
+
+ net_message.data = net_message_buffer;
+ net_message.maxsize = sizeof(net_message_buffer);
+
+ M_Init ();
+
+ SCR_Init ();
+ cls.disable_screen = true; // don't draw yet
+
+ CDAudio_Init ();
+ CL_InitLocal ();
+
+// Cbuf_AddText ("exec autoexec.cfg\n");
+ FS_ExecAutoexec ();
+ Cbuf_Execute ();
+}
+
+
+/*
+===============
+CL_Shutdown
+
+FIXME: this is a callback from Sys_Quit and Com_Error. It would be better
+to run quit through here before the final handoff to the sys code.
+===============
+*/
+void CL_Shutdown(void)
+{
+ static qboolean isdown = false;
+
+ if (isdown)
+ {
+ printf ("recursive shutdown\n");
+ return;
+ }
+ isdown = true;
+
+ CL_WriteConfiguration ();
+
+ CDAudio_Shutdown ();
+ S_Shutdown();
+ IN_Shutdown ();
+ VID_Shutdown();
+}
+
+
--- /dev/null
+++ b/cl_newfx.c
@@ -1,0 +1,1307 @@
+// cl_newfx.c -- MORE entity effects parsing and management
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+extern cparticle_t *active_particles, *free_particles;
+extern cparticle_t particles[MAX_PARTICLES];
+extern int cl_numparticles;
+
+extern void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up);
+
+
+/*
+======
+vectoangles2 - this is duplicated in the game DLL, but I need it here.
+======
+*/
+void vectoangles2 (vec3_t value1, vec3_t angles)
+{
+ float forward;
+ float yaw, pitch;
+
+ if (value1[1] == 0 && value1[0] == 0)
+ {
+ yaw = 0;
+ if (value1[2] > 0)
+ pitch = 90;
+ else
+ pitch = 270;
+ }
+ else
+ {
+ // PMM - fixed to correct for pitch of 0
+ if (value1[0])
+ yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
+ else if (value1[1] > 0)
+ yaw = 90;
+ else
+ yaw = 270;
+
+ if (yaw < 0)
+ yaw += 360;
+
+ forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
+ pitch = (atan2(value1[2], forward) * 180 / M_PI);
+ if (pitch < 0)
+ pitch += 360;
+ }
+
+ angles[PITCH] = -pitch;
+ angles[YAW] = yaw;
+ angles[ROLL] = 0;
+}
+
+//=============
+//=============
+void CL_Flashlight (int ent, vec3_t pos)
+{
+ cdlight_t *dl;
+
+ dl = CL_AllocDlight (ent);
+ VectorCopy (pos, dl->origin);
+ dl->radius = 400;
+ dl->minlight = 250;
+ dl->die = cl.time + 100;
+ dl->color[0] = 1;
+ dl->color[1] = 1;
+ dl->color[2] = 1;
+}
+
+/*
+======
+CL_ColorFlash - flash of light
+======
+*/
+void CL_ColorFlash (vec3_t pos, int ent, int intensity, float r, float g, float b)
+{
+ cdlight_t *dl;
+
+ if((vidref_val == VIDREF_SOFT) && ((r < 0) || (g<0) || (b<0)))
+ {
+ intensity = -intensity;
+ r = -r;
+ g = -g;
+ b = -b;
+ }
+
+ dl = CL_AllocDlight (ent);
+ VectorCopy (pos, dl->origin);
+ dl->radius = intensity;
+ dl->minlight = 250;
+ dl->die = cl.time + 100;
+ dl->color[0] = r;
+ dl->color[1] = g;
+ dl->color[2] = b;
+}
+
+
+/*
+======
+CL_DebugTrail
+======
+*/
+void CL_DebugTrail (vec3_t start, vec3_t end)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+// int j;
+ cparticle_t *p;
+ float dec;
+ vec3_t right, up;
+// int i;
+// float d, c, s;
+// vec3_t dir;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ MakeNormalVectors (vec, right, up);
+
+// VectorScale(vec, RT2_SKIP, vec);
+
+// dec = 1.0;
+// dec = 0.75;
+ dec = 3;
+ VectorScale (vec, dec, vec);
+ VectorCopy (start, move);
+
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ VectorClear (p->accel);
+ VectorClear (p->vel);
+ p->alpha = 1.0;
+ p->alphavel = -0.1;
+// p->alphavel = 0;
+ p->color = 0x74 + (rand()&7);
+ VectorCopy (move, p->org);
+/*
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*2;
+ p->vel[j] = crand()*3;
+ p->accel[j] = 0;
+ }
+*/
+ VectorAdd (move, vec, move);
+ }
+
+}
+
+/*
+===============
+CL_SmokeTrail
+===============
+*/
+void CL_SmokeTrail (vec3_t start, vec3_t end, int colorStart, int colorRun, int spacing)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ VectorScale (vec, spacing, vec);
+
+ // FIXME: this is a really silly way to have a loop
+ while (len > 0)
+ {
+ len -= spacing;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (1+qfrand()*0.5);
+ p->color = colorStart + (rand() % colorRun);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*3;
+ p->accel[j] = 0;
+ }
+ p->vel[2] = 20 + crand()*5;
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+void CL_ForceWall (vec3_t start, vec3_t end, int color)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ VectorScale (vec, 4, vec);
+
+ // FIXME: this is a really silly way to have a loop
+ while (len > 0)
+ {
+ len -= 4;
+
+ if (!free_particles)
+ return;
+
+ if (qfrand() > 0.3)
+ {
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (3.0+qfrand()*0.5);
+ p->color = color;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*3;
+ p->accel[j] = 0;
+ }
+ p->vel[0] = 0;
+ p->vel[1] = 0;
+ p->vel[2] = -40 - (crand()*10);
+ }
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+void CL_FlameEffects (centity_t */*ent*/, vec3_t origin)
+{
+ int n, count;
+ int j;
+ cparticle_t *p;
+
+ count = rand() & 0xF;
+
+ for(n=0;n<count;n++)
+ {
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ VectorClear (p->accel);
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (1+qfrand()*0.2);
+ p->color = 226 + (rand() % 4);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = origin[j] + crand()*5;
+ p->vel[j] = crand()*5;
+ }
+ p->vel[2] = crand() * -10;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ }
+
+ count = rand() & 0x7;
+
+ for(n=0;n<count;n++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (1+qfrand()*0.5);
+ p->color = 0 + (rand() % 4);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = origin[j] + crand()*3;
+ }
+ p->vel[2] = 20 + crand()*5;
+ }
+
+}
+
+
+/*
+===============
+CL_GenericParticleEffect
+===============
+*/
+void CL_GenericParticleEffect (vec3_t org, vec3_t dir, int color, int count, int numcolors, int dirspread, float alphavel)
+{
+ int i, j;
+ cparticle_t *p;
+ float d;
+
+ for (i=0 ; i<count ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ if (numcolors > 1)
+ p->color = color + (rand() & numcolors);
+ else
+ p->color = color;
+
+ d = rand() & dirspread;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+ p->vel[j] = crand()*20;
+ }
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+// VectorCopy (accel, p->accel);
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (0.5 + qfrand()*alphavel);
+// p->alphavel = alphavel;
+ }
+}
+
+/*
+===============
+CL_BubbleTrail2 (lets you control the # of bubbles by setting the distance between the spawns)
+
+===============
+*/
+void CL_BubbleTrail2 (vec3_t start, vec3_t end, int dist)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int i, j;
+ cparticle_t *p;
+ float dec;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = dist;
+ VectorScale (vec, dec, vec);
+
+ for (i=0 ; i<len ; i+=dec)
+ {
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ VectorClear (p->accel);
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (1+qfrand()*0.1);
+ p->color = 4 + (rand()&7);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*2;
+ p->vel[j] = crand()*10;
+ }
+ p->org[2] -= 4;
+// p->vel[2] += 6;
+ p->vel[2] += 20;
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+//#define CORKSCREW 1
+//#define DOUBLE_SCREW 1
+#define RINGS 1
+//#define SPRAY 1
+
+#ifdef CORKSCREW
+void CL_Heatbeam (vec3_t start, vec3_t end)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j,k;
+ cparticle_t *p;
+ vec3_t right, up;
+ int i;
+ float d, c, s;
+ vec3_t dir;
+ float ltime;
+ float step = 5.0;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+// MakeNormalVectors (vec, right, up);
+ VectorCopy (cl.v_right, right);
+ VectorCopy (cl.v_up, up);
+ VectorMA (move, -1, right, move);
+ VectorMA (move, -1, up, move);
+
+ VectorScale (vec, step, vec);
+ ltime = (float) cl.time/1000.0;
+
+// for (i=0 ; i<len ; i++)
+ for (i=0 ; i<len ; i+=step)
+ {
+ d = i * 0.1 - fmod(ltime,16.0)*M_PI;
+ c = cos(d)/1.75;
+ s = sin(d)/1.75;
+#ifdef DOUBLE_SCREW
+ for (k=-1; k<2; k+=2)
+ {
+#else
+ k=1;
+#endif
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ VectorClear (p->accel);
+
+ p->alpha = 0.5;
+ // p->alphavel = -1.0 / (1+qfrand()*0.2);
+ // only last one frame!
+ p->alphavel = INSTANT_PARTICLE;
+ // p->color = 0x74 + (rand()&7);
+// p->color = 223 - (rand()&7);
+ p->color = 223;
+// p->color = 240;
+
+ // trim it so it looks like it's starting at the origin
+ if (i < 10)
+ {
+ VectorScale (right, c*(i/10.0)*k, dir);
+ VectorMA (dir, s*(i/10.0)*k, up, dir);
+ }
+ else
+ {
+ VectorScale (right, c*k, dir);
+ VectorMA (dir, s*k, up, dir);
+ }
+
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + dir[j]*3;
+ // p->vel[j] = dir[j]*6;
+ p->vel[j] = 0;
+ }
+#ifdef DOUBLE_SCREW
+ }
+#endif
+ VectorAdd (move, vec, move);
+ }
+}
+#endif
+#ifdef RINGS
+//void CL_Heatbeam (vec3_t start, vec3_t end)
+void CL_Heatbeam (vec3_t start, vec3_t forward)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ vec3_t right, up;
+ int i;
+ float c, s;
+ vec3_t dir;
+ float ltime;
+ float step = 32.0, rstep;
+ float start_pt;
+ float rot;
+ float variance;
+ vec3_t end;
+
+ VectorMA (start, 4096, forward, end);
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ // FIXME - pmm - these might end up using old values?
+// MakeNormalVectors (vec, right, up);
+ VectorCopy (cl.v_right, right);
+ VectorCopy (cl.v_up, up);
+ if (vidref_val == VIDREF_GL)
+ { // GL mode
+ VectorMA (move, -0.5, right, move);
+ VectorMA (move, -0.5, up, move);
+ }
+ // otherwise assume SOFT
+
+ ltime = (float) cl.time/1000.0;
+ start_pt = fmod(ltime*96.0,step);
+ VectorMA (move, start_pt, vec, move);
+
+ VectorScale (vec, step, vec);
+
+// Com_Printf ("%f\n", ltime);
+ rstep = M_PI/10.0;
+ for (i=start_pt ; i<len ; i+=step)
+ {
+ if (i>step*5) // don't bother after the 5th ring
+ break;
+
+ for (rot = 0; rot < M_PI*2; rot += rstep)
+ {
+
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ VectorClear (p->accel);
+// rot+= fmod(ltime, 12.0)*M_PI;
+// c = cos(rot)/2.0;
+// s = sin(rot)/2.0;
+// variance = 0.4 + ((float)rand()/(float)RAND_MAX) *0.2;
+ variance = 0.5;
+ c = cos(rot)*variance;
+ s = sin(rot)*variance;
+
+ // trim it so it looks like it's starting at the origin
+ if (i < 10)
+ {
+ VectorScale (right, c*(i/10.0), dir);
+ VectorMA (dir, s*(i/10.0), up, dir);
+ }
+ else
+ {
+ VectorScale (right, c, dir);
+ VectorMA (dir, s, up, dir);
+ }
+
+ p->alpha = 0.5;
+ // p->alphavel = -1.0 / (1+qfrand()*0.2);
+ p->alphavel = -1000.0;
+ // p->color = 0x74 + (rand()&7);
+ p->color = 223 - (rand()&7);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + dir[j]*3;
+ // p->vel[j] = dir[j]*6;
+ p->vel[j] = 0;
+ }
+ }
+ VectorAdd (move, vec, move);
+ }
+}
+#endif
+#ifdef SPRAY
+void CL_Heatbeam (vec3_t start, vec3_t end)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ vec3_t forward, right, up;
+ int i;
+ float d, c, s;
+ vec3_t dir;
+ float ltime;
+ float step = 32.0, rstep;
+ float start_pt;
+ float rot;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+// MakeNormalVectors (vec, right, up);
+ VectorCopy (cl.v_forward, forward);
+ VectorCopy (cl.v_right, right);
+ VectorCopy (cl.v_up, up);
+ VectorMA (move, -0.5, right, move);
+ VectorMA (move, -0.5, up, move);
+
+ for (i=0; i<8; i++)
+ {
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ VectorClear (p->accel);
+
+ d = crand()*M_PI;
+ c = cos(d)*30;
+ s = sin(d)*30;
+
+ p->alpha = 1.0;
+ p->alphavel = -5.0 / (1+qfrand());
+ p->color = 223 - (rand()&7);
+
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j];
+ }
+ VectorScale (vec, 450, p->vel);
+ VectorMA (p->vel, c, right, p->vel);
+ VectorMA (p->vel, s, up, p->vel);
+ }
+/*
+
+ ltime = (float) cl.time/1000.0;
+ start_pt = fmod(ltime*16.0,step);
+ VectorMA (move, start_pt, vec, move);
+
+ VectorScale (vec, step, vec);
+
+// Com_Printf ("%f\n", ltime);
+ rstep = M_PI/12.0;
+ for (i=start_pt ; i<len ; i+=step)
+ {
+ if (i>step*5) // don't bother after the 5th ring
+ break;
+
+ for (rot = 0; rot < M_PI*2; rot += rstep)
+ {
+ if (!free_particles)
+ return;
+
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ VectorClear (p->accel);
+// rot+= fmod(ltime, 12.0)*M_PI;
+// c = cos(rot)/2.0;
+// s = sin(rot)/2.0;
+ c = cos(rot)/1.5;
+ s = sin(rot)/1.5;
+
+ // trim it so it looks like it's starting at the origin
+ if (i < 10)
+ {
+ VectorScale (right, c*(i/10.0), dir);
+ VectorMA (dir, s*(i/10.0), up, dir);
+ }
+ else
+ {
+ VectorScale (right, c, dir);
+ VectorMA (dir, s, up, dir);
+ }
+
+ p->alpha = 0.5;
+ // p->alphavel = -1.0 / (1+qfrand()*0.2);
+ p->alphavel = -1000.0;
+ // p->color = 0x74 + (rand()&7);
+ p->color = 223 - (rand()&7);
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + dir[j]*3;
+ // p->vel[j] = dir[j]*6;
+ p->vel[j] = 0;
+ }
+ }
+ VectorAdd (move, vec, move);
+ }
+*/
+}
+#endif
+
+/*
+===============
+CL_ParticleSteamEffect
+
+Puffs with velocity along direction, with some randomness thrown in
+===============
+*/
+void CL_ParticleSteamEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude)
+{
+ int i, j;
+ cparticle_t *p;
+ float d;
+ vec3_t r, u;
+
+// vectoangles2 (dir, angle_dir);
+// AngleVectors (angle_dir, f, r, u);
+
+ MakeNormalVectors (dir, r, u);
+
+ for (i=0 ; i<count ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = color + (rand()&7);
+
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + magnitude*0.1*crand();
+// p->vel[j] = dir[j]*magnitude;
+ }
+ VectorScale (dir, magnitude, p->vel);
+ d = crand()*magnitude/3;
+ VectorMA (p->vel, d, r, p->vel);
+ d = crand()*magnitude/3;
+ VectorMA (p->vel, d, u, p->vel);
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY/2;
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+ }
+}
+
+void CL_ParticleSteamEffect2 (cl_sustain_t *self)
+//vec3_t org, vec3_t dir, int color, int count, int magnitude)
+{
+ int i, j;
+ cparticle_t *p;
+ float d;
+ vec3_t r, u;
+ vec3_t dir;
+
+// vectoangles2 (dir, angle_dir);
+// AngleVectors (angle_dir, f, r, u);
+
+ VectorCopy (self->dir, dir);
+ MakeNormalVectors (dir, r, u);
+
+ for (i=0 ; i<self->count ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = self->color + (rand()&7);
+
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = self->org[j] + self->magnitude*0.1*crand();
+// p->vel[j] = dir[j]*magnitude;
+ }
+ VectorScale (dir, self->magnitude, p->vel);
+ d = crand()*self->magnitude/3;
+ VectorMA (p->vel, d, r, p->vel);
+ d = crand()*self->magnitude/3;
+ VectorMA (p->vel, d, u, p->vel);
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY/2;
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+ }
+ self->nextthink += self->thinkinterval;
+}
+
+/*
+===============
+CL_TrackerTrail
+===============
+*/
+void CL_TrackerTrail (vec3_t start, vec3_t end, int particleColor)
+{
+ vec3_t move;
+ vec3_t vec;
+ vec3_t forward,right,up,angle_dir;
+ float len;
+ int j;
+ cparticle_t *p;
+ int dec;
+ float dist;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ VectorCopy(vec, forward);
+ vectoangles2 (forward, angle_dir);
+ AngleVectors (angle_dir, forward, right, up);
+
+ dec = 3;
+ VectorScale (vec, 3, vec);
+
+ // FIXME: this is a really silly way to have a loop
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -2.0;
+ p->color = particleColor;
+ dist = DotProduct(move, forward);
+ VectorMA(move, 8 * cos(dist), up, p->org);
+ for (j=0 ; j<3 ; j++)
+ {
+// p->org[j] = move[j] + crand();
+ p->vel[j] = 0;
+ p->accel[j] = 0;
+ }
+ p->vel[2] = 5;
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+void CL_Tracker_Shell(vec3_t origin)
+{
+ vec3_t dir;
+ int i;
+ cparticle_t *p;
+
+ for(i=0;i<300;i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = INSTANT_PARTICLE;
+ p->color = 0;
+
+ dir[0] = crand();
+ dir[1] = crand();
+ dir[2] = crand();
+ VectorNormalize(dir);
+
+ VectorMA(origin, 40, dir, p->org);
+ }
+}
+
+void CL_MonsterPlasma_Shell(vec3_t origin)
+{
+ vec3_t dir;
+ int i;
+ cparticle_t *p;
+
+ for(i=0;i<40;i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = INSTANT_PARTICLE;
+ p->color = 0xe0;
+
+ dir[0] = crand();
+ dir[1] = crand();
+ dir[2] = crand();
+ VectorNormalize(dir);
+
+ VectorMA(origin, 10, dir, p->org);
+// VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
+ }
+}
+
+void CL_Widowbeamout (cl_sustain_t *self)
+{
+ vec3_t dir;
+ int i;
+ cparticle_t *p;
+ static int colortable[4] = {2*8,13*8,21*8,18*8};
+ float ratio;
+
+ ratio = 1.0 - (((float)self->endtime - (float)cl.time)/2100.0);
+
+ for(i=0;i<300;i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = INSTANT_PARTICLE;
+ p->color = colortable[rand()&3];
+
+ dir[0] = crand();
+ dir[1] = crand();
+ dir[2] = crand();
+ VectorNormalize(dir);
+
+ VectorMA(self->org, (45.0 * ratio), dir, p->org);
+// VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
+ }
+}
+
+void CL_Nukeblast (cl_sustain_t *self)
+{
+ vec3_t dir;
+ int i;
+ cparticle_t *p;
+ static int colortable[4] = {110, 112, 114, 116};
+ float ratio;
+
+ ratio = 1.0 - (((float)self->endtime - (float)cl.time)/1000.0);
+
+ for(i=0;i<700;i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = INSTANT_PARTICLE;
+ p->color = colortable[rand()&3];
+
+ dir[0] = crand();
+ dir[1] = crand();
+ dir[2] = crand();
+ VectorNormalize(dir);
+
+ VectorMA(self->org, (200.0 * ratio), dir, p->org);
+// VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
+ }
+}
+
+void CL_WidowSplash (vec3_t org)
+{
+ static int colortable[4] = {2*8,13*8,21*8,18*8};
+ int i;
+ cparticle_t *p;
+ vec3_t dir;
+
+ for (i=0 ; i<256 ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = colortable[rand()&3];
+
+ dir[0] = crand();
+ dir[1] = crand();
+ dir[2] = crand();
+ VectorNormalize(dir);
+ VectorMA(org, 45.0, dir, p->org);
+ VectorMA(vec3_origin, 40.0, dir, p->vel);
+
+ p->accel[0] = p->accel[1] = 0;
+ p->alpha = 1.0;
+
+ p->alphavel = -0.8 / (0.5 + qfrand()*0.3);
+ }
+
+}
+
+void CL_Tracker_Explode(vec3_t origin)
+{
+ vec3_t dir, backdir;
+ int i;
+ cparticle_t *p;
+
+ for(i=0;i<300;i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0;
+ p->color = 0;
+
+ dir[0] = crand();
+ dir[1] = crand();
+ dir[2] = crand();
+ VectorNormalize(dir);
+ VectorScale(dir, -1, backdir);
+
+ VectorMA(origin, 64, dir, p->org);
+ VectorScale(backdir, 64, p->vel);
+ }
+
+}
+
+/*
+===============
+CL_TagTrail
+
+===============
+*/
+void CL_TagTrail (vec3_t start, vec3_t end, float color)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ int dec;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = 5;
+ VectorScale (vec, 5, vec);
+
+ while (len >= 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (0.8+qfrand()*0.2);
+ p->color = color;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand()*16;
+ p->vel[j] = crand()*5;
+ p->accel[j] = 0;
+ }
+
+ VectorAdd (move, vec, move);
+ }
+}
+
+/*
+===============
+CL_ColorExplosionParticles
+===============
+*/
+void CL_ColorExplosionParticles (vec3_t org, int color, int run)
+{
+ int i, j;
+ cparticle_t *p;
+
+ for (i=0 ; i<128 ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = color + (rand() % run);
+
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + ((rand()%32)-16);
+ p->vel[j] = (rand()%256)-128;
+ }
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ p->alpha = 1.0;
+
+ p->alphavel = -0.4 / (0.6 + qfrand()*0.2);
+ }
+}
+
+/*
+===============
+CL_ParticleSmokeEffect - like the steam effect, but unaffected by gravity
+===============
+*/
+void CL_ParticleSmokeEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude)
+{
+ int i, j;
+ cparticle_t *p;
+ float d;
+ vec3_t r, u;
+
+ MakeNormalVectors (dir, r, u);
+
+ for (i=0 ; i<count ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = color + (rand()&7);
+
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + magnitude*0.1*crand();
+// p->vel[j] = dir[j]*magnitude;
+ }
+ VectorScale (dir, magnitude, p->vel);
+ d = crand()*magnitude/3;
+ VectorMA (p->vel, d, r, p->vel);
+ d = crand()*magnitude/3;
+ VectorMA (p->vel, d, u, p->vel);
+
+ p->accel[0] = p->accel[1] = p->accel[2] = 0;
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+ }
+}
+
+/*
+===============
+CL_BlasterParticles2
+
+Wall impact puffs (Green)
+===============
+*/
+void CL_BlasterParticles2 (vec3_t org, vec3_t dir, unsigned int color)
+{
+ int i, j;
+ cparticle_t *p;
+ float d;
+ int count;
+
+ count = 40;
+ for (i=0 ; i<count ; i++)
+ {
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+
+ p->time = cl.time;
+ p->color = color + (rand()&7);
+
+ d = rand()&15;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
+ p->vel[j] = dir[j] * 30 + crand()*40;
+ }
+
+ p->accel[0] = p->accel[1] = 0;
+ p->accel[2] = -PARTICLE_GRAVITY;
+ p->alpha = 1.0;
+
+ p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
+ }
+}
+
+/*
+===============
+CL_BlasterTrail2
+
+Green!
+===============
+*/
+void CL_BlasterTrail2 (vec3_t start, vec3_t end)
+{
+ vec3_t move;
+ vec3_t vec;
+ float len;
+ int j;
+ cparticle_t *p;
+ int dec;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = 5;
+ VectorScale (vec, 5, vec);
+
+ // FIXME: this is a really silly way to have a loop
+ while (len > 0)
+ {
+ len -= dec;
+
+ if (!free_particles)
+ return;
+ p = free_particles;
+ free_particles = p->next;
+ p->next = active_particles;
+ active_particles = p;
+ VectorClear (p->accel);
+
+ p->time = cl.time;
+
+ p->alpha = 1.0;
+ p->alphavel = -1.0 / (0.3+qfrand()*0.2);
+ p->color = 0xd0;
+ for (j=0 ; j<3 ; j++)
+ {
+ p->org[j] = move[j] + crand();
+ p->vel[j] = crand()*5;
+ p->accel[j] = 0;
+ }
+
+ VectorAdd (move, vec, move);
+ }
+}
--- /dev/null
+++ b/cl_parse.c
@@ -1,0 +1,803 @@
+// cl_parse.c -- parse a message received from the server
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+char *svc_strings[256] =
+{
+ "svc_bad",
+
+ "svc_muzzleflash",
+ "svc_muzzlflash2",
+ "svc_temp_entity",
+ "svc_layout",
+ "svc_inventory",
+
+ "svc_nop",
+ "svc_disconnect",
+ "svc_reconnect",
+ "svc_sound",
+ "svc_print",
+ "svc_stufftext",
+ "svc_serverdata",
+ "svc_configstring",
+ "svc_spawnbaseline",
+ "svc_centerprint",
+ "svc_download",
+ "svc_playerinfo",
+ "svc_packetentities",
+ "svc_deltapacketentities",
+ "svc_frame"
+};
+
+//=============================================================================
+
+void CL_DownloadFileName(char *dest, int destlen, char *fn)
+{
+ if (strncmp(fn, "players", 7) == 0)
+ Com_sprintf (dest, destlen, "%s/%s", BASEDIRNAME, fn);
+ else
+ Com_sprintf (dest, destlen, "%s/%s", FS_Gamedir(), fn);
+}
+
+/*
+===============
+CL_CheckOrDownloadFile
+
+Returns true if the file exists, otherwise it attempts
+to start a download from the server.
+===============
+*/
+qboolean CL_CheckOrDownloadFile (char *filename)
+{
+ FILE *fp;
+ char name[MAX_OSPATH];
+
+ if (strstr (filename, ".."))
+ {
+ Com_Printf ("Refusing to download a path with ..\n");
+ return true;
+ }
+
+ if (FS_LoadFile (filename, NULL) != -1)
+ { // it exists, no need to download
+ return true;
+ }
+
+ strcpy (cls.downloadname, filename);
+
+ // download to a temp name, and only rename
+ // to the real name when done, so if interrupted
+ // a runt file wont be left
+ COM_StripExtension (cls.downloadname, cls.downloadtempname);
+ strcat (cls.downloadtempname, ".tmp");
+
+//ZOID
+ // check to see if we already have a tmp for this file, if so, try to resume
+ // open the file if not opened yet
+ CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
+
+// FS_CreatePath (name);
+
+ fp = fopen (name, "r+b");
+ if (fp) { // it exists
+ int len;
+ fseek(fp, 0, SEEK_END);
+ len = ftell(fp);
+
+ cls.download = fp;
+
+ // give the server an offset to start the download
+ Com_Printf ("Resuming %s\n", cls.downloadname);
+ MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+ MSG_WriteString (&cls.netchan.message,
+ va("download %s %i", cls.downloadname, len));
+ } else {
+ Com_Printf ("Downloading %s\n", cls.downloadname);
+ MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+ MSG_WriteString (&cls.netchan.message,
+ va("download %s", cls.downloadname));
+ }
+
+ cls.downloadnumber++;
+
+ return false;
+}
+
+/*
+===============
+CL_Download_f
+
+Request a download from the server
+===============
+*/
+void CL_Download_f (void)
+{
+ char filename[MAX_OSPATH];
+
+ if (Cmd_Argc() != 2) {
+ Com_Printf("Usage: download <filename>\n");
+ return;
+ }
+
+ Com_sprintf(filename, sizeof(filename), "%s", Cmd_Argv(1));
+
+ if (strstr (filename, ".."))
+ {
+ Com_Printf ("Refusing to download a path with ..\n");
+ return;
+ }
+
+ if (FS_LoadFile (filename, NULL) != -1)
+ { // it exists, no need to download
+ Com_Printf("File already exists.\n");
+ return;
+ }
+
+ strcpy (cls.downloadname, filename);
+ Com_Printf ("Downloading %s\n", cls.downloadname);
+
+ // download to a temp name, and only rename
+ // to the real name when done, so if interrupted
+ // a runt file wont be left
+ COM_StripExtension (cls.downloadname, cls.downloadtempname);
+ strcat (cls.downloadtempname, ".tmp");
+
+ MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+ MSG_WriteString (&cls.netchan.message,
+ va("download %s", cls.downloadname));
+
+ cls.downloadnumber++;
+}
+
+/*
+======================
+CL_RegisterSounds
+======================
+*/
+void CL_RegisterSounds (void)
+{
+ int i;
+
+ S_BeginRegistration ();
+ CL_RegisterTEntSounds ();
+ for (i=1 ; i<MAX_SOUNDS ; i++)
+ {
+ if (!cl.configstrings[CS_SOUNDS+i][0])
+ break;
+ cl.sound_precache[i] = S_RegisterSound (cl.configstrings[CS_SOUNDS+i]);
+ Sys_SendKeyEvents (); // pump message loop
+ }
+ S_EndRegistration ();
+}
+
+static void
+rename(char *old, char *new)
+{
+ char *p;
+ Dir d;
+
+ if((p = strrchr(new, '/')) == nil)
+ p = new;
+ else
+ p++;
+ nulldir(&d);
+ d.name = p;
+ if(dirwstat(old, &d) < 0)
+ fprint(2, "rename: %r\n");
+}
+
+/*
+=====================
+CL_ParseDownload
+
+A download message has been received from the server
+=====================
+*/
+void CL_ParseDownload (void)
+{
+ int size, percent;
+ char name[MAX_OSPATH];
+
+ // read the data
+ size = MSG_ReadShort (&net_message);
+ percent = MSG_ReadByte (&net_message);
+ if (size == -1)
+ {
+ Com_Printf ("Server does not have this file.\n");
+ if (cls.download)
+ {
+ // if here, we tried to resume a file but the server said no
+ fclose (cls.download);
+ cls.download = NULL;
+ }
+ CL_RequestNextDownload ();
+ return;
+ }
+
+ // open the file if not opened yet
+ if (!cls.download)
+ {
+ CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
+
+ FS_CreatePath (name);
+
+ cls.download = fopen (name, "wb");
+ if (!cls.download)
+ {
+ net_message.readcount += size;
+ Com_Printf ("Failed to open %s\n", cls.downloadtempname);
+ CL_RequestNextDownload ();
+ return;
+ }
+ }
+
+ fwrite (net_message.data + net_message.readcount, 1, size, cls.download);
+ net_message.readcount += size;
+
+ if (percent != 100)
+ {
+ // request next block
+// change display routines by zoid
+/*
+ Com_Printf (".");
+ if (10*(percent/10) != cls.downloadpercent)
+ {
+ cls.downloadpercent = 10*(percent/10);
+ Com_Printf ("%i%%", cls.downloadpercent);
+ }
+*/
+ cls.downloadpercent = percent;
+
+ MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
+ SZ_Print (&cls.netchan.message, "nextdl");
+ }
+ else
+ {
+ char oldn[MAX_OSPATH];
+ char newn[MAX_OSPATH];
+
+// Com_Printf ("100%%\n");
+
+ fclose (cls.download);
+
+ // rename the temp file to it's final name
+ CL_DownloadFileName(oldn, sizeof(oldn), cls.downloadtempname);
+ CL_DownloadFileName(newn, sizeof(newn), cls.downloadname);
+ rename (oldn, newn); /* FIXME */
+
+ cls.download = NULL;
+ cls.downloadpercent = 0;
+
+ // get another file if needed
+
+ CL_RequestNextDownload ();
+ }
+}
+
+
+/*
+=====================================================================
+
+ SERVER CONNECTING MESSAGES
+
+=====================================================================
+*/
+
+/*
+==================
+CL_ParseServerData
+==================
+*/
+void CL_ParseServerData (void)
+{
+ extern cvar_t *fs_gamedirvar;
+ char *str;
+ int i;
+
+ Com_DPrintf ("Serverdata packet received.\n");
+//
+// wipe the client_state_t struct
+//
+ CL_ClearState ();
+ cls.state = ca_connected;
+
+// parse protocol version number
+ i = MSG_ReadLong (&net_message);
+ cls.serverProtocol = i;
+
+ // BIG HACK to let demos from release work with the 3.0x patch!!!
+ if (Com_ServerState() && PROTOCOL_VERSION == 34)
+ {
+ }
+ else if (i != PROTOCOL_VERSION)
+ Com_Error (ERR_DROP,"Server returned version %i, not %i", i, PROTOCOL_VERSION);
+
+ cl.servercount = MSG_ReadLong (&net_message);
+ cl.attractloop = MSG_ReadByte (&net_message);
+
+ // game directory
+ str = MSG_ReadString (&net_message);
+ strncpy (cl.gamedir, str, sizeof(cl.gamedir)-1);
+
+ // set gamedir
+ if ((*str && (!fs_gamedirvar->string || !*fs_gamedirvar->string || strcmp(fs_gamedirvar->string, str))) || (!*str && (fs_gamedirvar->string || *fs_gamedirvar->string)))
+ Cvar_Set("game", str);
+
+ // parse player entity number
+ cl.playernum = MSG_ReadShort (&net_message);
+
+ // get the full level name
+ str = MSG_ReadString (&net_message);
+
+ if (cl.playernum == -1)
+ { // playing a cinematic or showing a pic, not a level
+ SCR_PlayCinematic (str);
+ }
+ else
+ {
+ // seperate the printfs so the server message can have a color
+ Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
+ Com_Printf ("%c%s\n", 2, str);
+
+ // need to prep refresh at next oportunity
+ cl.refresh_prepped = false;
+ }
+}
+
+/*
+==================
+CL_ParseBaseline
+==================
+*/
+void CL_ParseBaseline (void)
+{
+ entity_state_t *es;
+ int bits;
+ int newnum;
+ entity_state_t nullstate;
+
+ memset (&nullstate, 0, sizeof(nullstate));
+
+ newnum = CL_ParseEntityBits (&bits);
+ es = &cl_entities[newnum].baseline;
+ CL_ParseDelta (&nullstate, es, newnum, bits);
+}
+
+
+/*
+================
+CL_LoadClientinfo
+
+================
+*/
+void CL_LoadClientinfo (clientinfo_t *ci, char *s)
+{
+ int i;
+ char *t;
+ char model_name[MAX_QPATH];
+ char skin_name[MAX_QPATH];
+ char model_filename[MAX_QPATH];
+ char skin_filename[MAX_QPATH];
+ char weapon_filename[MAX_QPATH];
+
+ strncpy(ci->cinfo, s, sizeof(ci->cinfo));
+ ci->cinfo[sizeof(ci->cinfo)-1] = 0;
+
+ // isolate the player's name
+ strncpy(ci->name, s, sizeof(ci->name));
+ ci->name[sizeof(ci->name)-1] = 0;
+ t = strstr (s, "\\");
+ if (t)
+ {
+ ci->name[t-s] = 0;
+ s = t+1;
+ }
+
+ if (cl_noskins->value || *s == 0)
+ {
+ Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
+ Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/weapon.md2");
+ Com_sprintf (skin_filename, sizeof(skin_filename), "players/male/grunt.pcx");
+ Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/male/grunt_i.pcx");
+ ci->model = re.RegisterModel (model_filename);
+ memset(ci->weaponmodel, 0, sizeof(ci->weaponmodel));
+ ci->weaponmodel[0] = re.RegisterModel (weapon_filename);
+ ci->skin = re.RegisterSkin (skin_filename);
+ ci->icon = re.RegisterPic (ci->iconname);
+ }
+ else
+ {
+ // isolate the model name
+ strcpy (model_name, s);
+ t = strstr(model_name, "/");
+ if (!t)
+ t = strstr(model_name, "\\");
+ if (!t)
+ t = model_name;
+ *t = 0;
+
+ // isolate the skin name
+ strcpy (skin_name, s + strlen(model_name) + 1);
+
+ // model file
+ Com_sprintf (model_filename, sizeof(model_filename), "players/%s/tris.md2", model_name);
+ ci->model = re.RegisterModel (model_filename);
+ if (!ci->model)
+ {
+ strcpy(model_name, "male");
+ Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
+ ci->model = re.RegisterModel (model_filename);
+ }
+
+ // skin file
+ Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
+ ci->skin = re.RegisterSkin (skin_filename);
+
+ // if we don't have the skin and the model wasn't male,
+ // see if the male has it (this is for CTF's skins)
+ if (!ci->skin && cistrcmp(model_name, "male"))
+ {
+ // change model to male
+ strcpy(model_name, "male");
+ Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
+ ci->model = re.RegisterModel (model_filename);
+
+ // see if the skin exists for the male model
+ Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
+ ci->skin = re.RegisterSkin (skin_filename);
+ }
+
+ // if we still don't have a skin, it means that the male model didn't have
+ // it, so default to grunt
+ if (!ci->skin) {
+ // see if the skin exists for the male model
+ Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/grunt.pcx", model_name, skin_name);
+ ci->skin = re.RegisterSkin (skin_filename);
+ }
+
+ // weapon file
+ for (i = 0; i < num_cl_weaponmodels; i++) {
+ Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/%s/%s", model_name, cl_weaponmodels[i]);
+ ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
+ if (!ci->weaponmodel[i] && strcmp(model_name, "cyborg") == 0) {
+ // try male
+ Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/%s", cl_weaponmodels[i]);
+ ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
+ }
+ if (!cl_vwep->value)
+ break; // only one when vwep is off
+ }
+
+ // icon file
+ Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/%s/%s_i.pcx", model_name, skin_name);
+ ci->icon = re.RegisterPic (ci->iconname);
+ }
+
+ // must have loaded all data types to be valud
+ if (!ci->skin || !ci->icon || !ci->model || !ci->weaponmodel[0])
+ {
+ ci->skin = NULL;
+ ci->icon = NULL;
+ ci->model = NULL;
+ ci->weaponmodel[0] = NULL;
+ return;
+ }
+}
+
+/*
+================
+CL_ParseClientinfo
+
+Load the skin, icon, and model for a client
+================
+*/
+void CL_ParseClientinfo (int player)
+{
+ char *s;
+ clientinfo_t *ci;
+
+ s = cl.configstrings[player+CS_PLAYERSKINS];
+
+ ci = &cl.clientinfo[player];
+
+ CL_LoadClientinfo (ci, s);
+}
+
+
+/*
+================
+CL_ParseConfigString
+================
+*/
+void CL_ParseConfigString (void)
+{
+ int i;
+ char *s;
+
+ i = MSG_ReadShort (&net_message);
+ if (i < 0 || i >= MAX_CONFIGSTRINGS)
+ Com_Error (ERR_DROP, "configstring > MAX_CONFIGSTRINGS");
+ s = MSG_ReadString(&net_message);
+ strcpy (cl.configstrings[i], s);
+
+ // do something apropriate
+
+ if (i >= CS_LIGHTS && i < CS_LIGHTS+MAX_LIGHTSTYLES)
+ CL_SetLightstyle (i - CS_LIGHTS);
+ else if (i == CS_CDTRACK)
+ {
+ if (cl.refresh_prepped)
+ CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
+ }
+ else if (i >= CS_MODELS && i < CS_MODELS+MAX_MODELS)
+ {
+ if (cl.refresh_prepped)
+ {
+ cl.model_draw[i-CS_MODELS] = re.RegisterModel (cl.configstrings[i]);
+ if (cl.configstrings[i][0] == '*')
+ cl.model_clip[i-CS_MODELS] = CM_InlineModel (cl.configstrings[i]);
+ else
+ cl.model_clip[i-CS_MODELS] = NULL;
+ }
+ }
+ else if (i >= CS_SOUNDS && i < CS_SOUNDS+MAX_MODELS)
+ {
+ if (cl.refresh_prepped)
+ cl.sound_precache[i-CS_SOUNDS] = S_RegisterSound (cl.configstrings[i]);
+ }
+ else if (i >= CS_IMAGES && i < CS_IMAGES+MAX_MODELS)
+ {
+ if (cl.refresh_prepped)
+ cl.image_precache[i-CS_IMAGES] = re.RegisterPic (cl.configstrings[i]);
+ }
+ else if (i >= CS_PLAYERSKINS && i < CS_PLAYERSKINS+MAX_CLIENTS)
+ {
+ if (cl.refresh_prepped)
+ CL_ParseClientinfo (i-CS_PLAYERSKINS);
+ }
+}
+
+
+/*
+=====================================================================
+
+ACTION MESSAGES
+
+=====================================================================
+*/
+
+/*
+==================
+CL_ParseStartSoundPacket
+==================
+*/
+void CL_ParseStartSoundPacket(void)
+{
+ vec3_t pos_v;
+ float *pos;
+ int channel, ent;
+ int sound_num;
+ float volume;
+ float attenuation;
+ int flags;
+ float ofs;
+
+ flags = MSG_ReadByte (&net_message);
+ sound_num = MSG_ReadByte (&net_message);
+
+ if (flags & SND_VOLUME)
+ volume = MSG_ReadByte (&net_message) / 255.0;
+ else
+ volume = DEFAULT_SOUND_PACKET_VOLUME;
+
+ if (flags & SND_ATTENUATION)
+ attenuation = MSG_ReadByte (&net_message) / 64.0;
+ else
+ attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
+
+ if (flags & SND_OFFSET)
+ ofs = MSG_ReadByte (&net_message) / 1000.0;
+ else
+ ofs = 0;
+
+ if (flags & SND_ENT)
+ { // entity reletive
+ channel = MSG_ReadShort(&net_message);
+ ent = channel>>3;
+ if (ent > MAX_EDICTS)
+ Com_Error (ERR_DROP,"CL_ParseStartSoundPacket: ent = %i", ent);
+
+ channel &= 7;
+ }
+ else
+ {
+ ent = 0;
+ channel = 0;
+ }
+
+ if (flags & SND_POS)
+ { // positioned in space
+ MSG_ReadPos (&net_message, pos_v);
+
+ pos = pos_v;
+ }
+ else // use entity number
+ pos = NULL;
+
+ if (!cl.sound_precache[sound_num])
+ return;
+
+ S_StartSound (pos, ent, channel, cl.sound_precache[sound_num], volume, attenuation, ofs);
+}
+
+
+void SHOWNET(char *s)
+{
+ if (cl_shownet->value>=2)
+ Com_Printf ("%3i:%s\n", net_message.readcount-1, s);
+}
+
+/*
+=====================
+CL_ParseServerMessage
+=====================
+*/
+void CL_ParseServerMessage (void)
+{
+ int cmd;
+ char *s;
+ int i;
+
+//
+// if recording demos, copy the message out
+//
+ if (cl_shownet->value == 1)
+ Com_Printf ("%i ",net_message.cursize);
+ else if (cl_shownet->value >= 2)
+ Com_Printf ("------------------\n");
+
+
+//
+// parse the message
+//
+ while (1)
+ {
+ if (net_message.readcount > net_message.cursize)
+ {
+ Com_Error (ERR_DROP,"CL_ParseServerMessage: Bad server message");
+ break;
+ }
+
+ cmd = MSG_ReadByte (&net_message);
+
+ if (cmd == -1)
+ {
+ SHOWNET("END OF MESSAGE");
+ break;
+ }
+
+ if (cl_shownet->value>=2)
+ {
+ if (!svc_strings[cmd])
+ Com_Printf ("%3i:BAD CMD %i\n", net_message.readcount-1,cmd);
+ else
+ SHOWNET(svc_strings[cmd]);
+ }
+
+ // other commands
+ switch (cmd)
+ {
+ default:
+ Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
+ break;
+
+ case svc_nop:
+// Com_Printf ("svc_nop\n");
+ break;
+
+ case svc_disconnect:
+ Com_Error (ERR_DISCONNECT,"Server disconnected\n");
+ break;
+
+ case svc_reconnect:
+ Com_Printf ("Server disconnected, reconnecting\n");
+ if (cls.download) {
+ //ZOID, close download
+ fclose (cls.download);
+ cls.download = NULL;
+ }
+ cls.state = ca_connecting;
+ cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
+ break;
+
+ case svc_print:
+ i = MSG_ReadByte (&net_message);
+ if (i == PRINT_CHAT)
+ {
+ S_StartLocalSound ("misc/talk.wav");
+ con.ormask = 128;
+ }
+ Com_Printf ("%s", MSG_ReadString (&net_message));
+ con.ormask = 0;
+ break;
+
+ case svc_centerprint:
+ SCR_CenterPrint (MSG_ReadString (&net_message));
+ break;
+
+ case svc_stufftext:
+ s = MSG_ReadString (&net_message);
+ Com_DPrintf ("stufftext: %s\n", s);
+ Cbuf_AddText (s);
+ break;
+
+ case svc_serverdata:
+ Cbuf_Execute (); // make sure any stuffed commands are done
+ CL_ParseServerData ();
+ break;
+
+ case svc_configstring:
+ CL_ParseConfigString ();
+ break;
+
+ case svc_sound:
+ CL_ParseStartSoundPacket();
+ break;
+
+ case svc_spawnbaseline:
+ CL_ParseBaseline ();
+ break;
+
+ case svc_temp_entity:
+ CL_ParseTEnt ();
+ break;
+
+ case svc_muzzleflash:
+ CL_ParseMuzzleFlash ();
+ break;
+
+ case svc_muzzleflash2:
+ CL_ParseMuzzleFlash2 ();
+ break;
+
+ case svc_download:
+ CL_ParseDownload ();
+ break;
+
+ case svc_frame:
+ CL_ParseFrame ();
+ break;
+
+ case svc_inventory:
+ CL_ParseInventory ();
+ break;
+
+ case svc_layout:
+ s = MSG_ReadString (&net_message);
+ strncpy (cl.layout, s, sizeof(cl.layout)-1);
+ break;
+
+ case svc_playerinfo:
+ case svc_packetentities:
+ case svc_deltapacketentities:
+ Com_Error (ERR_DROP, "Out of place frame data");
+ break;
+ }
+ }
+
+ CL_AddNetgraph ();
+
+ //
+ // we don't know if it is ok to save a demo message until
+ // after we have parsed the frame
+ //
+ if (cls.demorecording && !cls.demowaiting)
+ CL_WriteDemoMessage ();
+
+}
+
+
--- /dev/null
+++ b/cl_pred.c
@@ -1,0 +1,260 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+
+/*
+===================
+CL_CheckPredictionError
+===================
+*/
+void CL_CheckPredictionError (void)
+{
+ int frame;
+ int delta[3];
+ int i;
+ int len;
+
+ if (!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
+ return;
+
+ // calculate the last usercmd_t we sent that the server has processed
+ frame = cls.netchan.incoming_acknowledged;
+ frame &= (CMD_BACKUP-1);
+
+ // compare what the server returned with what we had predicted it to be
+ VectorSubtract (cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame], delta);
+
+ // save the prediction error for interpolation
+ len = abs(delta[0]) + abs(delta[1]) + abs(delta[2]);
+ if (len > 640) // 80 world units
+ { // a teleport or something
+ VectorClear (cl.prediction_error);
+ }
+ else
+ {
+ if (cl_showmiss->value && (delta[0] || delta[1] || delta[2]) )
+ Com_Printf ("prediction miss on %i: %i\n", cl.frame.serverframe,
+ delta[0] + delta[1] + delta[2]);
+
+ VectorCopy (cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame]);
+
+ // save for error itnerpolation
+ for (i=0 ; i<3 ; i++)
+ cl.prediction_error[i] = delta[i]*0.125;
+ }
+}
+
+
+/*
+====================
+CL_ClipMoveToEntities
+
+====================
+*/
+void CL_ClipMoveToEntities ( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, trace_t *tr )
+{
+ int i, x, zd, zu;
+ trace_t trace;
+ int headnode;
+ float *angles;
+ entity_state_t *ent;
+ int num;
+ cmodel_t *cmodel;
+ vec3_t bmins, bmaxs;
+
+ for (i=0 ; i<cl.frame.num_entities ; i++)
+ {
+ num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
+ ent = &cl_parse_entities[num];
+
+ if (!ent->solid)
+ continue;
+
+ if (ent->number == cl.playernum+1)
+ continue;
+
+ if (ent->solid == 31)
+ { // special value for bmodel
+ cmodel = cl.model_clip[ent->modelindex];
+ if (!cmodel)
+ continue;
+ headnode = cmodel->headnode;
+ angles = ent->angles;
+ }
+ else
+ { // encoded bbox
+ x = 8*(ent->solid & 31);
+ zd = 8*((ent->solid>>5) & 31);
+ zu = 8*((ent->solid>>10) & 63) - 32;
+
+ bmins[0] = bmins[1] = -x;
+ bmaxs[0] = bmaxs[1] = x;
+ bmins[2] = -zd;
+ bmaxs[2] = zu;
+
+ headnode = CM_HeadnodeForBox (bmins, bmaxs);
+ angles = vec3_origin; // boxes don't rotate
+ }
+
+ if (tr->allsolid)
+ return;
+
+ trace = CM_TransformedBoxTrace (start, end,
+ mins, maxs, headnode, MASK_PLAYERSOLID,
+ ent->origin, angles);
+
+ if (trace.allsolid || trace.startsolid ||
+ trace.fraction < tr->fraction)
+ {
+ trace.ent = (edict_t *)ent;
+ if (tr->startsolid)
+ {
+ *tr = trace;
+ tr->startsolid = true;
+ }
+ else
+ *tr = trace;
+ }
+ else if (trace.startsolid)
+ tr->startsolid = true;
+ }
+}
+
+
+/*
+================
+CL_PMTrace
+================
+*/
+trace_t CL_PMTrace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
+{
+ trace_t t;
+
+ // check against world
+ t = CM_BoxTrace (start, end, mins, maxs, 0, MASK_PLAYERSOLID);
+ if (t.fraction < 1.0)
+ t.ent = (edict_t *)1;
+
+ // check all other solid models
+ CL_ClipMoveToEntities (start, mins, maxs, end, &t);
+
+ return t;
+}
+
+int CL_PMpointcontents (vec3_t point)
+{
+ int i;
+ entity_state_t *ent;
+ int num;
+ cmodel_t *cmodel;
+ int contents;
+
+ contents = CM_PointContents (point, 0);
+
+ for (i=0 ; i<cl.frame.num_entities ; i++)
+ {
+ num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
+ ent = &cl_parse_entities[num];
+
+ if (ent->solid != 31) // special value for bmodel
+ continue;
+
+ cmodel = cl.model_clip[ent->modelindex];
+ if (!cmodel)
+ continue;
+
+ contents |= CM_TransformedPointContents (point, cmodel->headnode, ent->origin, ent->angles);
+ }
+
+ return contents;
+}
+
+
+/*
+=================
+CL_PredictMovement
+
+Sets cl.predicted_origin and cl.predicted_angles
+=================
+*/
+void CL_PredictMovement (void)
+{
+ int ack, current;
+ int frame;
+ int oldframe;
+ usercmd_t *cmd;
+ pmove_t pm;
+ int i;
+ int step;
+ int oldz;
+
+ if (cls.state != ca_active)
+ return;
+
+ if (cl_paused->value)
+ return;
+
+ if (!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
+ { // just set angles
+ for (i=0 ; i<3 ; i++)
+ {
+ cl.predicted_angles[i] = cl.viewangles[i] + SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[i]);
+ }
+ return;
+ }
+
+ ack = cls.netchan.incoming_acknowledged;
+ current = cls.netchan.outgoing_sequence;
+
+ // if we are too far out of date, just freeze
+ if (current - ack >= CMD_BACKUP)
+ {
+ if (cl_showmiss->value)
+ Com_Printf ("exceeded CMD_BACKUP\n");
+ return;
+ }
+
+ // copy current state to pmove
+ memset (&pm, 0, sizeof(pm));
+ pm.trace = CL_PMTrace;
+ pm.pointcontents = CL_PMpointcontents;
+
+ pm_airaccelerate = atof(cl.configstrings[CS_AIRACCEL]);
+
+ pm.s = cl.frame.playerstate.pmove;
+
+// SCR_DebugGraph (current - ack - 1, 0);
+
+ // run frames
+ while (++ack < current)
+ {
+ frame = ack & (CMD_BACKUP-1);
+ cmd = &cl.cmds[frame];
+
+ pm.cmd = *cmd;
+ Pmove (&pm);
+
+ // save for debug checking
+ VectorCopy (pm.s.origin, cl.predicted_origins[frame]);
+ }
+
+ oldframe = (ack-2) & (CMD_BACKUP-1);
+ oldz = cl.predicted_origins[oldframe][2];
+ step = pm.s.origin[2] - oldz;
+ if (step > 63 && step < 160 && (pm.s.pm_flags & PMF_ON_GROUND) )
+ {
+ cl.predicted_step = step * 0.125;
+ cl.predicted_step_time = cls.realtime - cls.frametime * 500;
+ }
+
+
+ // copy results out for rendering
+ cl.predicted_origin[0] = pm.s.origin[0]*0.125;
+ cl.predicted_origin[1] = pm.s.origin[1]*0.125;
+ cl.predicted_origin[2] = pm.s.origin[2]*0.125;
+
+ VectorCopy (pm.viewangles, cl.predicted_angles);
+}
--- /dev/null
+++ b/cl_scrn.c
@@ -1,0 +1,1368 @@
+// cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc
+
+/*
+
+ full screen console
+ put up loading plaque
+ blanked background with loading plaque
+ blanked background with menu
+ cinematics
+ full screen image for quit and victory
+
+ end of unit intermissions
+
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+float scr_con_current; // aproaches scr_conlines at scr_conspeed
+float scr_conlines; // 0.0 to 1.0 lines of console to display
+
+qboolean scr_initialized; // ready to draw
+
+int scr_draw_loading;
+
+vrect_t scr_vrect; // position of render window on screen
+
+
+cvar_t *scr_viewsize;
+cvar_t *scr_conspeed;
+cvar_t *scr_centertime;
+cvar_t *scr_showturtle;
+cvar_t *scr_showpause;
+cvar_t *scr_printspeed;
+
+cvar_t *scr_netgraph;
+cvar_t *scr_timegraph;
+cvar_t *scr_debuggraph;
+cvar_t *scr_graphheight;
+cvar_t *scr_graphscale;
+cvar_t *scr_graphshift;
+cvar_t *scr_drawall;
+
+typedef struct
+{
+ int x1, y1, x2, y2;
+} dirty_t;
+
+dirty_t scr_dirty, scr_old_dirty[2];
+
+char crosshair_pic[MAX_QPATH];
+int crosshair_width, crosshair_height;
+
+void SCR_TimeRefresh_f (void);
+void SCR_Loading_f (void);
+
+
+/*
+===============================================================================
+
+BAR GRAPHS
+
+===============================================================================
+*/
+
+/*
+==============
+CL_AddNetgraph
+
+A new packet was just parsed
+==============
+*/
+void CL_AddNetgraph (void)
+{
+ int i;
+ int in;
+ int ping;
+
+ // if using the debuggraph for something else, don't
+ // add the net lines
+ if (scr_debuggraph->value || scr_timegraph->value)
+ return;
+
+ for (i=0 ; i<cls.netchan.dropped ; i++)
+ SCR_DebugGraph (30, 0x40);
+
+ for (i=0 ; i<cl.surpressCount ; i++)
+ SCR_DebugGraph (30, 0xdf);
+
+ // see what the latency was on this packet
+ in = cls.netchan.incoming_acknowledged & (CMD_BACKUP-1);
+ ping = cls.realtime - cl.cmd_time[in];
+ ping /= 30;
+ if (ping > 30)
+ ping = 30;
+ SCR_DebugGraph (ping, 0xd0);
+}
+
+
+typedef struct
+{
+ float value;
+ int color;
+} graphsamp_t;
+
+static int current;
+static graphsamp_t values[1024];
+
+/* this is in the client code, but can be used for debugging from server */
+void SCR_DebugGraph (float value, int color)
+{
+ values[current&1023].value = value;
+ values[current&1023].color = color;
+ current++;
+}
+
+/*
+==============
+SCR_DrawDebugGraph
+==============
+*/
+void SCR_DrawDebugGraph (void)
+{
+ int a, x, y, w, i, h;
+ float v;
+ int color;
+
+ //
+ // draw the graph
+ //
+ w = scr_vrect.width;
+
+ x = scr_vrect.x;
+ y = scr_vrect.y+scr_vrect.height;
+ re.DrawFill (x, y-scr_graphheight->value,
+ w, scr_graphheight->value, 8);
+
+ for (a=0 ; a<w ; a++)
+ {
+ i = (current-1-a+1024) & 1023;
+ v = values[i].value;
+ color = values[i].color;
+ v = v*scr_graphscale->value + scr_graphshift->value;
+
+ if (v < 0)
+ v += scr_graphheight->value * (1+(int)(-v/scr_graphheight->value));
+ h = (int)v % (int)scr_graphheight->value;
+ re.DrawFill (x+w-1-a, y - h, 1, h, color);
+ }
+}
+
+/*
+===============================================================================
+
+CENTER PRINTING
+
+===============================================================================
+*/
+
+char scr_centerstring[1024];
+float scr_centertime_start; // for slow victory printing
+float scr_centertime_off;
+int scr_center_lines;
+int scr_erase_center;
+
+/*
+==============
+SCR_CenterPrint
+
+Called for important messages that should stay in the center of the screen
+for a few moments
+==============
+*/
+void SCR_CenterPrint (char *str)
+{
+ char *s;
+ char line[64];
+ int i, j, l;
+
+ strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
+ scr_centertime_off = scr_centertime->value;
+ scr_centertime_start = cl.time;
+
+ // count the number of lines for centering
+ scr_center_lines = 1;
+ s = str;
+ while (*s)
+ {
+ if (*s == '\n')
+ scr_center_lines++;
+ s++;
+ }
+
+ // echo it to the console
+ Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
+
+ s = str;
+ do
+ {
+ // scan the width of the line
+ for (l=0 ; l<40 ; l++)
+ if (s[l] == '\n' || !s[l])
+ break;
+ for (i=0 ; i<(40-l)/2 ; i++)
+ line[i] = ' ';
+
+ for (j=0 ; j<l ; j++)
+ {
+ line[i++] = s[j];
+ }
+
+ line[i] = '\n';
+ line[i+1] = 0;
+
+ Com_Printf ("%s", line);
+
+ while (*s && *s != '\n')
+ s++;
+
+ if (!*s)
+ break;
+ s++; // skip the \n
+ } while (1);
+ Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
+ Con_ClearNotify ();
+}
+
+
+void SCR_DrawCenterString (void)
+{
+ char *start;
+ int l;
+ int j;
+ int x, y;
+ int remaining;
+
+// the finale prints the characters one at a time
+ remaining = 9999;
+
+ scr_erase_center = 0;
+ start = scr_centerstring;
+
+ if (scr_center_lines <= 4)
+ y = vid.height*0.35;
+ else
+ y = 48;
+
+ do
+ {
+ // scan the width of the line
+ for (l=0 ; l<40 ; l++)
+ if (start[l] == '\n' || !start[l])
+ break;
+ x = (vid.width - l*8)/2;
+ SCR_AddDirtyPoint (x, y);
+ for (j=0 ; j<l ; j++, x+=8)
+ {
+ re.DrawChar (x, y, start[j]);
+ if (!remaining--)
+ return;
+ }
+ SCR_AddDirtyPoint (x, y+8);
+
+ y += 8;
+
+ while (*start && *start != '\n')
+ start++;
+
+ if (!*start)
+ break;
+ start++; // skip the \n
+ } while (1);
+}
+
+void SCR_CheckDrawCenterString (void)
+{
+ scr_centertime_off -= cls.frametime;
+
+ if (scr_centertime_off <= 0)
+ return;
+
+ SCR_DrawCenterString ();
+}
+
+//=============================================================================
+
+/*
+=================
+SCR_CalcVrect
+
+Sets scr_vrect, the coordinates of the rendered window
+=================
+*/
+static void SCR_CalcVrect (void)
+{
+ int size;
+
+ // bound viewsize
+ if (scr_viewsize->value < 40)
+ Cvar_Set ("viewsize","40");
+ if (scr_viewsize->value > 100)
+ Cvar_Set ("viewsize","100");
+
+ size = scr_viewsize->value;
+
+ scr_vrect.width = vid.width*size/100;
+ scr_vrect.width &= ~7;
+
+ scr_vrect.height = vid.height*size/100;
+ scr_vrect.height &= ~1;
+
+ scr_vrect.x = (vid.width - scr_vrect.width)/2;
+ scr_vrect.y = (vid.height - scr_vrect.height)/2;
+}
+
+
+/*
+=================
+SCR_SizeUp_f
+
+Keybinding command
+=================
+*/
+void SCR_SizeUp_f (void)
+{
+ Cvar_SetValue ("viewsize",scr_viewsize->value+10);
+}
+
+
+/*
+=================
+SCR_SizeDown_f
+
+Keybinding command
+=================
+*/
+void SCR_SizeDown_f (void)
+{
+ Cvar_SetValue ("viewsize",scr_viewsize->value-10);
+}
+
+/*
+=================
+SCR_Sky_f
+
+Set a specific sky and rotation speed
+=================
+*/
+void SCR_Sky_f (void)
+{
+ float rotate;
+ vec3_t axis;
+
+ if (Cmd_Argc() < 2)
+ {
+ Com_Printf ("Usage: sky <basename> <rotate> <axis x y z>\n");
+ return;
+ }
+ if (Cmd_Argc() > 2)
+ rotate = atof(Cmd_Argv(2));
+ else
+ rotate = 0;
+ if (Cmd_Argc() == 6)
+ {
+ axis[0] = atof(Cmd_Argv(3));
+ axis[1] = atof(Cmd_Argv(4));
+ axis[2] = atof(Cmd_Argv(5));
+ }
+ else
+ {
+ axis[0] = 0;
+ axis[1] = 0;
+ axis[2] = 1;
+ }
+
+ re.SetSky (Cmd_Argv(1), rotate, axis);
+}
+
+//============================================================================
+
+/*
+==================
+SCR_Init
+==================
+*/
+void SCR_Init (void)
+{
+ scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE);
+ scr_conspeed = Cvar_Get ("scr_conspeed", "3", 0);
+ scr_showturtle = Cvar_Get ("scr_showturtle", "0", 0);
+ scr_showpause = Cvar_Get ("scr_showpause", "1", 0);
+ scr_centertime = Cvar_Get ("scr_centertime", "2.5", 0);
+ scr_printspeed = Cvar_Get ("scr_printspeed", "8", 0);
+ scr_netgraph = Cvar_Get ("netgraph", "0", 0);
+ scr_timegraph = Cvar_Get ("timegraph", "0", 0);
+ scr_debuggraph = Cvar_Get ("debuggraph", "0", 0);
+ scr_graphheight = Cvar_Get ("graphheight", "32", 0);
+ scr_graphscale = Cvar_Get ("graphscale", "1", 0);
+ scr_graphshift = Cvar_Get ("graphshift", "0", 0);
+ scr_drawall = Cvar_Get ("scr_drawall", "0", 0);
+
+//
+// register our commands
+//
+ Cmd_AddCommand ("timerefresh",SCR_TimeRefresh_f);
+ Cmd_AddCommand ("loading",SCR_Loading_f);
+ Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
+ Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
+ Cmd_AddCommand ("sky",SCR_Sky_f);
+
+ scr_initialized = true;
+}
+
+
+/*
+==============
+SCR_DrawNet
+==============
+*/
+void SCR_DrawNet (void)
+{
+ if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged
+ < CMD_BACKUP-1)
+ return;
+
+ re.DrawPic (scr_vrect.x+64, scr_vrect.y, "net");
+}
+
+/*
+==============
+SCR_DrawPause
+==============
+*/
+void SCR_DrawPause (void)
+{
+ int w, h;
+
+ if (!scr_showpause->value) // turn off for screenshots
+ return;
+
+ if (!cl_paused->value)
+ return;
+
+ re.DrawGetPicSize (&w, &h, "pause");
+ re.DrawPic ((vid.width-w)/2, vid.height/2 + 8, "pause");
+}
+
+/*
+==============
+SCR_DrawLoading
+==============
+*/
+void SCR_DrawLoading (void)
+{
+ int w, h;
+
+ if (!scr_draw_loading)
+ return;
+
+ scr_draw_loading = false;
+ re.DrawGetPicSize (&w, &h, "loading");
+ re.DrawPic ((vid.width-w)/2, (vid.height-h)/2, "loading");
+}
+
+//=============================================================================
+
+/*
+==================
+SCR_RunConsole
+
+Scroll it up or down
+==================
+*/
+void SCR_RunConsole (void)
+{
+// decide on the height of the console
+ if (cls.key_dest == key_console)
+ scr_conlines = 0.5; // half screen
+ else
+ scr_conlines = 0; // none visible
+
+ if (scr_conlines < scr_con_current)
+ {
+ scr_con_current -= scr_conspeed->value*cls.frametime;
+ if (scr_conlines > scr_con_current)
+ scr_con_current = scr_conlines;
+
+ }
+ else if (scr_conlines > scr_con_current)
+ {
+ scr_con_current += scr_conspeed->value*cls.frametime;
+ if (scr_conlines < scr_con_current)
+ scr_con_current = scr_conlines;
+ }
+
+}
+
+/*
+==================
+SCR_DrawConsole
+==================
+*/
+void SCR_DrawConsole (void)
+{
+ Con_CheckResize ();
+
+ if (cls.state == ca_disconnected || cls.state == ca_connecting)
+ { // forced full screen console
+ Con_DrawConsole (1.0);
+ return;
+ }
+
+ if (cls.state != ca_active || !cl.refresh_prepped)
+ { // connected, but can't render
+ Con_DrawConsole (0.5);
+ re.DrawFill (0, vid.height/2, vid.width, vid.height/2, 0);
+ return;
+ }
+
+ if (scr_con_current)
+ {
+ Con_DrawConsole (scr_con_current);
+ }
+ else
+ {
+ if (cls.key_dest == key_game || cls.key_dest == key_message)
+ Con_DrawNotify (); // only draw notify in game
+ }
+}
+
+//=============================================================================
+
+/*
+================
+SCR_BeginLoadingPlaque
+================
+*/
+void SCR_BeginLoadingPlaque (void)
+{
+ S_StopAllSounds ();
+ cl.sound_prepped = false; // don't play ambients
+ CDAudio_Stop ();
+ if (cls.disable_screen)
+ return;
+ if (developer->value)
+ return;
+ if (cls.state == ca_disconnected)
+ return; // if at console, don't bring up the plaque
+ if (cls.key_dest == key_console)
+ return;
+ if (cl.cinematictime > 0)
+ scr_draw_loading = 2; // clear to balack first
+ else
+ scr_draw_loading = 1;
+ SCR_UpdateScreen ();
+ cls.disable_screen = Sys_Milliseconds ();
+ cls.disable_servercount = cl.servercount;
+}
+
+/*
+================
+SCR_EndLoadingPlaque
+================
+*/
+void SCR_EndLoadingPlaque (void)
+{
+ cls.disable_screen = 0;
+ Con_ClearNotify ();
+}
+
+/*
+================
+SCR_Loading_f
+================
+*/
+void SCR_Loading_f (void)
+{
+ SCR_BeginLoadingPlaque ();
+}
+
+int
+entitycmpfnc(entity_t *a, entity_t *b)
+{
+ /* all other models are sorted by model then skin */
+ if(a->model == b->model)
+ return (uintptr)a->skin - (uintptr)b->skin;
+ else
+ return (uintptr)a->model - (uintptr)b->model;
+}
+
+void SCR_TimeRefresh_f (void)
+{
+ int i;
+ int start, stop;
+ float time;
+
+ if ( cls.state != ca_active )
+ return;
+
+ start = Sys_Milliseconds ();
+
+ if (Cmd_Argc() == 2)
+ { // run without page flipping
+ re.BeginFrame( 0 );
+ for (i=0 ; i<128 ; i++)
+ {
+ cl.refdef.viewangles[1] = i/128.0*360.0;
+ re.RenderFrame (&cl.refdef);
+ }
+ re.EndFrame();
+ }
+ else
+ {
+ for (i=0 ; i<128 ; i++)
+ {
+ cl.refdef.viewangles[1] = i/128.0*360.0;
+
+ re.BeginFrame( 0 );
+ re.RenderFrame (&cl.refdef);
+ re.EndFrame();
+ }
+ }
+
+ stop = Sys_Milliseconds ();
+ time = (stop-start)/1000.0;
+ Com_Printf ("%f seconds (%f fps)\n", time, 128/time);
+}
+
+/*
+=================
+SCR_AddDirtyPoint
+=================
+*/
+void SCR_AddDirtyPoint (int x, int y)
+{
+ if (x < scr_dirty.x1)
+ scr_dirty.x1 = x;
+ if (x > scr_dirty.x2)
+ scr_dirty.x2 = x;
+ if (y < scr_dirty.y1)
+ scr_dirty.y1 = y;
+ if (y > scr_dirty.y2)
+ scr_dirty.y2 = y;
+}
+
+void SCR_DirtyScreen (void)
+{
+ SCR_AddDirtyPoint (0, 0);
+ SCR_AddDirtyPoint (vid.width-1, vid.height-1);
+}
+
+/*
+==============
+SCR_TileClear
+
+Clear any parts of the tiled background that were drawn on last frame
+==============
+*/
+void SCR_TileClear (void)
+{
+ int i;
+ int top, bottom, left, right;
+ dirty_t clear;
+
+ if (scr_drawall->value)
+ SCR_DirtyScreen (); // for power vr or broken page flippers...
+
+ if (scr_con_current == 1.0)
+ return; // full screen console
+ if (scr_viewsize->value == 100)
+ return; // full screen rendering
+ if (cl.cinematictime > 0)
+ return; // full screen cinematic
+
+ // erase rect will be the union of the past three frames
+ // so tripple buffering works properly
+ clear = scr_dirty;
+ for (i=0 ; i<2 ; i++)
+ {
+ if (scr_old_dirty[i].x1 < clear.x1)
+ clear.x1 = scr_old_dirty[i].x1;
+ if (scr_old_dirty[i].x2 > clear.x2)
+ clear.x2 = scr_old_dirty[i].x2;
+ if (scr_old_dirty[i].y1 < clear.y1)
+ clear.y1 = scr_old_dirty[i].y1;
+ if (scr_old_dirty[i].y2 > clear.y2)
+ clear.y2 = scr_old_dirty[i].y2;
+ }
+
+ scr_old_dirty[1] = scr_old_dirty[0];
+ scr_old_dirty[0] = scr_dirty;
+
+ scr_dirty.x1 = 9999;
+ scr_dirty.x2 = -9999;
+ scr_dirty.y1 = 9999;
+ scr_dirty.y2 = -9999;
+
+ // don't bother with anything convered by the console)
+ top = scr_con_current*vid.height;
+ if (top >= clear.y1)
+ clear.y1 = top;
+
+ if (clear.y2 <= clear.y1)
+ return; // nothing disturbed
+
+ top = scr_vrect.y;
+ bottom = top + scr_vrect.height-1;
+ left = scr_vrect.x;
+ right = left + scr_vrect.width-1;
+
+ if (clear.y1 < top)
+ { // clear above view screen
+ i = clear.y2 < top-1 ? clear.y2 : top-1;
+ re.DrawTileClear (clear.x1 , clear.y1,
+ clear.x2 - clear.x1 + 1, i - clear.y1+1, "backtile");
+ clear.y1 = top;
+ }
+ if (clear.y2 > bottom)
+ { // clear below view screen
+ i = clear.y1 > bottom+1 ? clear.y1 : bottom+1;
+ re.DrawTileClear (clear.x1, i,
+ clear.x2-clear.x1+1, clear.y2-i+1, "backtile");
+ clear.y2 = bottom;
+ }
+ if (clear.x1 < left)
+ { // clear left of view screen
+ i = clear.x2 < left-1 ? clear.x2 : left-1;
+ re.DrawTileClear (clear.x1, clear.y1,
+ i-clear.x1+1, clear.y2 - clear.y1 + 1, "backtile");
+ clear.x1 = left;
+ }
+ if (clear.x2 > right)
+ { // clear left of view screen
+ i = clear.x1 > right+1 ? clear.x1 : right+1;
+ re.DrawTileClear (i, clear.y1,
+ clear.x2-i+1, clear.y2 - clear.y1 + 1, "backtile");
+ clear.x2 = right;
+ }
+
+}
+
+
+//===============================================================
+
+
+#define STAT_MINUS 10 // num frame for '-' stats digit
+char *sb_nums[2][11] =
+{
+ {"num_0", "num_1", "num_2", "num_3", "num_4", "num_5",
+ "num_6", "num_7", "num_8", "num_9", "num_minus"},
+ {"anum_0", "anum_1", "anum_2", "anum_3", "anum_4", "anum_5",
+ "anum_6", "anum_7", "anum_8", "anum_9", "anum_minus"}
+};
+
+#define ICON_WIDTH 24
+#define ICON_HEIGHT 24
+#define CHAR_WIDTH 16
+#define ICON_SPACE 8
+
+
+
+/*
+================
+SizeHUDString
+
+Allow embedded \n in the string
+================
+*/
+void SizeHUDString (char *string, int *w, int *h)
+{
+ int lines, width, current;
+
+ lines = 1;
+ width = 0;
+
+ current = 0;
+ while (*string)
+ {
+ if (*string == '\n')
+ {
+ lines++;
+ current = 0;
+ }
+ else
+ {
+ current++;
+ if (current > width)
+ width = current;
+ }
+ string++;
+ }
+
+ *w = width * 8;
+ *h = lines * 8;
+}
+
+void DrawHUDString (char *string, int x, int y, int centerwidth, int xor)
+{
+ int margin;
+ char line[1024];
+ int width;
+ int i;
+
+ margin = x;
+
+ while (*string)
+ {
+ // scan out one line of text from the string
+ width = 0;
+ while (*string && *string != '\n')
+ line[width++] = *string++;
+ line[width] = 0;
+
+ if (centerwidth)
+ x = margin + (centerwidth - width*8)/2;
+ else
+ x = margin;
+ for (i=0 ; i<width ; i++)
+ {
+ re.DrawChar (x, y, line[i]^xor);
+ x += 8;
+ }
+ if (*string)
+ {
+ string++; // skip the \n
+ y += 8;
+ }
+ }
+}
+
+
+/*
+==============
+SCR_DrawField
+==============
+*/
+void SCR_DrawField (int x, int y, int color, int width, int value)
+{
+ char num[16], *ptr;
+ int l;
+ int frame;
+
+ if (width < 1)
+ return;
+
+ // draw number string
+ if (width > 5)
+ width = 5;
+
+ SCR_AddDirtyPoint (x, y);
+ SCR_AddDirtyPoint (x+width*CHAR_WIDTH+2, y+23);
+
+ Com_sprintf (num, sizeof(num), "%i", value);
+ l = strlen(num);
+ if (l > width)
+ l = width;
+ x += 2 + CHAR_WIDTH*(width - l);
+
+ ptr = num;
+ while (*ptr && l)
+ {
+ if (*ptr == '-')
+ frame = STAT_MINUS;
+ else
+ frame = *ptr -'0';
+
+ re.DrawPic (x,y,sb_nums[color][frame]);
+ x += CHAR_WIDTH;
+ ptr++;
+ l--;
+ }
+}
+
+
+/*
+===============
+SCR_TouchPics
+
+Allows rendering code to cache all needed sbar graphics
+===============
+*/
+void SCR_TouchPics (void)
+{
+ int i, j;
+
+ for (i=0 ; i<2 ; i++)
+ for (j=0 ; j<11 ; j++)
+ re.RegisterPic (sb_nums[i][j]);
+
+ if (crosshair->value)
+ {
+ if (crosshair->value > 3 || crosshair->value < 0)
+ crosshair->value = 3;
+
+ Com_sprintf (crosshair_pic, sizeof(crosshair_pic), "ch%i", (int)(crosshair->value));
+ re.DrawGetPicSize (&crosshair_width, &crosshair_height, crosshair_pic);
+ if (!crosshair_width)
+ crosshair_pic[0] = 0;
+ }
+}
+
+/*
+================
+SCR_ExecuteLayoutString
+
+================
+*/
+void SCR_ExecuteLayoutString (char *s)
+{
+ int x, y;
+ int value;
+ char *token;
+ int width;
+ int index;
+ clientinfo_t *ci;
+
+ if (cls.state != ca_active || !cl.refresh_prepped)
+ return;
+
+ if (!s[0])
+ return;
+
+ x = 0;
+ y = 0;
+
+ while (s)
+ {
+ token = COM_Parse (&s);
+ if (!strcmp(token, "xl"))
+ {
+ token = COM_Parse (&s);
+ x = atoi(token);
+ continue;
+ }
+ if (!strcmp(token, "xr"))
+ {
+ token = COM_Parse (&s);
+ x = vid.width + atoi(token);
+ continue;
+ }
+ if (!strcmp(token, "xv"))
+ {
+ token = COM_Parse (&s);
+ x = vid.width/2 - 160 + atoi(token);
+ continue;
+ }
+
+ if (!strcmp(token, "yt"))
+ {
+ token = COM_Parse (&s);
+ y = atoi(token);
+ continue;
+ }
+ if (!strcmp(token, "yb"))
+ {
+ token = COM_Parse (&s);
+ y = vid.height + atoi(token);
+ continue;
+ }
+ if (!strcmp(token, "yv"))
+ {
+ token = COM_Parse (&s);
+ y = vid.height/2 - 120 + atoi(token);
+ continue;
+ }
+
+ if (!strcmp(token, "pic"))
+ { // draw a pic from a stat number
+ token = COM_Parse (&s);
+ value = cl.frame.playerstate.stats[atoi(token)];
+ if (value >= MAX_IMAGES)
+ Com_Error (ERR_DROP, "Pic >= MAX_IMAGES");
+ if (cl.configstrings[CS_IMAGES+value])
+ {
+ SCR_AddDirtyPoint (x, y);
+ SCR_AddDirtyPoint (x+23, y+23);
+ re.DrawPic (x, y, cl.configstrings[CS_IMAGES+value]);
+ }
+ continue;
+ }
+
+ if (!strcmp(token, "client"))
+ { // draw a deathmatch client block
+ int score, ping, time;
+
+ token = COM_Parse (&s);
+ x = vid.width/2 - 160 + atoi(token);
+ token = COM_Parse (&s);
+ y = vid.height/2 - 120 + atoi(token);
+ SCR_AddDirtyPoint (x, y);
+ SCR_AddDirtyPoint (x+159, y+31);
+
+ token = COM_Parse (&s);
+ value = atoi(token);
+ if (value >= MAX_CLIENTS || value < 0)
+ Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
+ ci = &cl.clientinfo[value];
+
+ token = COM_Parse (&s);
+ score = atoi(token);
+
+ token = COM_Parse (&s);
+ ping = atoi(token);
+
+ token = COM_Parse (&s);
+ time = atoi(token);
+
+ DrawAltString (x+32, y, ci->name);
+ DrawString (x+32, y+8, "Score: ");
+ DrawAltString (x+32+7*8, y+8, va("%i", score));
+ DrawString (x+32, y+16, va("Ping: %i", ping));
+ DrawString (x+32, y+24, va("Time: %i", time));
+
+ if (!ci->icon)
+ ci = &cl.baseclientinfo;
+ re.DrawPic (x, y, ci->iconname);
+ continue;
+ }
+
+ if (!strcmp(token, "ctf"))
+ { // draw a ctf client block
+ int score, ping;
+ char block[80];
+
+ token = COM_Parse (&s);
+ x = vid.width/2 - 160 + atoi(token);
+ token = COM_Parse (&s);
+ y = vid.height/2 - 120 + atoi(token);
+ SCR_AddDirtyPoint (x, y);
+ SCR_AddDirtyPoint (x+159, y+31);
+
+ token = COM_Parse (&s);
+ value = atoi(token);
+ if (value >= MAX_CLIENTS || value < 0)
+ Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
+ ci = &cl.clientinfo[value];
+
+ token = COM_Parse (&s);
+ score = atoi(token);
+
+ token = COM_Parse (&s);
+ ping = atoi(token);
+ if (ping > 999)
+ ping = 999;
+
+ sprintf(block, "%3d %3d %-12.12s", score, ping, ci->name);
+
+ if (value == cl.playernum)
+ DrawAltString (x, y, block);
+ else
+ DrawString (x, y, block);
+ continue;
+ }
+
+ if (!strcmp(token, "picn"))
+ { // draw a pic from a name
+ token = COM_Parse (&s);
+ SCR_AddDirtyPoint (x, y);
+ SCR_AddDirtyPoint (x+23, y+23);
+ re.DrawPic (x, y, token);
+ continue;
+ }
+
+ if (!strcmp(token, "num"))
+ { // draw a number
+ token = COM_Parse (&s);
+ width = atoi(token);
+ token = COM_Parse (&s);
+ value = cl.frame.playerstate.stats[atoi(token)];
+ SCR_DrawField (x, y, 0, width, value);
+ continue;
+ }
+
+ if (!strcmp(token, "hnum"))
+ { // health number
+ int color;
+
+ width = 3;
+ value = cl.frame.playerstate.stats[STAT_HEALTH];
+ if (value > 25)
+ color = 0; // green
+ else if (value > 0)
+ color = (cl.frame.serverframe>>2) & 1; // flash
+ else
+ color = 1;
+
+ if (cl.frame.playerstate.stats[STAT_FLASHES] & 1)
+ re.DrawPic (x, y, "field_3");
+
+ SCR_DrawField (x, y, color, width, value);
+ continue;
+ }
+
+ if (!strcmp(token, "anum"))
+ { // ammo number
+ int color;
+
+ width = 3;
+ value = cl.frame.playerstate.stats[STAT_AMMO];
+ if (value > 5)
+ color = 0; // green
+ else if (value >= 0)
+ color = (cl.frame.serverframe>>2) & 1; // flash
+ else
+ continue; // negative number = don't show
+
+ if (cl.frame.playerstate.stats[STAT_FLASHES] & 4)
+ re.DrawPic (x, y, "field_3");
+
+ SCR_DrawField (x, y, color, width, value);
+ continue;
+ }
+
+ if (!strcmp(token, "rnum"))
+ { // armor number
+ int color;
+
+ width = 3;
+ value = cl.frame.playerstate.stats[STAT_ARMOR];
+ if (value < 1)
+ continue;
+
+ color = 0; // green
+
+ if (cl.frame.playerstate.stats[STAT_FLASHES] & 2)
+ re.DrawPic (x, y, "field_3");
+
+ SCR_DrawField (x, y, color, width, value);
+ continue;
+ }
+
+
+ if (!strcmp(token, "stat_string"))
+ {
+ token = COM_Parse (&s);
+ index = atoi(token);
+ if (index < 0 || index >= MAX_CONFIGSTRINGS)
+ Com_Error (ERR_DROP, "Bad stat_string index");
+ index = cl.frame.playerstate.stats[index];
+ if (index < 0 || index >= MAX_CONFIGSTRINGS)
+ Com_Error (ERR_DROP, "Bad stat_string index");
+ DrawString (x, y, cl.configstrings[index]);
+ continue;
+ }
+
+ if (!strcmp(token, "cstring"))
+ {
+ token = COM_Parse (&s);
+ DrawHUDString (token, x, y, 320, 0);
+ continue;
+ }
+
+ if (!strcmp(token, "string"))
+ {
+ token = COM_Parse (&s);
+ DrawString (x, y, token);
+ continue;
+ }
+
+ if (!strcmp(token, "cstring2"))
+ {
+ token = COM_Parse (&s);
+ DrawHUDString (token, x, y, 320,0x80);
+ continue;
+ }
+
+ if (!strcmp(token, "string2"))
+ {
+ token = COM_Parse (&s);
+ DrawAltString (x, y, token);
+ continue;
+ }
+
+ if (!strcmp(token, "if"))
+ { // draw a number
+ token = COM_Parse (&s);
+ value = cl.frame.playerstate.stats[atoi(token)];
+ if (!value)
+ { // skip to endif
+ while (s && strcmp(token, "endif") )
+ {
+ token = COM_Parse (&s);
+ }
+ }
+
+ continue;
+ }
+
+
+ }
+}
+
+
+/*
+================
+SCR_DrawStats
+
+The status bar is a small layout program that
+is based on the stats array
+================
+*/
+void SCR_DrawStats (void)
+{
+ SCR_ExecuteLayoutString (cl.configstrings[CS_STATUSBAR]);
+}
+
+
+/*
+================
+SCR_DrawLayout
+
+================
+*/
+void SCR_DrawLayout (void)
+{
+ if (!cl.frame.playerstate.stats[STAT_LAYOUTS])
+ return;
+ SCR_ExecuteLayoutString (cl.layout);
+}
+
+//=======================================================
+
+/*
+==================
+SCR_UpdateScreen
+
+This is called every frame, and can also be called explicitly to flush
+text to the screen.
+==================
+*/
+void SCR_UpdateScreen (void)
+{
+ int numframes;
+ int i;
+ float separation[2] = { 0, 0 };
+
+ // if the screen is disabled (loading plaque is up, or vid mode changing)
+ // do nothing at all
+ if (cls.disable_screen)
+ {
+ if (Sys_Milliseconds() - cls.disable_screen > 120000)
+ {
+ cls.disable_screen = 0;
+ Com_Printf ("Loading plaque timed out.\n");
+ }
+ return;
+ }
+
+ if (!scr_initialized || !con.initialized)
+ return; // not initialized yet
+
+ /*
+ ** range check cl_camera_separation so we don't inadvertently fry someone's
+ ** brain
+ */
+ if ( cl_stereo_separation->value > 1.0 )
+ Cvar_SetValue( "cl_stereo_separation", 1.0 );
+ else if ( cl_stereo_separation->value < 0 )
+ Cvar_SetValue( "cl_stereo_separation", 0.0 );
+
+ if ( cl_stereo->value )
+ {
+ numframes = 2;
+ separation[0] = -cl_stereo_separation->value / 2;
+ separation[1] = cl_stereo_separation->value / 2;
+ }
+ else
+ {
+ separation[0] = 0;
+ separation[1] = 0;
+ numframes = 1;
+ }
+
+ for ( i = 0; i < numframes; i++ )
+ {
+ re.BeginFrame( separation[i] );
+
+ if (scr_draw_loading == 2)
+ { // loading plaque over black screen
+ int w, h;
+
+ re.CinematicSetPalette(NULL);
+ scr_draw_loading = false;
+ re.DrawGetPicSize (&w, &h, "loading");
+ re.DrawPic ((vid.width-w)/2, (vid.height-h)/2, "loading");
+// re.EndFrame();
+// return;
+ }
+ // if a cinematic is supposed to be running, handle menus
+ // and console specially
+ else if (cl.cinematictime > 0)
+ {
+ if (cls.key_dest == key_menu)
+ {
+ if (cl.cinematicpalette_active)
+ {
+ re.CinematicSetPalette(NULL);
+ cl.cinematicpalette_active = false;
+ }
+ M_Draw ();
+// re.EndFrame();
+// return;
+ }
+ else if (cls.key_dest == key_console)
+ {
+ if (cl.cinematicpalette_active)
+ {
+ re.CinematicSetPalette(NULL);
+ cl.cinematicpalette_active = false;
+ }
+ SCR_DrawConsole ();
+// re.EndFrame();
+// return;
+ }
+ else
+ {
+ SCR_DrawCinematic();
+// re.EndFrame();
+// return;
+ }
+ }
+ else
+ {
+
+ // make sure the game palette is active
+ if (cl.cinematicpalette_active)
+ {
+ re.CinematicSetPalette(NULL);
+ cl.cinematicpalette_active = false;
+ }
+
+ // do 3D refresh drawing, and then update the screen
+ SCR_CalcVrect ();
+
+ // clear any dirty part of the background
+ SCR_TileClear ();
+
+ V_RenderView ( separation[i] );
+
+ SCR_DrawStats ();
+ if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 1)
+ SCR_DrawLayout ();
+ if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 2)
+ CL_DrawInventory ();
+
+ SCR_DrawNet ();
+ SCR_CheckDrawCenterString ();
+
+ if (scr_timegraph->value)
+ SCR_DebugGraph (cls.frametime*300, 0);
+
+ if (scr_debuggraph->value || scr_timegraph->value || scr_netgraph->value)
+ SCR_DrawDebugGraph ();
+
+ SCR_DrawPause ();
+
+ SCR_DrawConsole ();
+
+ M_Draw ();
+
+ SCR_DrawLoading ();
+ }
+ }
+ re.EndFrame();
+}
--- /dev/null
+++ b/cl_tent.c
@@ -1,0 +1,1718 @@
+// cl_tent.c -- client side temporary entities
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+typedef enum
+{
+ ex_free, ex_explosion, ex_misc, ex_flash, ex_mflash, ex_poly, ex_poly2
+} exptype_t;
+
+typedef struct
+{
+ exptype_t type;
+ entity_t ent;
+
+ int frames;
+ float light;
+ vec3_t lightcolor;
+ float start;
+ int baseframe;
+} explosion_t;
+
+
+
+#define MAX_EXPLOSIONS 32
+explosion_t cl_explosions[MAX_EXPLOSIONS];
+
+
+#define MAX_BEAMS 32
+typedef struct
+{
+ int entity;
+ int dest_entity;
+ model_t *model;
+ int endtime;
+ vec3_t offset;
+ vec3_t start, end;
+} beam_t;
+beam_t cl_beams[MAX_BEAMS];
+//PMM - added this for player-linked beams. Currently only used by the plasma beam
+beam_t cl_playerbeams[MAX_BEAMS];
+
+
+#define MAX_LASERS 32
+typedef struct
+{
+ entity_t ent;
+ int endtime;
+} laser_t;
+laser_t cl_lasers[MAX_LASERS];
+
+//ROGUE
+cl_sustain_t cl_sustains[MAX_SUSTAINS];
+//ROGUE
+
+//PGM
+extern void CL_TeleportParticles (vec3_t org);
+//PGM
+
+void CL_BlasterParticles (vec3_t org, vec3_t dir);
+void CL_ExplosionParticles (vec3_t org);
+void CL_BFGExplosionParticles (vec3_t org);
+// RAFAEL
+void CL_BlueBlasterParticles (vec3_t org, vec3_t dir);
+
+sfx_t *cl_sfx_ric1;
+sfx_t *cl_sfx_ric2;
+sfx_t *cl_sfx_ric3;
+sfx_t *cl_sfx_lashit;
+sfx_t *cl_sfx_spark5;
+sfx_t *cl_sfx_spark6;
+sfx_t *cl_sfx_spark7;
+sfx_t *cl_sfx_railg;
+sfx_t *cl_sfx_rockexp;
+sfx_t *cl_sfx_grenexp;
+sfx_t *cl_sfx_watrexp;
+sfx_t *cl_sfx_plasexp;
+sfx_t *cl_sfx_footsteps[4];
+
+model_t *cl_mod_explode;
+model_t *cl_mod_smoke;
+model_t *cl_mod_flash;
+model_t *cl_mod_parasite_segment;
+model_t *cl_mod_grapple_cable;
+model_t *cl_mod_parasite_tip;
+model_t *cl_mod_explo4;
+model_t *cl_mod_bfg_explo;
+model_t *cl_mod_powerscreen;
+// RAFAEL
+model_t *cl_mod_plasmaexplo;
+
+//ROGUE
+sfx_t *cl_sfx_lightning;
+sfx_t *cl_sfx_disrexp;
+model_t *cl_mod_lightning;
+model_t *cl_mod_heatbeam;
+model_t *cl_mod_monster_heatbeam;
+model_t *cl_mod_explo4_big;
+
+//ROGUE
+/*
+=================
+CL_RegisterTEntSounds
+=================
+*/
+void CL_RegisterTEntSounds (void)
+{
+ int i;
+ char name[MAX_QPATH];
+
+ // PMM - version stuff
+// Com_Printf ("%s\n", ROGUE_VERSION_STRING);
+ // PMM
+ cl_sfx_ric1 = S_RegisterSound ("world/ric1.wav");
+ cl_sfx_ric2 = S_RegisterSound ("world/ric2.wav");
+ cl_sfx_ric3 = S_RegisterSound ("world/ric3.wav");
+ cl_sfx_lashit = S_RegisterSound("weapons/lashit.wav");
+ cl_sfx_spark5 = S_RegisterSound ("world/spark5.wav");
+ cl_sfx_spark6 = S_RegisterSound ("world/spark6.wav");
+ cl_sfx_spark7 = S_RegisterSound ("world/spark7.wav");
+ cl_sfx_railg = S_RegisterSound ("weapons/railgf1a.wav");
+ cl_sfx_rockexp = S_RegisterSound ("weapons/rocklx1a.wav");
+ cl_sfx_grenexp = S_RegisterSound ("weapons/grenlx1a.wav");
+ cl_sfx_watrexp = S_RegisterSound ("weapons/xpld_wat.wav");
+ // RAFAEL
+ // cl_sfx_plasexp = S_RegisterSound ("weapons/plasexpl.wav");
+ S_RegisterSound ("player/land1.wav");
+
+ S_RegisterSound ("player/fall2.wav");
+ S_RegisterSound ("player/fall1.wav");
+
+ for (i=0 ; i<4 ; i++)
+ {
+ Com_sprintf (name, sizeof(name), "player/step%i.wav", i+1);
+ cl_sfx_footsteps[i] = S_RegisterSound (name);
+ }
+
+//PGM
+ cl_sfx_lightning = S_RegisterSound ("weapons/tesla.wav");
+ cl_sfx_disrexp = S_RegisterSound ("weapons/disrupthit.wav");
+ // version stuff
+ sprintf (name, "weapons/sound%d.wav", ROGUE_VERSION_ID);
+ if (name[0] == 'w')
+ name[0] = 'W';
+//PGM
+}
+
+/*
+=================
+CL_RegisterTEntModels
+=================
+*/
+void CL_RegisterTEntModels (void)
+{
+ cl_mod_explode = re.RegisterModel ("models/objects/explode/tris.md2");
+ cl_mod_smoke = re.RegisterModel ("models/objects/smoke/tris.md2");
+ cl_mod_flash = re.RegisterModel ("models/objects/flash/tris.md2");
+ cl_mod_parasite_segment = re.RegisterModel ("models/monsters/parasite/segment/tris.md2");
+ cl_mod_grapple_cable = re.RegisterModel ("models/ctf/segment/tris.md2");
+ cl_mod_parasite_tip = re.RegisterModel ("models/monsters/parasite/tip/tris.md2");
+ cl_mod_explo4 = re.RegisterModel ("models/objects/r_explode/tris.md2");
+ cl_mod_bfg_explo = re.RegisterModel ("sprites/s_bfg2.sp2");
+ cl_mod_powerscreen = re.RegisterModel ("models/items/armor/effect/tris.md2");
+
+re.RegisterModel ("models/objects/laser/tris.md2");
+re.RegisterModel ("models/objects/grenade2/tris.md2");
+re.RegisterModel ("models/weapons/v_machn/tris.md2");
+re.RegisterModel ("models/weapons/v_handgr/tris.md2");
+re.RegisterModel ("models/weapons/v_shotg2/tris.md2");
+re.RegisterModel ("models/objects/gibs/bone/tris.md2");
+re.RegisterModel ("models/objects/gibs/sm_meat/tris.md2");
+re.RegisterModel ("models/objects/gibs/bone2/tris.md2");
+// RAFAEL
+// re.RegisterModel ("models/objects/blaser/tris.md2");
+
+re.RegisterPic ("w_machinegun");
+re.RegisterPic ("a_bullets");
+re.RegisterPic ("i_health");
+re.RegisterPic ("a_grenades");
+
+//ROGUE
+ cl_mod_explo4_big = re.RegisterModel ("models/objects/r_explode2/tris.md2");
+ cl_mod_lightning = re.RegisterModel ("models/proj/lightning/tris.md2");
+ cl_mod_heatbeam = re.RegisterModel ("models/proj/beam/tris.md2");
+ cl_mod_monster_heatbeam = re.RegisterModel ("models/proj/widowbeam/tris.md2");
+//ROGUE
+}
+
+/*
+=================
+CL_ClearTEnts
+=================
+*/
+void CL_ClearTEnts (void)
+{
+ memset (cl_beams, 0, sizeof(cl_beams));
+ memset (cl_explosions, 0, sizeof(cl_explosions));
+ memset (cl_lasers, 0, sizeof(cl_lasers));
+
+//ROGUE
+ memset (cl_playerbeams, 0, sizeof(cl_playerbeams));
+ memset (cl_sustains, 0, sizeof(cl_sustains));
+//ROGUE
+}
+
+/*
+=================
+CL_AllocExplosion
+=================
+*/
+explosion_t *CL_AllocExplosion (void)
+{
+ int i;
+ int time;
+ int index;
+
+ for (i=0 ; i<MAX_EXPLOSIONS ; i++)
+ {
+ if (cl_explosions[i].type == ex_free)
+ {
+ memset (&cl_explosions[i], 0, sizeof (cl_explosions[i]));
+ return &cl_explosions[i];
+ }
+ }
+// find the oldest explosion
+ time = cl.time;
+ index = 0;
+
+ for (i=0 ; i<MAX_EXPLOSIONS ; i++)
+ if (cl_explosions[i].start < time)
+ {
+ time = cl_explosions[i].start;
+ index = i;
+ }
+ memset (&cl_explosions[index], 0, sizeof (cl_explosions[index]));
+ return &cl_explosions[index];
+}
+
+/*
+=================
+CL_SmokeAndFlash
+=================
+*/
+void CL_SmokeAndFlash(vec3_t origin)
+{
+ explosion_t *ex;
+
+ ex = CL_AllocExplosion ();
+ VectorCopy (origin, ex->ent.origin);
+ ex->type = ex_misc;
+ ex->frames = 4;
+ ex->ent.flags = RF_TRANSLUCENT;
+ ex->start = cl.frame.servertime - 100;
+ ex->ent.model = cl_mod_smoke;
+
+ ex = CL_AllocExplosion ();
+ VectorCopy (origin, ex->ent.origin);
+ ex->type = ex_flash;
+ ex->ent.flags = RF_FULLBRIGHT;
+ ex->frames = 2;
+ ex->start = cl.frame.servertime - 100;
+ ex->ent.model = cl_mod_flash;
+}
+
+/*
+=================
+CL_ParseParticles
+=================
+*/
+void CL_ParseParticles (void)
+{
+ int color, count;
+ vec3_t pos, dir;
+
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+
+ color = MSG_ReadByte (&net_message);
+
+ count = MSG_ReadByte (&net_message);
+
+ CL_ParticleEffect (pos, dir, color, count);
+}
+
+int
+CL_ParseBeam(model_t *model)
+{
+ int ent;
+ vec3_t start, end;
+ beam_t *b;
+ int i;
+
+ ent = MSG_ReadShort (&net_message);
+
+ MSG_ReadPos (&net_message, start);
+ MSG_ReadPos (&net_message, end);
+
+// override any beam with the same entity
+ for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+ if (b->entity == ent)
+ {
+ b->entity = ent;
+ b->model = model;
+ b->endtime = cl.time + 200;
+ VectorCopy (start, b->start);
+ VectorCopy (end, b->end);
+ VectorClear (b->offset);
+ return ent;
+ }
+
+// find a free beam
+ for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+ {
+ if (!b->model || b->endtime < cl.time)
+ {
+ b->entity = ent;
+ b->model = model;
+ b->endtime = cl.time + 200;
+ VectorCopy (start, b->start);
+ VectorCopy (end, b->end);
+ VectorClear (b->offset);
+ return ent;
+ }
+ }
+ Com_Printf ("beam list overflow!\n");
+ return ent;
+}
+
+int
+CL_ParseBeam2(model_t *model)
+{
+ int ent;
+ vec3_t start, end, offset;
+ beam_t *b;
+ int i;
+
+ ent = MSG_ReadShort (&net_message);
+
+ MSG_ReadPos (&net_message, start);
+ MSG_ReadPos (&net_message, end);
+ MSG_ReadPos (&net_message, offset);
+
+// Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
+
+// override any beam with the same entity
+
+ for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+ if (b->entity == ent)
+ {
+ b->entity = ent;
+ b->model = model;
+ b->endtime = cl.time + 200;
+ VectorCopy (start, b->start);
+ VectorCopy (end, b->end);
+ VectorCopy (offset, b->offset);
+ return ent;
+ }
+
+// find a free beam
+ for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+ {
+ if (!b->model || b->endtime < cl.time)
+ {
+ b->entity = ent;
+ b->model = model;
+ b->endtime = cl.time + 200;
+ VectorCopy (start, b->start);
+ VectorCopy (end, b->end);
+ VectorCopy (offset, b->offset);
+ return ent;
+ }
+ }
+ Com_Printf ("beam list overflow!\n");
+ return ent;
+}
+
+// ROGUE
+/*
+=================
+CL_ParsePlayerBeam
+ - adds to the cl_playerbeam array instead of the cl_beams array
+=================
+*/
+int
+CL_ParsePlayerBeam(model_t *model)
+{
+ int ent;
+ vec3_t start, end, offset;
+ beam_t *b;
+ int i;
+
+ ent = MSG_ReadShort (&net_message);
+
+ MSG_ReadPos (&net_message, start);
+ MSG_ReadPos (&net_message, end);
+ // PMM - network optimization
+ if (model == cl_mod_heatbeam)
+ VectorSet(offset, 2, 7, -3);
+ else if (model == cl_mod_monster_heatbeam)
+ {
+ model = cl_mod_heatbeam;
+ VectorSet(offset, 0, 0, 0);
+ }
+ else
+ MSG_ReadPos (&net_message, offset);
+
+// Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
+
+// override any beam with the same entity
+// PMM - For player beams, we only want one per player (entity) so..
+ for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
+ {
+ if (b->entity == ent)
+ {
+ b->entity = ent;
+ b->model = model;
+ b->endtime = cl.time + 200;
+ VectorCopy (start, b->start);
+ VectorCopy (end, b->end);
+ VectorCopy (offset, b->offset);
+ return ent;
+ }
+ }
+
+// find a free beam
+ for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
+ {
+ if (!b->model || b->endtime < cl.time)
+ {
+ b->entity = ent;
+ b->model = model;
+ b->endtime = cl.time + 100; // PMM - this needs to be 100 to prevent multiple heatbeams
+ VectorCopy (start, b->start);
+ VectorCopy (end, b->end);
+ VectorCopy (offset, b->offset);
+ return ent;
+ }
+ }
+ Com_Printf ("beam list overflow!\n");
+ return ent;
+}
+//rogue
+
+int
+CL_ParseLightning(model_t *model)
+{
+ int srcEnt, destEnt;
+ vec3_t start, end;
+ beam_t *b;
+ int i;
+
+ srcEnt = MSG_ReadShort (&net_message);
+ destEnt = MSG_ReadShort (&net_message);
+
+ MSG_ReadPos (&net_message, start);
+ MSG_ReadPos (&net_message, end);
+
+// override any beam with the same source AND destination entities
+ for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+ if (b->entity == srcEnt && b->dest_entity == destEnt)
+ {
+// Com_Printf("%d: OVERRIDE %d -> %d\n", cl.time, srcEnt, destEnt);
+ b->entity = srcEnt;
+ b->dest_entity = destEnt;
+ b->model = model;
+ b->endtime = cl.time + 200;
+ VectorCopy (start, b->start);
+ VectorCopy (end, b->end);
+ VectorClear (b->offset);
+ return srcEnt;
+ }
+
+// find a free beam
+ for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+ {
+ if (!b->model || b->endtime < cl.time)
+ {
+// Com_Printf("%d: NORMAL %d -> %d\n", cl.time, srcEnt, destEnt);
+ b->entity = srcEnt;
+ b->dest_entity = destEnt;
+ b->model = model;
+ b->endtime = cl.time + 200;
+ VectorCopy (start, b->start);
+ VectorCopy (end, b->end);
+ VectorClear (b->offset);
+ return srcEnt;
+ }
+ }
+ Com_Printf ("beam list overflow!\n");
+ return srcEnt;
+}
+
+/*
+=================
+CL_ParseLaser
+=================
+*/
+void CL_ParseLaser (int colors)
+{
+ vec3_t start;
+ vec3_t end;
+ laser_t *l;
+ int i;
+
+ MSG_ReadPos (&net_message, start);
+ MSG_ReadPos (&net_message, end);
+
+ for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
+ {
+ if (l->endtime < cl.time)
+ {
+ l->ent.flags = RF_TRANSLUCENT | RF_BEAM;
+ VectorCopy (start, l->ent.origin);
+ VectorCopy (end, l->ent.oldorigin);
+ l->ent.alpha = 0.30;
+ l->ent.skinnum = (colors >> ((rand() % 4)*8)) & 0xff;
+ l->ent.model = NULL;
+ l->ent.frame = 4;
+ l->endtime = cl.time + 100;
+ return;
+ }
+ }
+}
+
+//=============
+//ROGUE
+void CL_ParseSteam (void)
+{
+ vec3_t pos, dir;
+ int id, i;
+ int r;
+ int cnt;
+ int color;
+ int magnitude;
+ cl_sustain_t *s, *free_sustain;
+
+ id = MSG_ReadShort (&net_message); // an id of -1 is an instant effect
+ if (id != -1) // sustains
+ {
+// Com_Printf ("Sustain effect id %d\n", id);
+ free_sustain = NULL;
+ for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
+ {
+ if (s->id == 0)
+ {
+ free_sustain = s;
+ break;
+ }
+ }
+ if (free_sustain)
+ {
+ s->id = id;
+ s->count = MSG_ReadByte (&net_message);
+ MSG_ReadPos (&net_message, s->org);
+ MSG_ReadDir (&net_message, s->dir);
+ r = MSG_ReadByte (&net_message);
+ s->color = r & 0xff;
+ s->magnitude = MSG_ReadShort (&net_message);
+ s->endtime = cl.time + MSG_ReadLong (&net_message);
+ s->think = CL_ParticleSteamEffect2;
+ s->thinkinterval = 100;
+ s->nextthink = cl.time;
+ }
+ else
+ {
+// Com_Printf ("No free sustains!\n");
+ // FIXME - read the stuff anyway /* and toss the results */
+ MSG_ReadByte (&net_message);
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ MSG_ReadByte (&net_message);
+ MSG_ReadShort (&net_message);
+ MSG_ReadLong (&net_message); // really interval
+ }
+ }
+ else // instant
+ {
+ cnt = MSG_ReadByte (&net_message);
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ r = MSG_ReadByte (&net_message);
+ magnitude = MSG_ReadShort (&net_message);
+ color = r & 0xff;
+ CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
+// S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ }
+}
+
+void CL_ParseWidow (void)
+{
+ vec3_t pos;
+ int id, i;
+ cl_sustain_t *s, *free_sustain;
+
+ id = MSG_ReadShort (&net_message);
+
+ free_sustain = NULL;
+ for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
+ {
+ if (s->id == 0)
+ {
+ free_sustain = s;
+ break;
+ }
+ }
+ if (free_sustain)
+ {
+ s->id = id;
+ MSG_ReadPos (&net_message, s->org);
+ s->endtime = cl.time + 2100;
+ s->think = CL_Widowbeamout;
+ s->thinkinterval = 1;
+ s->nextthink = cl.time;
+ }
+ else // no free sustains
+ {
+ // FIXME - read the stuff anyway
+ MSG_ReadPos (&net_message, pos);
+ }
+}
+
+void CL_ParseNuke (void)
+{
+ vec3_t pos;
+ int i;
+ cl_sustain_t *s, *free_sustain;
+
+ free_sustain = NULL;
+ for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
+ {
+ if (s->id == 0)
+ {
+ free_sustain = s;
+ break;
+ }
+ }
+ if (free_sustain)
+ {
+ s->id = 21000;
+ MSG_ReadPos (&net_message, s->org);
+ s->endtime = cl.time + 1000;
+ s->think = CL_Nukeblast;
+ s->thinkinterval = 1;
+ s->nextthink = cl.time;
+ }
+ else // no free sustains
+ {
+ // FIXME - read the stuff anyway
+ MSG_ReadPos (&net_message, pos);
+ }
+}
+
+//ROGUE
+//=============
+
+
+/*
+=================
+CL_ParseTEnt
+=================
+*/
+static byte splash_color[] = {0x00, 0xe0, 0xb0, 0x50, 0xd0, 0xe0, 0xe8};
+
+void CL_ParseTEnt (void)
+{
+ int type;
+ vec3_t pos, pos2, dir;
+ explosion_t *ex;
+ int cnt;
+ int color;
+ int r;
+ int ent;
+ int magnitude;
+
+ type = MSG_ReadByte (&net_message);
+
+ switch (type)
+ {
+ case TE_BLOOD: // bullet hitting flesh
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ CL_ParticleEffect (pos, dir, 0xe8, 60);
+ break;
+
+ case TE_GUNSHOT: // bullet hitting wall
+ case TE_SPARKS:
+ case TE_BULLET_SPARKS:
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ if (type == TE_GUNSHOT)
+ CL_ParticleEffect (pos, dir, 0, 40);
+ else
+ CL_ParticleEffect (pos, dir, 0xe0, 6);
+
+ if (type != TE_SPARKS)
+ {
+ CL_SmokeAndFlash(pos);
+
+ // impact sound
+ cnt = rand()&15;
+ if (cnt == 1)
+ S_StartSound (pos, 0, 0, cl_sfx_ric1, 1, ATTN_NORM, 0);
+ else if (cnt == 2)
+ S_StartSound (pos, 0, 0, cl_sfx_ric2, 1, ATTN_NORM, 0);
+ else if (cnt == 3)
+ S_StartSound (pos, 0, 0, cl_sfx_ric3, 1, ATTN_NORM, 0);
+ }
+
+ break;
+
+ case TE_SCREEN_SPARKS:
+ case TE_SHIELD_SPARKS:
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ if (type == TE_SCREEN_SPARKS)
+ CL_ParticleEffect (pos, dir, 0xd0, 40);
+ else
+ CL_ParticleEffect (pos, dir, 0xb0, 40);
+ //FIXME : replace or remove this sound
+ S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_SHOTGUN: // bullet hitting wall
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ CL_ParticleEffect (pos, dir, 0, 20);
+ CL_SmokeAndFlash(pos);
+ break;
+
+ case TE_SPLASH: // bullet hitting water
+ cnt = MSG_ReadByte (&net_message);
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ r = MSG_ReadByte (&net_message);
+ if (r > 6)
+ color = 0x00;
+ else
+ color = splash_color[r];
+ CL_ParticleEffect (pos, dir, color, cnt);
+
+ if (r == SPLASH_SPARKS)
+ {
+ r = rand() & 3;
+ if (r == 0)
+ S_StartSound (pos, 0, 0, cl_sfx_spark5, 1, ATTN_STATIC, 0);
+ else if (r == 1)
+ S_StartSound (pos, 0, 0, cl_sfx_spark6, 1, ATTN_STATIC, 0);
+ else
+ S_StartSound (pos, 0, 0, cl_sfx_spark7, 1, ATTN_STATIC, 0);
+ }
+ break;
+
+ case TE_LASER_SPARKS:
+ cnt = MSG_ReadByte (&net_message);
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ color = MSG_ReadByte (&net_message);
+ CL_ParticleEffect2 (pos, dir, color, cnt);
+ break;
+
+ // RAFAEL
+ case TE_BLUEHYPERBLASTER:
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadPos (&net_message, dir);
+ CL_BlasterParticles (pos, dir);
+ break;
+
+ case TE_BLASTER: // blaster hitting wall
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ CL_BlasterParticles (pos, dir);
+
+ ex = CL_AllocExplosion ();
+ VectorCopy (pos, ex->ent.origin);
+ ex->ent.angles[0] = acos(dir[2])/M_PI*180;
+ // PMM - fixed to correct for pitch of 0
+ if (dir[0])
+ ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
+ else if (dir[1] > 0)
+ ex->ent.angles[1] = 90;
+ else if (dir[1] < 0)
+ ex->ent.angles[1] = 270;
+ else
+ ex->ent.angles[1] = 0;
+
+ ex->type = ex_misc;
+ ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
+ ex->start = cl.frame.servertime - 100;
+ ex->light = 150;
+ ex->lightcolor[0] = 1;
+ ex->lightcolor[1] = 1;
+ ex->ent.model = cl_mod_explode;
+ ex->frames = 4;
+ S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_RAILTRAIL: // railgun effect
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadPos (&net_message, pos2);
+ CL_RailTrail (pos, pos2);
+ S_StartSound (pos2, 0, 0, cl_sfx_railg, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_EXPLOSION2:
+ case TE_GRENADE_EXPLOSION:
+ case TE_GRENADE_EXPLOSION_WATER:
+ MSG_ReadPos (&net_message, pos);
+
+ ex = CL_AllocExplosion ();
+ VectorCopy (pos, ex->ent.origin);
+ ex->type = ex_poly;
+ ex->ent.flags = RF_FULLBRIGHT;
+ ex->start = cl.frame.servertime - 100;
+ ex->light = 350;
+ ex->lightcolor[0] = 1.0;
+ ex->lightcolor[1] = 0.5;
+ ex->lightcolor[2] = 0.5;
+ ex->ent.model = cl_mod_explo4;
+ ex->frames = 19;
+ ex->baseframe = 30;
+ ex->ent.angles[1] = rand() % 360;
+ CL_ExplosionParticles (pos);
+ if (type == TE_GRENADE_EXPLOSION_WATER)
+ S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
+ else
+ S_StartSound (pos, 0, 0, cl_sfx_grenexp, 1, ATTN_NORM, 0);
+ break;
+
+ // RAFAEL
+ case TE_PLASMA_EXPLOSION:
+ MSG_ReadPos (&net_message, pos);
+ ex = CL_AllocExplosion ();
+ VectorCopy (pos, ex->ent.origin);
+ ex->type = ex_poly;
+ ex->ent.flags = RF_FULLBRIGHT;
+ ex->start = cl.frame.servertime - 100;
+ ex->light = 350;
+ ex->lightcolor[0] = 1.0;
+ ex->lightcolor[1] = 0.5;
+ ex->lightcolor[2] = 0.5;
+ ex->ent.angles[1] = rand() % 360;
+ ex->ent.model = cl_mod_explo4;
+ if (qfrand() < 0.5)
+ ex->baseframe = 15;
+ ex->frames = 15;
+ CL_ExplosionParticles (pos);
+ S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_EXPLOSION1:
+ case TE_EXPLOSION1_BIG: // PMM
+ case TE_ROCKET_EXPLOSION:
+ case TE_ROCKET_EXPLOSION_WATER:
+ case TE_EXPLOSION1_NP: // PMM
+ MSG_ReadPos (&net_message, pos);
+
+ ex = CL_AllocExplosion ();
+ VectorCopy (pos, ex->ent.origin);
+ ex->type = ex_poly;
+ ex->ent.flags = RF_FULLBRIGHT;
+ ex->start = cl.frame.servertime - 100;
+ ex->light = 350;
+ ex->lightcolor[0] = 1.0;
+ ex->lightcolor[1] = 0.5;
+ ex->lightcolor[2] = 0.5;
+ ex->ent.angles[1] = rand() % 360;
+ if (type != TE_EXPLOSION1_BIG) // PMM
+ ex->ent.model = cl_mod_explo4; // PMM
+ else
+ ex->ent.model = cl_mod_explo4_big;
+ if (qfrand() < 0.5)
+ ex->baseframe = 15;
+ ex->frames = 15;
+ if ((type != TE_EXPLOSION1_BIG) && (type != TE_EXPLOSION1_NP)) // PMM
+ CL_ExplosionParticles (pos); // PMM
+ if (type == TE_ROCKET_EXPLOSION_WATER)
+ S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
+ else
+ S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_BFG_EXPLOSION:
+ MSG_ReadPos (&net_message, pos);
+ ex = CL_AllocExplosion ();
+ VectorCopy (pos, ex->ent.origin);
+ ex->type = ex_poly;
+ ex->ent.flags = RF_FULLBRIGHT;
+ ex->start = cl.frame.servertime - 100;
+ ex->light = 350;
+ ex->lightcolor[0] = 0.0;
+ ex->lightcolor[1] = 1.0;
+ ex->lightcolor[2] = 0.0;
+ ex->ent.model = cl_mod_bfg_explo;
+ ex->ent.flags |= RF_TRANSLUCENT;
+ ex->ent.alpha = 0.30;
+ ex->frames = 4;
+ break;
+
+ case TE_BFG_BIGEXPLOSION:
+ MSG_ReadPos (&net_message, pos);
+ CL_BFGExplosionParticles (pos);
+ break;
+
+ case TE_BFG_LASER:
+ CL_ParseLaser (0xd0d1d2d3);
+ break;
+
+ case TE_BUBBLETRAIL:
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadPos (&net_message, pos2);
+ CL_BubbleTrail (pos, pos2);
+ break;
+
+ case TE_PARASITE_ATTACK:
+ case TE_MEDIC_CABLE_ATTACK:
+ CL_ParseBeam (cl_mod_parasite_segment); /* toss result */
+ break;
+
+ case TE_BOSSTPORT: // boss teleporting to station
+ MSG_ReadPos (&net_message, pos);
+ CL_BigTeleportParticles (pos);
+ S_StartSound (pos, 0, 0, S_RegisterSound ("misc/bigtele.wav"), 1, ATTN_NONE, 0);
+ break;
+
+ case TE_GRAPPLE_CABLE:
+ CL_ParseBeam2 (cl_mod_grapple_cable); /* toss result */
+ break;
+
+ // RAFAEL
+ case TE_WELDING_SPARKS:
+ cnt = MSG_ReadByte (&net_message);
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ color = MSG_ReadByte (&net_message);
+ CL_ParticleEffect2 (pos, dir, color, cnt);
+
+ ex = CL_AllocExplosion ();
+ VectorCopy (pos, ex->ent.origin);
+ ex->type = ex_flash;
+ // note to self
+ // we need a better no draw flag
+ ex->ent.flags = RF_BEAM;
+ ex->start = cl.frame.servertime - 0.1;
+ ex->light = 100 + (rand()%75);
+ ex->lightcolor[0] = 1.0;
+ ex->lightcolor[1] = 1.0;
+ ex->lightcolor[2] = 0.3;
+ ex->ent.model = cl_mod_flash;
+ ex->frames = 2;
+ break;
+
+ case TE_GREENBLOOD:
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ CL_ParticleEffect2 (pos, dir, 0xdf, 30);
+ break;
+
+ // RAFAEL
+ case TE_TUNNEL_SPARKS:
+ cnt = MSG_ReadByte (&net_message);
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ color = MSG_ReadByte (&net_message);
+ CL_ParticleEffect3 (pos, dir, color, cnt);
+ break;
+
+//=============
+//PGM
+ // PMM -following code integrated for flechette (different color)
+ case TE_BLASTER2: // green blaster hitting wall
+ case TE_FLECHETTE: // flechette
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+
+ // PMM
+ if (type == TE_BLASTER2)
+ CL_BlasterParticles2 (pos, dir, 0xd0);
+ else
+ CL_BlasterParticles2 (pos, dir, 0x6f); // 75
+
+ ex = CL_AllocExplosion ();
+ VectorCopy (pos, ex->ent.origin);
+ ex->ent.angles[0] = acos(dir[2])/M_PI*180;
+ // PMM - fixed to correct for pitch of 0
+ if (dir[0])
+ ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
+ else if (dir[1] > 0)
+ ex->ent.angles[1] = 90;
+ else if (dir[1] < 0)
+ ex->ent.angles[1] = 270;
+ else
+ ex->ent.angles[1] = 0;
+
+ ex->type = ex_misc;
+ ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
+
+ // PMM
+ if (type == TE_BLASTER2)
+ ex->ent.skinnum = 1;
+ else // flechette
+ ex->ent.skinnum = 2;
+
+ ex->start = cl.frame.servertime - 100;
+ ex->light = 150;
+ // PMM
+ if (type == TE_BLASTER2)
+ ex->lightcolor[1] = 1;
+ else // flechette
+ {
+ ex->lightcolor[0] = 0.19;
+ ex->lightcolor[1] = 0.41;
+ ex->lightcolor[2] = 0.75;
+ }
+ ex->ent.model = cl_mod_explode;
+ ex->frames = 4;
+ S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ break;
+
+
+ case TE_LIGHTNING:
+ ent = CL_ParseLightning (cl_mod_lightning);
+ S_StartSound (NULL, ent, CHAN_WEAPON, cl_sfx_lightning, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_DEBUGTRAIL:
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadPos (&net_message, pos2);
+ CL_DebugTrail (pos, pos2);
+ break;
+
+ case TE_PLAIN_EXPLOSION:
+ MSG_ReadPos (&net_message, pos);
+
+ ex = CL_AllocExplosion ();
+ VectorCopy (pos, ex->ent.origin);
+ ex->type = ex_poly;
+ ex->ent.flags = RF_FULLBRIGHT;
+ ex->start = cl.frame.servertime - 100;
+ ex->light = 350;
+ ex->lightcolor[0] = 1.0;
+ ex->lightcolor[1] = 0.5;
+ ex->lightcolor[2] = 0.5;
+ ex->ent.angles[1] = rand() % 360;
+ ex->ent.model = cl_mod_explo4;
+ if (qfrand() < 0.5)
+ ex->baseframe = 15;
+ ex->frames = 15;
+ if (type == TE_ROCKET_EXPLOSION_WATER)
+ S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
+ else
+ S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_FLASHLIGHT:
+ MSG_ReadPos(&net_message, pos);
+ ent = MSG_ReadShort(&net_message);
+ CL_Flashlight(ent, pos);
+ break;
+
+ case TE_FORCEWALL:
+ MSG_ReadPos(&net_message, pos);
+ MSG_ReadPos(&net_message, pos2);
+ color = MSG_ReadByte (&net_message);
+ CL_ForceWall(pos, pos2, color);
+ break;
+
+ case TE_HEATBEAM:
+ CL_ParsePlayerBeam (cl_mod_heatbeam); /* toss result */
+ break;
+
+ case TE_MONSTER_HEATBEAM:
+ CL_ParsePlayerBeam (cl_mod_monster_heatbeam); /* toss result */
+ break;
+
+ case TE_HEATBEAM_SPARKS:
+// cnt = MSG_ReadByte (&net_message);
+ cnt = 50;
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+// r = MSG_ReadByte (&net_message);
+// magnitude = MSG_ReadShort (&net_message);
+ r = 8;
+ magnitude = 60;
+ color = r & 0xff;
+ CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
+ S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_HEATBEAM_STEAM:
+// cnt = MSG_ReadByte (&net_message);
+ cnt = 20;
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+// r = MSG_ReadByte (&net_message);
+// magnitude = MSG_ReadShort (&net_message);
+// color = r & 0xff;
+ color = 0xe0;
+ magnitude = 60;
+ CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
+ S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_STEAM:
+ CL_ParseSteam();
+ break;
+
+ case TE_BUBBLETRAIL2:
+// cnt = MSG_ReadByte (&net_message);
+ cnt = 8;
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadPos (&net_message, pos2);
+ CL_BubbleTrail2 (pos, pos2, cnt);
+ S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_MOREBLOOD:
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+ CL_ParticleEffect (pos, dir, 0xe8, 250);
+ break;
+
+ case TE_CHAINFIST_SMOKE:
+ dir[0]=0; dir[1]=0; dir[2]=1;
+ MSG_ReadPos(&net_message, pos);
+ CL_ParticleSmokeEffect (pos, dir, 0, 20, 20);
+ break;
+
+ case TE_ELECTRIC_SPARKS:
+ MSG_ReadPos (&net_message, pos);
+ MSG_ReadDir (&net_message, dir);
+// CL_ParticleEffect (pos, dir, 109, 40);
+ CL_ParticleEffect (pos, dir, 0x75, 40);
+ //FIXME : replace or remove this sound
+ S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_TRACKER_EXPLOSION:
+ MSG_ReadPos (&net_message, pos);
+ CL_ColorFlash (pos, 0, 150, -1, -1, -1);
+ CL_ColorExplosionParticles (pos, 0, 1);
+// CL_Tracker_Explode (pos);
+ S_StartSound (pos, 0, 0, cl_sfx_disrexp, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_TELEPORT_EFFECT:
+ case TE_DBALL_GOAL:
+ MSG_ReadPos (&net_message, pos);
+ CL_TeleportParticles (pos);
+ break;
+
+ case TE_WIDOWBEAMOUT:
+ CL_ParseWidow ();
+ break;
+
+ case TE_NUKEBLAST:
+ CL_ParseNuke ();
+ break;
+
+ case TE_WIDOWSPLASH:
+ MSG_ReadPos (&net_message, pos);
+ CL_WidowSplash (pos);
+ break;
+//PGM
+//==============
+
+ default:
+ Com_Error (ERR_DROP, "CL_ParseTEnt: bad type");
+ }
+}
+
+/*
+=================
+CL_AddBeams
+=================
+*/
+void CL_AddBeams (void)
+{
+ int i,j;
+ beam_t *b;
+ vec3_t dist, org;
+ float d;
+ entity_t ent;
+ float yaw, pitch;
+ float forward;
+ float len, steps;
+ float model_length;
+
+// update beams
+ for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
+ {
+ if (!b->model || b->endtime < cl.time)
+ continue;
+
+ // if coming from the player, update the start position
+ if (b->entity == cl.playernum+1) // entity 0 is the world
+ {
+ VectorCopy (cl.refdef.vieworg, b->start);
+ b->start[2] -= 22; // adjust for view height
+ }
+ VectorAdd (b->start, b->offset, org);
+
+ // calculate pitch and yaw
+ VectorSubtract (b->end, org, dist);
+
+ if (dist[1] == 0 && dist[0] == 0)
+ {
+ yaw = 0;
+ if (dist[2] > 0)
+ pitch = 90;
+ else
+ pitch = 270;
+ }
+ else
+ {
+ // PMM - fixed to correct for pitch of 0
+ if (dist[0])
+ yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
+ else if (dist[1] > 0)
+ yaw = 90;
+ else
+ yaw = 270;
+ if (yaw < 0)
+ yaw += 360;
+
+ forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
+ pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
+ if (pitch < 0)
+ pitch += 360.0;
+ }
+
+ // add new entities for the beams
+ d = VectorNormalize(dist);
+
+ memset (&ent, 0, sizeof(ent));
+ if (b->model == cl_mod_lightning)
+ {
+ model_length = 35.0;
+ d-= 20.0; // correction so it doesn't end in middle of tesla
+ }
+ else
+ {
+ model_length = 30.0;
+ }
+ steps = ceil(d/model_length);
+ len = (d-model_length)/(steps-1);
+
+ // PMM - special case for lightning model .. if the real length is shorter than the model,
+ // flip it around & draw it from the end to the start. This prevents the model from going
+ // through the tesla mine (instead it goes through the target)
+ if ((b->model == cl_mod_lightning) && (d <= model_length))
+ {
+// Com_Printf ("special case\n");
+ VectorCopy (b->end, ent.origin);
+ // offset to push beam outside of tesla model (negative because dist is from end to start
+ // for this beam)
+// for (j=0 ; j<3 ; j++)
+// ent.origin[j] -= dist[j]*10.0;
+ ent.model = b->model;
+ ent.flags = RF_FULLBRIGHT;
+ ent.angles[0] = pitch;
+ ent.angles[1] = yaw;
+ ent.angles[2] = rand()%360;
+ V_AddEntity (&ent);
+ return;
+ }
+ while (d > 0)
+ {
+ VectorCopy (org, ent.origin);
+ ent.model = b->model;
+ if (b->model == cl_mod_lightning)
+ {
+ ent.flags = RF_FULLBRIGHT;
+ ent.angles[0] = -pitch;
+ ent.angles[1] = yaw + 180.0;
+ ent.angles[2] = rand()%360;
+ }
+ else
+ {
+ ent.angles[0] = pitch;
+ ent.angles[1] = yaw;
+ ent.angles[2] = rand()%360;
+ }
+
+// Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity);
+ V_AddEntity (&ent);
+
+ for (j=0 ; j<3 ; j++)
+ org[j] += dist[j]*len;
+ d -= model_length;
+ }
+ }
+}
+
+
+/*
+// Com_Printf ("Endpoint: %f %f %f\n", b->end[0], b->end[1], b->end[2]);
+// Com_Printf ("Pred View Angles: %f %f %f\n", cl.predicted_angles[0], cl.predicted_angles[1], cl.predicted_angles[2]);
+// Com_Printf ("Act View Angles: %f %f %f\n", cl.refdef.viewangles[0], cl.refdef.viewangles[1], cl.refdef.viewangles[2]);
+// VectorCopy (cl.predicted_origin, b->start);
+// b->start[2] += 22; // adjust for view height
+// if (fabs(cl.refdef.vieworg[2] - b->start[2]) >= 10) {
+// b->start[2] = cl.refdef.vieworg[2];
+// }
+
+// Com_Printf ("Time: %d %d %f\n", cl.time, cls.realtime, cls.frametime);
+*/
+
+extern cvar_t *hand;
+
+/*
+=================
+ROGUE - draw player locked beams
+CL_AddPlayerBeams
+=================
+*/
+void CL_AddPlayerBeams (void)
+{
+ int i,j;
+ beam_t *b;
+ vec3_t dist, org;
+ float d;
+ entity_t ent;
+ float yaw, pitch;
+ float forward;
+ float len, steps;
+ int framenum = 0;
+ float model_length;
+
+ float hand_multiplier;
+ frame_t *oldframe;
+ player_state_t *ps, *ops;
+
+//PMM
+ if (hand)
+ {
+ if (hand->value == 2)
+ hand_multiplier = 0;
+ else if (hand->value == 1)
+ hand_multiplier = -1;
+ else
+ hand_multiplier = 1;
+ }
+ else
+ {
+ hand_multiplier = 1;
+ }
+//PMM
+
+// update beams
+ for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
+ {
+ vec3_t f,r,u;
+ if (!b->model || b->endtime < cl.time)
+ continue;
+
+ if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
+ {
+
+ // if coming from the player, update the start position
+ if (b->entity == cl.playernum+1) // entity 0 is the world
+ {
+ // set up gun position
+ // code straight out of CL_AddViewWeapon
+ ps = &cl.frame.playerstate;
+ j = (cl.frame.serverframe - 1) & UPDATE_MASK;
+ oldframe = &cl.frames[j];
+ if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid)
+ oldframe = &cl.frame; // previous frame was dropped or involid
+ ops = &oldframe->playerstate;
+ for (j=0 ; j<3 ; j++)
+ {
+ b->start[j] = cl.refdef.vieworg[j] + ops->gunoffset[j]
+ + cl.lerpfrac * (ps->gunoffset[j] - ops->gunoffset[j]);
+ }
+ VectorMA (b->start, (hand_multiplier * b->offset[0]), cl.v_right, org);
+ VectorMA ( org, b->offset[1], cl.v_forward, org);
+ VectorMA ( org, b->offset[2], cl.v_up, org);
+ if ((hand) && (hand->value == 2)) {
+ VectorMA (org, -1, cl.v_up, org);
+ }
+ // FIXME - take these out when final
+ VectorCopy (cl.v_right, r);
+ VectorCopy (cl.v_forward, f);
+ VectorCopy (cl.v_up, u);
+
+ }
+ else
+ VectorCopy (b->start, org);
+ }
+ else
+ {
+ // if coming from the player, update the start position
+ if (b->entity == cl.playernum+1) // entity 0 is the world
+ {
+ VectorCopy (cl.refdef.vieworg, b->start);
+ b->start[2] -= 22; // adjust for view height
+ }
+ VectorAdd (b->start, b->offset, org);
+ }
+
+ // calculate pitch and yaw
+ VectorSubtract (b->end, org, dist);
+
+//PMM
+ if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.playernum+1))
+ {
+ vec_t len;
+
+ len = VectorLength (dist);
+ VectorScale (f, len, dist);
+ VectorMA (dist, (hand_multiplier * b->offset[0]), r, dist);
+ VectorMA (dist, b->offset[1], f, dist);
+ VectorMA (dist, b->offset[2], u, dist);
+ if ((hand) && (hand->value == 2)) {
+ VectorMA (org, -1, cl.v_up, org);
+ }
+ }
+//PMM
+
+ if (dist[1] == 0 && dist[0] == 0)
+ {
+ yaw = 0;
+ if (dist[2] > 0)
+ pitch = 90;
+ else
+ pitch = 270;
+ }
+ else
+ {
+ // PMM - fixed to correct for pitch of 0
+ if (dist[0])
+ yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
+ else if (dist[1] > 0)
+ yaw = 90;
+ else
+ yaw = 270;
+ if (yaw < 0)
+ yaw += 360;
+
+ forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
+ pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
+ if (pitch < 0)
+ pitch += 360.0;
+ }
+
+ if (cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
+ {
+ if (b->entity != cl.playernum+1)
+ {
+ framenum = 2;
+// Com_Printf ("Third person\n");
+ ent.angles[0] = -pitch;
+ ent.angles[1] = yaw + 180.0;
+ ent.angles[2] = 0;
+// Com_Printf ("%f %f - %f %f %f\n", -pitch, yaw+180.0, b->offset[0], b->offset[1], b->offset[2]);
+ AngleVectors(ent.angles, f, r, u);
+
+ // if it's a non-origin offset, it's a player, so use the hardcoded player offset
+ if (!VectorCompare (b->offset, vec3_origin))
+ {
+ VectorMA (org, -(b->offset[0])+1, r, org);
+ VectorMA (org, -(b->offset[1]), f, org);
+ VectorMA (org, -(b->offset[2])-10, u, org);
+ }
+ else
+ {
+ // if it's a monster, do the particle effect
+ CL_MonsterPlasma_Shell(b->start);
+ }
+ }
+ else
+ {
+ framenum = 1;
+ }
+ }
+
+ // if it's the heatbeam, draw the particle effect
+ if ((cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.playernum+1)))
+ {
+ CL_Heatbeam (org, dist);
+ }
+
+ // add new entities for the beams
+ d = VectorNormalize(dist);
+
+ memset (&ent, 0, sizeof(ent));
+ if (b->model == cl_mod_heatbeam)
+ {
+ model_length = 32.0;
+ }
+ else if (b->model == cl_mod_lightning)
+ {
+ model_length = 35.0;
+ d-= 20.0; // correction so it doesn't end in middle of tesla
+ }
+ else
+ {
+ model_length = 30.0;
+ }
+ steps = ceil(d/model_length);
+ len = (d-model_length)/(steps-1);
+
+ // PMM - special case for lightning model .. if the real length is shorter than the model,
+ // flip it around & draw it from the end to the start. This prevents the model from going
+ // through the tesla mine (instead it goes through the target)
+ if ((b->model == cl_mod_lightning) && (d <= model_length))
+ {
+// Com_Printf ("special case\n");
+ VectorCopy (b->end, ent.origin);
+ // offset to push beam outside of tesla model (negative because dist is from end to start
+ // for this beam)
+// for (j=0 ; j<3 ; j++)
+// ent.origin[j] -= dist[j]*10.0;
+ ent.model = b->model;
+ ent.flags = RF_FULLBRIGHT;
+ ent.angles[0] = pitch;
+ ent.angles[1] = yaw;
+ ent.angles[2] = rand()%360;
+ V_AddEntity (&ent);
+ return;
+ }
+ while (d > 0)
+ {
+ VectorCopy (org, ent.origin);
+ ent.model = b->model;
+ if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
+ {
+// ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
+// ent.alpha = 0.3;
+ ent.flags = RF_FULLBRIGHT;
+ ent.angles[0] = -pitch;
+ ent.angles[1] = yaw + 180.0;
+ ent.angles[2] = (cl.time) % 360;
+// ent.angles[2] = rand()%360;
+ ent.frame = framenum;
+ }
+ else if (b->model == cl_mod_lightning)
+ {
+ ent.flags = RF_FULLBRIGHT;
+ ent.angles[0] = -pitch;
+ ent.angles[1] = yaw + 180.0;
+ ent.angles[2] = rand()%360;
+ }
+ else
+ {
+ ent.angles[0] = pitch;
+ ent.angles[1] = yaw;
+ ent.angles[2] = rand()%360;
+ }
+
+// Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity);
+ V_AddEntity (&ent);
+
+ for (j=0 ; j<3 ; j++)
+ org[j] += dist[j]*len;
+ d -= model_length;
+ }
+ }
+}
+
+/*
+=================
+CL_AddExplosions
+=================
+*/
+void CL_AddExplosions (void)
+{
+ entity_t *ent;
+ int i;
+ explosion_t *ex;
+ float frac;
+ int f;
+
+ memset (&ent, 0, sizeof(ent));
+
+ for (i=0, ex=cl_explosions ; i< MAX_EXPLOSIONS ; i++, ex++)
+ {
+ if (ex->type == ex_free)
+ continue;
+ frac = (cl.time - ex->start)/100.0;
+ f = floor(frac);
+
+ ent = &ex->ent;
+
+ switch (ex->type)
+ {
+ case ex_mflash:
+ if (f >= ex->frames-1)
+ ex->type = ex_free;
+ break;
+ case ex_misc:
+ if (f >= ex->frames-1)
+ {
+ ex->type = ex_free;
+ break;
+ }
+ ent->alpha = 1.0 - frac/(ex->frames-1);
+ break;
+ case ex_flash:
+ if (f >= 1)
+ {
+ ex->type = ex_free;
+ break;
+ }
+ ent->alpha = 1.0;
+ break;
+ case ex_poly:
+ if (f >= ex->frames-1)
+ {
+ ex->type = ex_free;
+ break;
+ }
+
+ ent->alpha = (16.0 - (float)f)/16.0;
+
+ if (f < 10)
+ {
+ ent->skinnum = (f>>1);
+ if (ent->skinnum < 0)
+ ent->skinnum = 0;
+ }
+ else
+ {
+ ent->flags |= RF_TRANSLUCENT;
+ if (f < 13)
+ ent->skinnum = 5;
+ else
+ ent->skinnum = 6;
+ }
+ break;
+ case ex_poly2:
+ if (f >= ex->frames-1)
+ {
+ ex->type = ex_free;
+ break;
+ }
+
+ ent->alpha = (5.0 - (float)f)/5.0;
+ ent->skinnum = 0;
+ ent->flags |= RF_TRANSLUCENT;
+ break;
+ }
+
+ if (ex->type == ex_free)
+ continue;
+ if (ex->light)
+ {
+ V_AddLight (ent->origin, ex->light*ent->alpha,
+ ex->lightcolor[0], ex->lightcolor[1], ex->lightcolor[2]);
+ }
+
+ VectorCopy (ent->origin, ent->oldorigin);
+
+ if (f < 0)
+ f = 0;
+ ent->frame = ex->baseframe + f + 1;
+ ent->oldframe = ex->baseframe + f;
+ ent->backlerp = 1.0 - cl.lerpfrac;
+
+ V_AddEntity (ent);
+ }
+}
+
+
+/*
+=================
+CL_AddLasers
+=================
+*/
+void CL_AddLasers (void)
+{
+ laser_t *l;
+ int i;
+
+ for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
+ {
+ if (l->endtime >= cl.time)
+ V_AddEntity (&l->ent);
+ }
+}
+
+/* PMM - CL_Sustains */
+void CL_ProcessSustain (void)
+{
+ cl_sustain_t *s;
+ int i;
+
+ for (i=0, s=cl_sustains; i< MAX_SUSTAINS; i++, s++)
+ {
+ if (s->id)
+ if ((s->endtime >= cl.time) && (cl.time >= s->nextthink))
+ {
+// Com_Printf ("think %d %d %d\n", cl.time, s->nextthink, s->thinkinterval);
+ s->think (s);
+ }
+ else if (s->endtime < cl.time)
+ s->id = 0;
+ }
+}
+
+/*
+=================
+CL_AddTEnts
+=================
+*/
+void CL_AddTEnts (void)
+{
+ CL_AddBeams ();
+ // PMM - draw plasma beams
+ CL_AddPlayerBeams ();
+ CL_AddExplosions ();
+ CL_AddLasers ();
+ // PMM - set up sustain
+ CL_ProcessSustain();
+}
--- /dev/null
+++ b/cl_view.c
@@ -1,0 +1,569 @@
+// cl_view.c -- player rendering positioning
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+//=============
+//
+// development tools for weapons
+//
+int gun_frame;
+model_t *gun_model;
+
+//=============
+
+cvar_t *crosshair;
+cvar_t *cl_testparticles;
+cvar_t *cl_testentities;
+cvar_t *cl_testlights;
+cvar_t *cl_testblend;
+
+cvar_t *cl_stats;
+
+
+int r_numdlights;
+dlight_t r_dlights[MAX_DLIGHTS];
+
+int r_numentities;
+entity_t r_entities[MAX_ENTITIES];
+
+int r_numparticles;
+particle_t r_particles[MAX_PARTICLES];
+
+lightstyle_t r_lightstyles[MAX_LIGHTSTYLES];
+
+char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
+int num_cl_weaponmodels;
+
+/*
+====================
+V_ClearScene
+
+Specifies the model that will be used as the world
+====================
+*/
+void V_ClearScene (void)
+{
+ r_numdlights = 0;
+ r_numentities = 0;
+ r_numparticles = 0;
+}
+
+
+/*
+=====================
+V_AddEntity
+
+=====================
+*/
+void V_AddEntity (entity_t *ent)
+{
+ if (r_numentities >= MAX_ENTITIES)
+ return;
+ r_entities[r_numentities++] = *ent;
+}
+
+
+/*
+=====================
+V_AddParticle
+
+=====================
+*/
+void V_AddParticle (vec3_t org, int color, float alpha)
+{
+ particle_t *p;
+
+ if (r_numparticles >= MAX_PARTICLES)
+ return;
+ p = &r_particles[r_numparticles++];
+ VectorCopy (org, p->origin);
+ p->color = color;
+ p->alpha = alpha;
+}
+
+/*
+=====================
+V_AddLight
+
+=====================
+*/
+void V_AddLight (vec3_t org, float intensity, float r, float g, float b)
+{
+ dlight_t *dl;
+
+ if (r_numdlights >= MAX_DLIGHTS)
+ return;
+ dl = &r_dlights[r_numdlights++];
+ VectorCopy (org, dl->origin);
+ dl->intensity = intensity;
+ dl->color[0] = r;
+ dl->color[1] = g;
+ dl->color[2] = b;
+}
+
+
+/*
+=====================
+V_AddLightStyle
+
+=====================
+*/
+void V_AddLightStyle (int style, float r, float g, float b)
+{
+ lightstyle_t *ls;
+
+ if (style < 0 || style > MAX_LIGHTSTYLES)
+ Com_Error (ERR_DROP, "Bad light style %i", style);
+ ls = &r_lightstyles[style];
+
+ ls->white = r+g+b;
+ ls->rgb[0] = r;
+ ls->rgb[1] = g;
+ ls->rgb[2] = b;
+}
+
+/*
+================
+V_TestParticles
+
+If cl_testparticles is set, create 4096 particles in the view
+================
+*/
+void V_TestParticles (void)
+{
+ particle_t *p;
+ int i, j;
+ float d, r, u;
+
+ r_numparticles = MAX_PARTICLES;
+ for (i=0 ; i<r_numparticles ; i++)
+ {
+ d = i*0.25;
+ r = 4*((i&7)-3.5);
+ u = 4*(((i>>3)&7)-3.5);
+ p = &r_particles[i];
+
+ for (j=0 ; j<3 ; j++)
+ p->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*d +
+ cl.v_right[j]*r + cl.v_up[j]*u;
+
+ p->color = 8;
+ p->alpha = cl_testparticles->value;
+ }
+}
+
+/*
+================
+V_TestEntities
+
+If cl_testentities is set, create 32 player models
+================
+*/
+void V_TestEntities (void)
+{
+ int i, j;
+ float f, r;
+ entity_t *ent;
+
+ r_numentities = 32;
+ memset (r_entities, 0, sizeof(r_entities));
+
+ for (i=0 ; i<r_numentities ; i++)
+ {
+ ent = &r_entities[i];
+
+ r = 64 * ( (i%4) - 1.5 );
+ f = 64 * (i/4) + 128;
+
+ for (j=0 ; j<3 ; j++)
+ ent->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
+ cl.v_right[j]*r;
+
+ ent->model = cl.baseclientinfo.model;
+ ent->skin = cl.baseclientinfo.skin;
+ }
+}
+
+/*
+================
+V_TestLights
+
+If cl_testlights is set, create 32 lights models
+================
+*/
+void V_TestLights (void)
+{
+ int i, j;
+ float f, r;
+ dlight_t *dl;
+
+ r_numdlights = 32;
+ memset (r_dlights, 0, sizeof(r_dlights));
+
+ for (i=0 ; i<r_numdlights ; i++)
+ {
+ dl = &r_dlights[i];
+
+ r = 64 * ( (i%4) - 1.5 );
+ f = 64 * (i/4) + 128;
+
+ for (j=0 ; j<3 ; j++)
+ dl->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
+ cl.v_right[j]*r;
+ dl->color[0] = ((i%6)+1) & 1;
+ dl->color[1] = (((i%6)+1) & 2)>>1;
+ dl->color[2] = (((i%6)+1) & 4)>>2;
+ dl->intensity = 200;
+ }
+}
+
+//===================================================================
+
+/*
+=================
+CL_PrepRefresh
+
+Call before entering a new level, or after changing dlls
+=================
+*/
+void CL_PrepRefresh (void)
+{
+ char mapname[32];
+ int i;
+ char name[MAX_QPATH];
+ float rotate;
+ vec3_t axis;
+
+ if (!cl.configstrings[CS_MODELS+1][0])
+ return; // no map loaded
+
+ SCR_AddDirtyPoint (0, 0);
+ SCR_AddDirtyPoint (vid.width-1, vid.height-1);
+
+ // let the render dll load the map
+ strcpy (mapname, cl.configstrings[CS_MODELS+1] + 5); // skip "maps/"
+ mapname[strlen(mapname)-4] = 0; // cut off ".bsp"
+
+ // register models, pics, and skins
+ Com_Printf ("Map: %s\r", mapname);
+ SCR_UpdateScreen ();
+ re.BeginRegistration (mapname);
+ Com_Printf (" \r");
+
+ // precache status bar pics
+ Com_Printf ("pics\r");
+ SCR_UpdateScreen ();
+ SCR_TouchPics ();
+ Com_Printf (" \r");
+
+ CL_RegisterTEntModels ();
+
+ num_cl_weaponmodels = 1;
+ strcpy(cl_weaponmodels[0], "weapon.md2");
+
+ for (i=1 ; i<MAX_MODELS && cl.configstrings[CS_MODELS+i][0] ; i++)
+ {
+ strcpy (name, cl.configstrings[CS_MODELS+i]);
+ name[37] = 0; // never go beyond one line
+ if (name[0] != '*')
+ Com_Printf ("%s\r", name);
+ SCR_UpdateScreen ();
+ Sys_SendKeyEvents (); // pump message loop
+ if (name[0] == '#')
+ {
+ // special player weapon model
+ if (num_cl_weaponmodels < MAX_CLIENTWEAPONMODELS)
+ {
+ strncpy(cl_weaponmodels[num_cl_weaponmodels], cl.configstrings[CS_MODELS+i]+1,
+ sizeof(cl_weaponmodels[num_cl_weaponmodels]) - 1);
+ num_cl_weaponmodels++;
+ }
+ }
+ else
+ {
+ cl.model_draw[i] = re.RegisterModel (cl.configstrings[CS_MODELS+i]);
+ if (name[0] == '*')
+ cl.model_clip[i] = CM_InlineModel (cl.configstrings[CS_MODELS+i]);
+ else
+ cl.model_clip[i] = NULL;
+ }
+ if (name[0] != '*')
+ Com_Printf (" \r");
+ }
+
+ Com_Printf ("images\r", i);
+ SCR_UpdateScreen ();
+ for (i=1 ; i<MAX_IMAGES && cl.configstrings[CS_IMAGES+i][0] ; i++)
+ {
+ cl.image_precache[i] = re.RegisterPic (cl.configstrings[CS_IMAGES+i]);
+ Sys_SendKeyEvents (); // pump message loop
+ }
+
+ Com_Printf (" \r");
+ for (i=0 ; i<MAX_CLIENTS ; i++)
+ {
+ if (!cl.configstrings[CS_PLAYERSKINS+i][0])
+ continue;
+ Com_Printf ("client %i\r", i);
+ SCR_UpdateScreen ();
+ Sys_SendKeyEvents (); // pump message loop
+ CL_ParseClientinfo (i);
+ Com_Printf (" \r");
+ }
+
+ CL_LoadClientinfo (&cl.baseclientinfo, "unnamed\\male/grunt");
+
+ // set sky textures and speed
+ Com_Printf ("sky\r", i);
+ SCR_UpdateScreen ();
+ rotate = atof (cl.configstrings[CS_SKYROTATE]);
+ sscanf (cl.configstrings[CS_SKYAXIS], "%f %f %f",
+ &axis[0], &axis[1], &axis[2]);
+ re.SetSky (cl.configstrings[CS_SKY], rotate, axis);
+ Com_Printf (" \r");
+
+ // the renderer can now free unneeded stuff
+ re.EndRegistration ();
+
+ // clear any lines of console text
+ Con_ClearNotify ();
+
+ SCR_UpdateScreen ();
+ cl.refresh_prepped = true;
+ cl.force_refdef = true; // make sure we have a valid refdef
+
+ // start the cd track
+ CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
+}
+
+/*
+====================
+CalcFov
+====================
+*/
+float CalcFov (float fov_x, float width, float height)
+{
+ float a;
+ float x;
+
+ if (fov_x < 1 || fov_x > 179)
+ Com_Error (ERR_DROP, "Bad fov: %f", fov_x);
+
+ x = width/tan(fov_x/360*M_PI);
+
+ a = atan (height/x);
+
+ a = a*360/M_PI;
+
+ return a;
+}
+
+//============================================================================
+
+// gun frame debugging functions
+void V_Gun_Next_f (void)
+{
+ gun_frame++;
+ Com_Printf ("frame %i\n", gun_frame);
+}
+
+void V_Gun_Prev_f (void)
+{
+ gun_frame--;
+ if (gun_frame < 0)
+ gun_frame = 0;
+ Com_Printf ("frame %i\n", gun_frame);
+}
+
+void V_Gun_Model_f (void)
+{
+ char name[MAX_QPATH];
+
+ if (Cmd_Argc() != 2)
+ {
+ gun_model = NULL;
+ return;
+ }
+ Com_sprintf (name, sizeof(name), "models/%s/tris.md2", Cmd_Argv(1));
+ gun_model = re.RegisterModel (name);
+}
+
+//============================================================================
+
+
+/*
+=================
+SCR_DrawCrosshair
+=================
+*/
+void SCR_DrawCrosshair (void)
+{
+ if (!crosshair->value)
+ return;
+
+ if (crosshair->modified)
+ {
+ crosshair->modified = false;
+ SCR_TouchPics ();
+ }
+
+ if (!crosshair_pic[0])
+ return;
+
+ re.DrawPic (scr_vrect.x + ((scr_vrect.width - crosshair_width)>>1)
+ , scr_vrect.y + ((scr_vrect.height - crosshair_height)>>1), crosshair_pic);
+}
+
+/*
+==================
+V_RenderView
+
+==================
+*/
+void V_RenderView( float stereo_separation )
+{
+ extern int entitycmpfnc(entity_t *, entity_t *);
+
+ if (cls.state != ca_active)
+ return;
+
+ if (!cl.refresh_prepped)
+ return; // still loading
+
+ if (cl_timedemo->value)
+ {
+ if (!cl.timedemo_start)
+ cl.timedemo_start = Sys_Milliseconds ();
+ cl.timedemo_frames++;
+ }
+
+ // an invalid frame will just use the exact previous refdef
+ // we can't use the old frame if the video mode has changed, though...
+ if ( cl.frame.valid && (cl.force_refdef || !cl_paused->value) )
+ {
+ cl.force_refdef = false;
+
+ V_ClearScene ();
+
+ // build a refresh entity list and calc cl.sim*
+ // this also calls CL_CalcViewValues which loads
+ // v_forward, etc.
+ CL_AddEntities ();
+
+ if (cl_testparticles->value)
+ V_TestParticles ();
+ if (cl_testentities->value)
+ V_TestEntities ();
+ if (cl_testlights->value)
+ V_TestLights ();
+ if (cl_testblend->value)
+ {
+ cl.refdef.blend[0] = 1;
+ cl.refdef.blend[1] = 0.5;
+ cl.refdef.blend[2] = 0.25;
+ cl.refdef.blend[3] = 0.5;
+ }
+
+ // offset vieworg appropriately if we're doing stereo separation
+ if ( stereo_separation != 0 )
+ {
+ vec3_t tmp;
+
+ VectorScale( cl.v_right, stereo_separation, tmp );
+ VectorAdd( cl.refdef.vieworg, tmp, cl.refdef.vieworg );
+ }
+
+ // never let it sit exactly on a node line, because a water plane can
+ // dissapear when viewed with the eye exactly on it.
+ // the server protocol only specifies to 1/8 pixel, so add 1/16 in each axis
+ cl.refdef.vieworg[0] += 1.0/16;
+ cl.refdef.vieworg[1] += 1.0/16;
+ cl.refdef.vieworg[2] += 1.0/16;
+
+ cl.refdef.x = scr_vrect.x;
+ cl.refdef.y = scr_vrect.y;
+ cl.refdef.width = scr_vrect.width;
+ cl.refdef.height = scr_vrect.height;
+ cl.refdef.fov_y = CalcFov (cl.refdef.fov_x, cl.refdef.width, cl.refdef.height);
+ cl.refdef.time = cl.time*0.001;
+
+ cl.refdef.areabits = cl.frame.areabits;
+
+ if (!cl_add_entities->value)
+ r_numentities = 0;
+ if (!cl_add_particles->value)
+ r_numparticles = 0;
+ if (!cl_add_lights->value)
+ r_numdlights = 0;
+ if (!cl_add_blend->value)
+ {
+ VectorClear (cl.refdef.blend);
+ }
+
+ cl.refdef.num_entities = r_numentities;
+ cl.refdef.entities = r_entities;
+ cl.refdef.num_particles = r_numparticles;
+ cl.refdef.particles = r_particles;
+ cl.refdef.num_dlights = r_numdlights;
+ cl.refdef.dlights = r_dlights;
+ cl.refdef.lightstyles = r_lightstyles;
+
+ cl.refdef.rdflags = cl.frame.playerstate.rdflags;
+
+ // sort entities for better cache locality
+ qsort( cl.refdef.entities, cl.refdef.num_entities, sizeof( cl.refdef.entities[0] ), (int (*)(void *, void *))entitycmpfnc );
+ }
+
+ re.RenderFrame (&cl.refdef);
+ if (cl_stats->value)
+ Com_Printf ("ent:%i lt:%i part:%i\n", r_numentities, r_numdlights, r_numparticles);
+ if ( log_stats->value && ( log_stats_file != 0 ) )
+ fprintf( log_stats_file, "%i,%i,%i,",r_numentities, r_numdlights, r_numparticles);
+
+
+ SCR_AddDirtyPoint (scr_vrect.x, scr_vrect.y);
+ SCR_AddDirtyPoint (scr_vrect.x+scr_vrect.width-1,
+ scr_vrect.y+scr_vrect.height-1);
+
+ SCR_DrawCrosshair ();
+}
+
+
+/*
+=============
+V_Viewpos_f
+=============
+*/
+void V_Viewpos_f (void)
+{
+ Com_Printf ("(%i %i %i) : %i\n", (int)cl.refdef.vieworg[0],
+ (int)cl.refdef.vieworg[1], (int)cl.refdef.vieworg[2],
+ (int)cl.refdef.viewangles[YAW]);
+}
+
+/*
+=============
+V_Init
+=============
+*/
+void V_Init (void)
+{
+ Cmd_AddCommand ("gun_next", V_Gun_Next_f);
+ Cmd_AddCommand ("gun_prev", V_Gun_Prev_f);
+ Cmd_AddCommand ("gun_model", V_Gun_Model_f);
+
+ Cmd_AddCommand ("viewpos", V_Viewpos_f);
+
+ crosshair = Cvar_Get ("crosshair", "0", CVAR_ARCHIVE);
+
+ cl_testblend = Cvar_Get ("cl_testblend", "0", 0);
+ cl_testparticles = Cvar_Get ("cl_testparticles", "0", 0);
+ cl_testentities = Cvar_Get ("cl_testentities", "0", 0);
+ cl_testlights = Cvar_Get ("cl_testlights", "0", 0);
+
+ cl_stats = Cvar_Get ("cl_stats", "0", 0);
+}
--- a/client/cdaudio.h
+++ /dev/null
@@ -1,6 +1,0 @@
-int CDAudio_Init(void);
-void CDAudio_Shutdown(void);
-void CDAudio_Play(int track, qboolean looping);
-void CDAudio_Stop(void);
-void CDAudio_Update(void);
-void CDAudio_Activate (qboolean active);
--- a/client/cl_cin.c
+++ /dev/null
@@ -1,632 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-typedef struct
-{
- byte *data;
- int count;
-} cblock_t;
-
-typedef struct
-{
- qboolean restart_sound;
- int s_rate;
- int s_width;
- int s_channels;
-
- int width;
- int height;
- byte *pic;
- byte *pic_pending;
-
- // order 1 huffman stuff
- int *hnodes1; // [256][256][2];
- int numhnodes1[256];
-
- int h_used[512];
- int h_count[512];
-} cinematics_t;
-
-cinematics_t cin;
-
-/*
-=================================================================
-
-PCX LOADING
-
-=================================================================
-*/
-
-
-/*
-==============
-SCR_LoadPCX
-==============
-*/
-void SCR_LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
-{
- byte *raw;
- pcx_t *pcx;
- int x, y;
- int len;
- int dataByte, runLength;
- byte *out, *pix;
-
- *pic = NULL;
-
- //
- // load the file
- //
- len = FS_LoadFile (filename, (void **)&raw);
- if (!raw)
- return; // Com_Printf ("Bad pcx file %s\n", filename);
-
- //
- // parse the PCX file
- //
- pcx = (pcx_t *)raw;
- raw = &pcx->data;
-
- if (pcx->manufacturer != 0x0a
- || pcx->version != 5
- || pcx->encoding != 1
- || pcx->bits_per_pixel != 8
- || pcx->xmax >= 640
- || pcx->ymax >= 480)
- {
- Com_Printf ("Bad pcx file %s\n", filename);
- return;
- }
-
- out = Z_Malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
-
- *pic = out;
-
- pix = out;
-
- if (palette)
- {
- *palette = Z_Malloc(768);
- memcpy (*palette, (byte *)pcx + len - 768, 768);
- }
-
- if (width)
- *width = pcx->xmax+1;
- if (height)
- *height = pcx->ymax+1;
-
- for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
- {
- for (x=0 ; x<=pcx->xmax ; )
- {
- dataByte = *raw++;
-
- if((dataByte & 0xC0) == 0xC0)
- {
- runLength = dataByte & 0x3F;
- dataByte = *raw++;
- }
- else
- runLength = 1;
-
- while(runLength-- > 0)
- pix[x++] = dataByte;
- }
-
- }
-
- if ( raw - (byte *)pcx > len)
- {
- Com_Printf ("PCX file %s was malformed", filename);
- Z_Free (*pic);
- *pic = NULL;
- }
-
- FS_FreeFile (pcx);
-}
-
-//=============================================================
-
-/*
-==================
-SCR_StopCinematic
-==================
-*/
-void SCR_StopCinematic (void)
-{
- cl.cinematictime = 0; // done
- if (cin.pic)
- {
- Z_Free (cin.pic);
- cin.pic = NULL;
- }
- if (cin.pic_pending)
- {
- Z_Free (cin.pic_pending);
- cin.pic_pending = NULL;
- }
- if (cl.cinematicpalette_active)
- {
- re.CinematicSetPalette(NULL);
- cl.cinematicpalette_active = false;
- }
- if (cl.cinematic_file)
- {
- fclose (cl.cinematic_file);
- cl.cinematic_file = NULL;
- }
- if (cin.hnodes1)
- {
- Z_Free (cin.hnodes1);
- cin.hnodes1 = NULL;
- }
-
- // switch back down to 11 khz sound if necessary
- if (cin.restart_sound)
- {
- cin.restart_sound = false;
- CL_Snd_Restart_f ();
- }
-
-}
-
-/*
-====================
-SCR_FinishCinematic
-
-Called when either the cinematic completes, or it is aborted
-====================
-*/
-void SCR_FinishCinematic (void)
-{
- // tell the server to advance to the next map / cinematic
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- SZ_Print (&cls.netchan.message, va("nextserver %i\n", cl.servercount));
-}
-
-//==========================================================================
-
-/*
-==================
-SmallestNode1
-==================
-*/
-int SmallestNode1 (int numhnodes)
-{
- int i;
- int best, bestnode;
-
- best = 99999999;
- bestnode = -1;
- for (i=0 ; i<numhnodes ; i++)
- {
- if (cin.h_used[i])
- continue;
- if (!cin.h_count[i])
- continue;
- if (cin.h_count[i] < best)
- {
- best = cin.h_count[i];
- bestnode = i;
- }
- }
-
- if (bestnode == -1)
- return -1;
-
- cin.h_used[bestnode] = true;
- return bestnode;
-}
-
-
-/*
-==================
-Huff1TableInit
-
-Reads the 64k counts table and initializes the node trees
-==================
-*/
-void Huff1TableInit (void)
-{
- int prev;
- int j;
- int *node, *nodebase;
- byte counts[256];
- int numhnodes;
-
- cin.hnodes1 = Z_Malloc (256*256*2*4);
- memset (cin.hnodes1, 0, 256*256*2*4);
-
- for (prev=0 ; prev<256 ; prev++)
- {
- memset (cin.h_count,0,sizeof(cin.h_count));
- memset (cin.h_used,0,sizeof(cin.h_used));
-
- // read a row of counts
- FS_Read (counts, sizeof(counts), cl.cinematic_file);
- for (j=0 ; j<256 ; j++)
- cin.h_count[j] = counts[j];
-
- // build the nodes
- numhnodes = 256;
- nodebase = cin.hnodes1 + prev*256*2;
-
- while (numhnodes != 511)
- {
- node = nodebase + (numhnodes-256)*2;
-
- // pick two lowest counts
- node[0] = SmallestNode1 (numhnodes);
- if (node[0] == -1)
- break; // no more
-
- node[1] = SmallestNode1 (numhnodes);
- if (node[1] == -1)
- break;
-
- cin.h_count[numhnodes] = cin.h_count[node[0]] + cin.h_count[node[1]];
- numhnodes++;
- }
-
- cin.numhnodes1[prev] = numhnodes-1;
- }
-}
-
-/*
-==================
-Huff1Decompress
-==================
-*/
-cblock_t Huff1Decompress (cblock_t in)
-{
- byte *input;
- byte *out_p;
- int nodenum;
- int count;
- cblock_t out;
- int inbyte;
- int *hnodes, *hnodesbase;
-//int i;
-
- // get decompressed count
- count = in.data[0] + (in.data[1]<<8) + (in.data[2]<<16) + (in.data[3]<<24);
- input = in.data + 4;
- out_p = out.data = Z_Malloc (count);
-
- // read bits
-
- hnodesbase = cin.hnodes1 - 256*2; // nodes 0-255 aren't stored
-
- hnodes = hnodesbase;
- nodenum = cin.numhnodes1[0];
- while (count)
- {
- inbyte = *input++;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- inbyte >>=1;
- //-----------
- if (nodenum < 256)
- {
- hnodes = hnodesbase + (nodenum<<9);
- *out_p++ = nodenum;
- if (!--count)
- break;
- nodenum = cin.numhnodes1[nodenum];
- }
- nodenum = hnodes[nodenum*2 + (inbyte&1)];
- }
-
- if (input - in.data != in.count && input - in.data != in.count+1)
- {
- Com_Printf ("Decompression overread by %i", (input - in.data) - in.count);
- }
- out.count = out_p - out.data;
-
- return out;
-}
-
-/*
-==================
-SCR_ReadNextFrame
-==================
-*/
-byte *SCR_ReadNextFrame (void)
-{
- int r;
- int command;
- byte samples[22050/14*4];
- byte compressed[0x20000];
- int size;
- byte *pic;
- cblock_t in, huf1;
- int start, end, count;
-
- // read the next frame
- r = fread (&command, 4, 1, cl.cinematic_file);
- if (r == 0) // we'll give it one more chance
- r = fread (&command, 4, 1, cl.cinematic_file);
-
- if (r != 1)
- return NULL;
- command = LittleLong(command);
- if (command == 2)
- return NULL; // last frame marker
-
- if (command == 1)
- { // read palette
- FS_Read (cl.cinematicpalette, sizeof(cl.cinematicpalette), cl.cinematic_file);
- cl.cinematicpalette_active=0; // dubious.... exposes an edge case
- }
-
- // decompress the next frame
- FS_Read (&size, 4, cl.cinematic_file);
- size = LittleLong(size);
- if (size > sizeof(compressed) || size < 1)
- Com_Error (ERR_DROP, "Bad compressed frame size");
- FS_Read (compressed, size, cl.cinematic_file);
-
- // read sound
- start = cl.cinematicframe*cin.s_rate/14;
- end = (cl.cinematicframe+1)*cin.s_rate/14;
- count = end - start;
-
- FS_Read (samples, count*cin.s_width*cin.s_channels, cl.cinematic_file);
-
- S_RawSamples (count, cin.s_rate, cin.s_width, cin.s_channels, samples);
-
- in.data = compressed;
- in.count = size;
-
- huf1 = Huff1Decompress (in);
-
- pic = huf1.data;
-
- cl.cinematicframe++;
-
- return pic;
-}
-
-
-/*
-==================
-SCR_RunCinematic
-
-==================
-*/
-void SCR_RunCinematic (void)
-{
- int frame;
-
- if (cl.cinematictime <= 0)
- {
- SCR_StopCinematic ();
- return;
- }
-
- if (cl.cinematicframe == -1)
- return; // static image
-
- if (cls.key_dest != key_game)
- { // pause if menu or console is up
- cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14;
- return;
- }
-
- frame = (cls.realtime - cl.cinematictime)*14.0/1000;
- if (frame <= cl.cinematicframe)
- return;
- if (frame > cl.cinematicframe+1)
- {
- Com_Printf ("Dropped frame: %i > %i\n", frame, cl.cinematicframe+1);
- cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14;
- }
- if (cin.pic)
- Z_Free (cin.pic);
- cin.pic = cin.pic_pending;
- cin.pic_pending = NULL;
- cin.pic_pending = SCR_ReadNextFrame ();
- if (!cin.pic_pending)
- {
- SCR_StopCinematic ();
- SCR_FinishCinematic ();
- cl.cinematictime = 1; // hack to get the black screen behind loading
- SCR_BeginLoadingPlaque ();
- cl.cinematictime = 0;
- return;
- }
-}
-
-/*
-==================
-SCR_DrawCinematic
-
-Returns true if a cinematic is active, meaning the view rendering
-should be skipped
-==================
-*/
-qboolean SCR_DrawCinematic (void)
-{
- if (cl.cinematictime <= 0)
- {
- return false;
- }
-
- if (cls.key_dest == key_menu)
- { // blank screen and pause if menu is up
- re.CinematicSetPalette(NULL);
- cl.cinematicpalette_active = false;
- return true;
- }
-
- if (!cl.cinematicpalette_active)
- {
- re.CinematicSetPalette((uchar *)cl.cinematicpalette);
- cl.cinematicpalette_active = true;
- }
-
- if (!cin.pic)
- return true;
-
- re.DrawStretchRaw (0, 0, vid.width, vid.height, cin.width, cin.height, cin.pic);
-
- return true;
-}
-
-/*
-==================
-SCR_PlayCinematic
-
-==================
-*/
-void SCR_PlayCinematic (char *arg)
-{
- int width, height;
- byte *palette;
- char name[MAX_OSPATH], *dot;
- int old_khz;
-
- // make sure CD isn't playing music
- CDAudio_Stop();
-
- cl.cinematicframe = 0;
- dot = strstr (arg, ".");
- if (dot && !strcmp (dot, ".pcx"))
- { // static pcx image
- Com_sprintf (name, sizeof(name), "pics/%s", arg);
- SCR_LoadPCX (name, &cin.pic, &palette, &cin.width, &cin.height);
- cl.cinematicframe = -1;
- cl.cinematictime = 1;
- SCR_EndLoadingPlaque ();
- cls.state = ca_active;
- if (!cin.pic)
- {
- Com_Printf ("%s not found.\n", name);
- cl.cinematictime = 0;
- }
- else
- {
- memcpy (cl.cinematicpalette, palette, sizeof(cl.cinematicpalette));
- Z_Free (palette);
- }
- return;
- }
-
- Com_sprintf (name, sizeof(name), "video/%s", arg);
- FS_FOpenFile (name, &cl.cinematic_file);
- if (!cl.cinematic_file)
- {
-// Com_Error (ERR_DROP, "Cinematic %s not found.\n", name);
- SCR_FinishCinematic ();
- cl.cinematictime = 0; // done
- return;
- }
-
- SCR_EndLoadingPlaque ();
-
- cls.state = ca_active;
-
- FS_Read (&width, 4, cl.cinematic_file);
- FS_Read (&height, 4, cl.cinematic_file);
- cin.width = LittleLong(width);
- cin.height = LittleLong(height);
-
- FS_Read (&cin.s_rate, 4, cl.cinematic_file);
- cin.s_rate = LittleLong(cin.s_rate);
- FS_Read (&cin.s_width, 4, cl.cinematic_file);
- cin.s_width = LittleLong(cin.s_width);
- FS_Read (&cin.s_channels, 4, cl.cinematic_file);
- cin.s_channels = LittleLong(cin.s_channels);
-
- Huff1TableInit ();
-
- // switch up to 22 khz sound if necessary
- old_khz = Cvar_VariableValue ("s_khz");
- if (old_khz != cin.s_rate/1000)
- {
- cin.restart_sound = true;
- Cvar_SetValue ("s_khz", cin.s_rate/1000);
- CL_Snd_Restart_f ();
- Cvar_SetValue ("s_khz", old_khz);
- }
-
- cl.cinematicframe = 0;
- cin.pic = SCR_ReadNextFrame ();
- cl.cinematictime = Sys_Milliseconds ();
-}
--- a/client/cl_ents.c
+++ /dev/null
@@ -1,1487 +1,0 @@
-// cl_ents.c -- entity parsing and management
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-
-extern struct model_s *cl_mod_powerscreen;
-
-//PGM
-int vidref_val;
-//PGM
-
-/*
-=========================================================================
-
-FRAME PARSING
-
-=========================================================================
-*/
-
-/* the following are commented out in release
-
-typedef struct
-{
- int modelindex;
- int num; // entity number
- int effects;
- vec3_t origin;
- vec3_t oldorigin;
- vec3_t angles;
- qboolean present;
-} projectile_t;
-
-#define MAX_PROJECTILES 64
-projectile_t cl_projectiles[MAX_PROJECTILES];
-
-void CL_ClearProjectiles (void)
-{
- int i;
-
- for (i = 0; i < MAX_PROJECTILES; i++) {
-// if (cl_projectiles[i].present)
-// Com_DPrintf("PROJ: %d CLEARED\n", cl_projectiles[i].num);
- cl_projectiles[i].present = false;
- }
-}
-
-*/
-
-/*
-=====================
-CL_ParseProjectiles
-
-Flechettes are passed as efficient temporary entities
-=====================
-*/
-/*
-void CL_ParseProjectiles (void)
-{
- int i, c, j;
- byte bits[8];
- byte b;
- projectile_t pr;
- int lastempty = -1;
- qboolean old = false;
-
- c = MSG_ReadByte (&net_message);
- for (i=0 ; i<c ; i++)
- {
- bits[0] = MSG_ReadByte (&net_message);
- bits[1] = MSG_ReadByte (&net_message);
- bits[2] = MSG_ReadByte (&net_message);
- bits[3] = MSG_ReadByte (&net_message);
- bits[4] = MSG_ReadByte (&net_message);
- pr.origin[0] = ( ( bits[0] + ((bits[1]&15)<<8) ) <<1) - 4096;
- pr.origin[1] = ( ( (bits[1]>>4) + (bits[2]<<4) ) <<1) - 4096;
- pr.origin[2] = ( ( bits[3] + ((bits[4]&15)<<8) ) <<1) - 4096;
- VectorCopy(pr.origin, pr.oldorigin);
-
- if (bits[4] & 64)
- pr.effects = EF_BLASTER;
- else
- pr.effects = 0;
-
- if (bits[4] & 128) {
- old = true;
- bits[0] = MSG_ReadByte (&net_message);
- bits[1] = MSG_ReadByte (&net_message);
- bits[2] = MSG_ReadByte (&net_message);
- bits[3] = MSG_ReadByte (&net_message);
- bits[4] = MSG_ReadByte (&net_message);
- pr.oldorigin[0] = ( ( bits[0] + ((bits[1]&15)<<8) ) <<1) - 4096;
- pr.oldorigin[1] = ( ( (bits[1]>>4) + (bits[2]<<4) ) <<1) - 4096;
- pr.oldorigin[2] = ( ( bits[3] + ((bits[4]&15)<<8) ) <<1) - 4096;
- }
-
- bits[0] = MSG_ReadByte (&net_message);
- bits[1] = MSG_ReadByte (&net_message);
- bits[2] = MSG_ReadByte (&net_message);
-
- pr.angles[0] = 360*bits[0]/256;
- pr.angles[1] = 360*bits[1]/256;
- pr.modelindex = bits[2];
-
- b = MSG_ReadByte (&net_message);
- pr.num = (b & 0x7f);
- if (b & 128) // extra entity number byte
- pr.num |= (MSG_ReadByte (&net_message) << 7);
-
- pr.present = true;
-
- // find if this projectile already exists from previous frame
- for (j = 0; j < MAX_PROJECTILES; j++) {
- if (cl_projectiles[j].modelindex) {
- if (cl_projectiles[j].num == pr.num) {
- // already present, set up oldorigin for interpolation
- if (!old)
- VectorCopy(cl_projectiles[j].origin, pr.oldorigin);
- cl_projectiles[j] = pr;
- break;
- }
- } else
- lastempty = j;
- }
-
- // not present previous frame, add it
- if (j == MAX_PROJECTILES) {
- if (lastempty != -1) {
- cl_projectiles[lastempty] = pr;
- }
- }
- }
-}
-*/
-
-/*
-=============
-CL_LinkProjectiles
-
-=============
-*/
-/*
-void CL_AddProjectiles (void)
-{
- int i, j;
- projectile_t *pr;
- entity_t ent;
-
- memset (&ent, 0, sizeof(ent));
-
- for (i=0, pr=cl_projectiles ; i < MAX_PROJECTILES ; i++, pr++)
- {
- // grab an entity to fill in
- if (pr->modelindex < 1)
- continue;
- if (!pr->present) {
- pr->modelindex = 0;
- continue; // not present this frame (it was in the previous frame)
- }
-
- ent.model = cl.model_draw[pr->modelindex];
-
- // interpolate origin
- for (j=0 ; j<3 ; j++)
- {
- ent.origin[j] = ent.oldorigin[j] = pr->oldorigin[j] + cl.lerpfrac *
- (pr->origin[j] - pr->oldorigin[j]);
-
- }
-
- if (pr->effects & EF_BLASTER)
- CL_BlasterTrail (pr->oldorigin, ent.origin);
- V_AddLight (pr->origin, 200, 1, 1, 0);
-
- VectorCopy (pr->angles, ent.angles);
- V_AddEntity (&ent);
- }
-}
-*/
-
-/*
-=================
-CL_ParseEntityBits
-
-Returns the entity number and the header bits
-=================
-*/
-int bitcounts[32]; /// just for protocol profiling
-int CL_ParseEntityBits (int *bits)
-{
- unsigned b, total;
- int i;
- int number;
-
- total = MSG_ReadByte (&net_message);
- if (total & U_MOREBITS1)
- {
- b = MSG_ReadByte (&net_message);
- total |= b<<8;
- }
- if (total & U_MOREBITS2)
- {
- b = MSG_ReadByte (&net_message);
- total |= b<<16;
- }
- if (total & U_MOREBITS3)
- {
- b = MSG_ReadByte (&net_message);
- total |= b<<24;
- }
-
- // count the bits for net profiling
- for (i=0 ; i<32 ; i++)
- if (total&(1<<i))
- bitcounts[i]++;
-
- if (total & U_NUMBER16)
- number = MSG_ReadShort (&net_message);
- else
- number = MSG_ReadByte (&net_message);
-
- *bits = total;
-
- return number;
-}
-
-/*
-==================
-CL_ParseDelta
-
-Can go from either a baseline or a previous packet_entity
-==================
-*/
-void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int number, int bits)
-{
- // set everything to the state we are delta'ing from
- *to = *from;
-
- VectorCopy (from->origin, to->old_origin);
- to->number = number;
-
- if (bits & U_MODEL)
- to->modelindex = MSG_ReadByte (&net_message);
- if (bits & U_MODEL2)
- to->modelindex2 = MSG_ReadByte (&net_message);
- if (bits & U_MODEL3)
- to->modelindex3 = MSG_ReadByte (&net_message);
- if (bits & U_MODEL4)
- to->modelindex4 = MSG_ReadByte (&net_message);
-
- if (bits & U_FRAME8)
- to->frame = MSG_ReadByte (&net_message);
- if (bits & U_FRAME16)
- to->frame = MSG_ReadShort (&net_message);
-
- if ((bits & U_SKIN8) && (bits & U_SKIN16)) //used for laser colors
- to->skinnum = MSG_ReadLong(&net_message);
- else if (bits & U_SKIN8)
- to->skinnum = MSG_ReadByte(&net_message);
- else if (bits & U_SKIN16)
- to->skinnum = MSG_ReadShort(&net_message);
-
- if ( (bits & (U_EFFECTS8|U_EFFECTS16)) == (U_EFFECTS8|U_EFFECTS16) )
- to->effects = MSG_ReadLong(&net_message);
- else if (bits & U_EFFECTS8)
- to->effects = MSG_ReadByte(&net_message);
- else if (bits & U_EFFECTS16)
- to->effects = MSG_ReadShort(&net_message);
-
- if ( (bits & (U_RENDERFX8|U_RENDERFX16)) == (U_RENDERFX8|U_RENDERFX16) )
- to->renderfx = MSG_ReadLong(&net_message);
- else if (bits & U_RENDERFX8)
- to->renderfx = MSG_ReadByte(&net_message);
- else if (bits & U_RENDERFX16)
- to->renderfx = MSG_ReadShort(&net_message);
-
- if (bits & U_ORIGIN1)
- to->origin[0] = MSG_ReadCoord (&net_message);
- if (bits & U_ORIGIN2)
- to->origin[1] = MSG_ReadCoord (&net_message);
- if (bits & U_ORIGIN3)
- to->origin[2] = MSG_ReadCoord (&net_message);
-
- if (bits & U_ANGLE1)
- to->angles[0] = MSG_ReadAngle(&net_message);
- if (bits & U_ANGLE2)
- to->angles[1] = MSG_ReadAngle(&net_message);
- if (bits & U_ANGLE3)
- to->angles[2] = MSG_ReadAngle(&net_message);
-
- if (bits & U_OLDORIGIN)
- MSG_ReadPos (&net_message, to->old_origin);
-
- if (bits & U_SOUND)
- to->sound = MSG_ReadByte (&net_message);
-
- if (bits & U_EVENT)
- to->event = MSG_ReadByte (&net_message);
- else
- to->event = 0;
-
- if (bits & U_SOLID)
- to->solid = MSG_ReadShort (&net_message);
-}
-
-/*
-==================
-CL_DeltaEntity
-
-Parses deltas from the given base and adds the resulting entity
-to the current frame
-==================
-*/
-void CL_DeltaEntity (frame_t *frame, int newnum, entity_state_t *old, int bits)
-{
- centity_t *ent;
- entity_state_t *state;
-
- ent = &cl_entities[newnum];
-
- state = &cl_parse_entities[cl.parse_entities & (MAX_PARSE_ENTITIES-1)];
- cl.parse_entities++;
- frame->num_entities++;
-
- CL_ParseDelta (old, state, newnum, bits);
-
- // some data changes will force no lerping
- if (state->modelindex != ent->current.modelindex
- || state->modelindex2 != ent->current.modelindex2
- || state->modelindex3 != ent->current.modelindex3
- || state->modelindex4 != ent->current.modelindex4
- || abs(state->origin[0] - ent->current.origin[0]) > 512
- || abs(state->origin[1] - ent->current.origin[1]) > 512
- || abs(state->origin[2] - ent->current.origin[2]) > 512
- || state->event == EV_PLAYER_TELEPORT
- || state->event == EV_OTHER_TELEPORT
- )
- {
- ent->serverframe = -99;
- }
-
- if (ent->serverframe != cl.frame.serverframe - 1)
- { // wasn't in last update, so initialize some things
- ent->trailcount = 1024; // for diminishing rocket / grenade trails
- // duplicate the current state so lerping doesn't hurt anything
- ent->prev = *state;
- if (state->event == EV_OTHER_TELEPORT)
- {
- VectorCopy (state->origin, ent->prev.origin);
- VectorCopy (state->origin, ent->lerp_origin);
- }
- else
- {
- VectorCopy (state->old_origin, ent->prev.origin);
- VectorCopy (state->old_origin, ent->lerp_origin);
- }
- }
- else
- { // shuffle the last state to previous
- ent->prev = ent->current;
- }
-
- ent->serverframe = cl.frame.serverframe;
- ent->current = *state;
-}
-
-/*
-==================
-CL_ParsePacketEntities
-
-An svc_packetentities has just been parsed, deal with the
-rest of the data stream.
-==================
-*/
-void CL_ParsePacketEntities (frame_t *oldframe, frame_t *newframe)
-{
- int newnum;
- int bits;
- entity_state_t *oldstate = nil;
- int oldindex, oldnum;
-
- newframe->parse_entities = cl.parse_entities;
- newframe->num_entities = 0;
-
- // delta from the entities present in oldframe
- oldindex = 0;
- if (!oldframe)
- oldnum = 99999;
- else
- {
- if (oldindex >= oldframe->num_entities)
- oldnum = 99999;
- else
- {
- oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
- oldnum = oldstate->number;
- }
- }
-
- while (1)
- {
- newnum = CL_ParseEntityBits (&bits);
- if (newnum >= MAX_EDICTS)
- Com_Error (ERR_DROP,"CL_ParsePacketEntities: bad number:%i", newnum);
-
- if (net_message.readcount > net_message.cursize)
- Com_Error (ERR_DROP,"CL_ParsePacketEntities: end of message");
-
- if (!newnum)
- break;
-
- while (oldnum < newnum)
- { // one or more entities from the old packet are unchanged
- if (cl_shownet->value == 3)
- Com_Printf (" unchanged: %i\n", oldnum);
- CL_DeltaEntity (newframe, oldnum, oldstate, 0);
-
- oldindex++;
-
- if (oldindex >= oldframe->num_entities)
- oldnum = 99999;
- else
- {
- oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
- oldnum = oldstate->number;
- }
- }
-
- if (bits & U_REMOVE)
- { // the entity present in oldframe is not in the current frame
- if (cl_shownet->value == 3)
- Com_Printf (" remove: %i\n", newnum);
- if (oldnum != newnum)
- Com_Printf ("U_REMOVE: oldnum != newnum\n");
-
- oldindex++;
-
- if (oldindex >= oldframe->num_entities)
- oldnum = 99999;
- else
- {
- oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
- oldnum = oldstate->number;
- }
- continue;
- }
-
- if (oldnum == newnum)
- { // delta from previous state
- if (cl_shownet->value == 3)
- Com_Printf (" delta: %i\n", newnum);
- CL_DeltaEntity (newframe, newnum, oldstate, bits);
-
- oldindex++;
-
- if (oldindex >= oldframe->num_entities)
- oldnum = 99999;
- else
- {
- oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
- oldnum = oldstate->number;
- }
- continue;
- }
-
- if (oldnum > newnum)
- { // delta from baseline
- if (cl_shownet->value == 3)
- Com_Printf (" baseline: %i\n", newnum);
- CL_DeltaEntity (newframe, newnum, &cl_entities[newnum].baseline, bits);
- continue;
- }
-
- }
-
- // any remaining entities in the old frame are copied over
- while (oldnum != 99999)
- { // one or more entities from the old packet are unchanged
- if (cl_shownet->value == 3)
- Com_Printf (" unchanged: %i\n", oldnum);
- CL_DeltaEntity (newframe, oldnum, oldstate, 0);
-
- oldindex++;
-
- if (oldindex >= oldframe->num_entities)
- oldnum = 99999;
- else
- {
- oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
- oldnum = oldstate->number;
- }
- }
-}
-
-
-
-/*
-===================
-CL_ParsePlayerstate
-===================
-*/
-void CL_ParsePlayerstate (frame_t *oldframe, frame_t *newframe)
-{
- int flags;
- player_state_t *state;
- int i;
- int statbits;
-
- state = &newframe->playerstate;
-
- // clear to old value before delta parsing
- if (oldframe)
- *state = oldframe->playerstate;
- else
- memset (state, 0, sizeof(*state));
-
- flags = MSG_ReadShort (&net_message);
-
- //
- // parse the pmove_state_t
- //
- if (flags & PS_M_TYPE)
- state->pmove.pm_type = MSG_ReadByte (&net_message);
-
- if (flags & PS_M_ORIGIN)
- {
- state->pmove.origin[0] = MSG_ReadShort (&net_message);
- state->pmove.origin[1] = MSG_ReadShort (&net_message);
- state->pmove.origin[2] = MSG_ReadShort (&net_message);
- }
-
- if (flags & PS_M_VELOCITY)
- {
- state->pmove.velocity[0] = MSG_ReadShort (&net_message);
- state->pmove.velocity[1] = MSG_ReadShort (&net_message);
- state->pmove.velocity[2] = MSG_ReadShort (&net_message);
- }
-
- if (flags & PS_M_TIME)
- state->pmove.pm_time = MSG_ReadByte (&net_message);
-
- if (flags & PS_M_FLAGS)
- state->pmove.pm_flags = MSG_ReadByte (&net_message);
-
- if (flags & PS_M_GRAVITY)
- state->pmove.gravity = MSG_ReadShort (&net_message);
-
- if (flags & PS_M_DELTA_ANGLES)
- {
- state->pmove.delta_angles[0] = MSG_ReadShort (&net_message);
- state->pmove.delta_angles[1] = MSG_ReadShort (&net_message);
- state->pmove.delta_angles[2] = MSG_ReadShort (&net_message);
- }
-
- if (cl.attractloop)
- state->pmove.pm_type = PM_FREEZE; // demo playback
-
- //
- // parse the rest of the player_state_t
- //
- if (flags & PS_VIEWOFFSET)
- {
- state->viewoffset[0] = MSG_ReadChar (&net_message) * 0.25;
- state->viewoffset[1] = MSG_ReadChar (&net_message) * 0.25;
- state->viewoffset[2] = MSG_ReadChar (&net_message) * 0.25;
- }
-
- if (flags & PS_VIEWANGLES)
- {
- state->viewangles[0] = MSG_ReadAngle16 (&net_message);
- state->viewangles[1] = MSG_ReadAngle16 (&net_message);
- state->viewangles[2] = MSG_ReadAngle16 (&net_message);
- }
-
- if (flags & PS_KICKANGLES)
- {
- state->kick_angles[0] = MSG_ReadChar (&net_message) * 0.25;
- state->kick_angles[1] = MSG_ReadChar (&net_message) * 0.25;
- state->kick_angles[2] = MSG_ReadChar (&net_message) * 0.25;
- }
-
- if (flags & PS_WEAPONINDEX)
- {
- state->gunindex = MSG_ReadByte (&net_message);
- }
-
- if (flags & PS_WEAPONFRAME)
- {
- state->gunframe = MSG_ReadByte (&net_message);
- state->gunoffset[0] = MSG_ReadChar (&net_message)*0.25;
- state->gunoffset[1] = MSG_ReadChar (&net_message)*0.25;
- state->gunoffset[2] = MSG_ReadChar (&net_message)*0.25;
- state->gunangles[0] = MSG_ReadChar (&net_message)*0.25;
- state->gunangles[1] = MSG_ReadChar (&net_message)*0.25;
- state->gunangles[2] = MSG_ReadChar (&net_message)*0.25;
- }
-
- if (flags & PS_BLEND)
- {
- state->blend[0] = MSG_ReadByte (&net_message)/255.0;
- state->blend[1] = MSG_ReadByte (&net_message)/255.0;
- state->blend[2] = MSG_ReadByte (&net_message)/255.0;
- state->blend[3] = MSG_ReadByte (&net_message)/255.0;
- }
-
- if (flags & PS_FOV)
- state->fov = MSG_ReadByte (&net_message);
-
- if (flags & PS_RDFLAGS)
- state->rdflags = MSG_ReadByte (&net_message);
-
- // parse stats
- statbits = MSG_ReadLong (&net_message);
- for (i=0 ; i<MAX_STATS ; i++)
- if (statbits & (1<<i) )
- state->stats[i] = MSG_ReadShort(&net_message);
-}
-
-
-/*
-==================
-CL_FireEntityEvents
-
-==================
-*/
-void CL_FireEntityEvents (frame_t *frame)
-{
- entity_state_t *s1;
- int pnum, num;
-
- for (pnum = 0 ; pnum<frame->num_entities ; pnum++)
- {
- num = (frame->parse_entities + pnum)&(MAX_PARSE_ENTITIES-1);
- s1 = &cl_parse_entities[num];
- if (s1->event)
- CL_EntityEvent (s1);
-
- // EF_TELEPORTER acts like an event, but is not cleared each frame
- if (s1->effects & EF_TELEPORTER)
- CL_TeleporterParticles (s1);
- }
-}
-
-
-/*
-================
-CL_ParseFrame
-================
-*/
-void CL_ParseFrame (void)
-{
- int cmd;
- int len;
- frame_t *old;
-
- memset (&cl.frame, 0, sizeof(cl.frame));
-
-/*
- CL_ClearProjectiles(); // clear projectiles for new frame
-*/
-
- cl.frame.serverframe = MSG_ReadLong (&net_message);
- cl.frame.deltaframe = MSG_ReadLong (&net_message);
- cl.frame.servertime = cl.frame.serverframe*100;
-
- // BIG HACK to let old demos continue to work
- if (cls.serverProtocol != 26)
- cl.surpressCount = MSG_ReadByte (&net_message);
-
- if (cl_shownet->value == 3)
- Com_Printf (" frame:%i delta:%i\n", cl.frame.serverframe,
- cl.frame.deltaframe);
-
- // If the frame is delta compressed from data that we
- // no longer have available, we must suck up the rest of
- // the frame, but not use it, then ask for a non-compressed
- // message
- if (cl.frame.deltaframe <= 0)
- {
- cl.frame.valid = true; // uncompressed frame
- old = NULL;
- cls.demowaiting = false; // we can start recording now
- }
- else
- {
- old = &cl.frames[cl.frame.deltaframe & UPDATE_MASK];
- if (!old->valid)
- { // should never happen
- Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
- }
- if (old->serverframe != cl.frame.deltaframe)
- { // The frame that the server did the delta from
- // is too old, so we can't reconstruct it properly.
- Com_Printf ("Delta frame too old.\n");
- }
- else if (cl.parse_entities - old->parse_entities > MAX_PARSE_ENTITIES-128)
- {
- Com_Printf ("Delta parse_entities too old.\n");
- }
- else
- cl.frame.valid = true; // valid delta parse
- }
-
- // clamp time
- if (cl.time > cl.frame.servertime)
- cl.time = cl.frame.servertime;
- else if (cl.time < cl.frame.servertime - 100)
- cl.time = cl.frame.servertime - 100;
-
- // read areabits
- len = MSG_ReadByte (&net_message);
- MSG_ReadData (&net_message, cl.frame.areabits, len);
-
- // read playerinfo
- cmd = MSG_ReadByte (&net_message);
- SHOWNET(svc_strings[cmd]);
- if (cmd != svc_playerinfo)
- Com_Error (ERR_DROP, "CL_ParseFrame: not playerinfo");
- CL_ParsePlayerstate (old, &cl.frame);
-
- // read packet entities
- cmd = MSG_ReadByte (&net_message);
- SHOWNET(svc_strings[cmd]);
- if (cmd != svc_packetentities)
- Com_Error (ERR_DROP, "CL_ParseFrame: not packetentities");
- CL_ParsePacketEntities (old, &cl.frame);
-
-/*
- if (cmd == svc_packetentities2)
- CL_ParseProjectiles();
-*/
-
- // save the frame off in the backup array for later delta comparisons
- cl.frames[cl.frame.serverframe & UPDATE_MASK] = cl.frame;
-
- if (cl.frame.valid)
- {
- // getting a valid frame message ends the connection process
- if (cls.state != ca_active)
- {
- cls.state = ca_active;
- cl.force_refdef = true;
- cl.predicted_origin[0] = cl.frame.playerstate.pmove.origin[0]*0.125;
- cl.predicted_origin[1] = cl.frame.playerstate.pmove.origin[1]*0.125;
- cl.predicted_origin[2] = cl.frame.playerstate.pmove.origin[2]*0.125;
- VectorCopy (cl.frame.playerstate.viewangles, cl.predicted_angles);
- if (cls.disable_servercount != cl.servercount
- && cl.refresh_prepped)
- SCR_EndLoadingPlaque (); // get rid of loading plaque
- }
- cl.sound_prepped = true; // can start mixing ambient sounds
-
- // fire entity events
- CL_FireEntityEvents (&cl.frame);
- CL_CheckPredictionError ();
- }
-}
-
-/*
-==========================================================================
-
-INTERPOLATE BETWEEN FRAMES TO GET RENDERING PARMS
-
-==========================================================================
-*/
-
-struct model_s *S_RegisterSexedModel (entity_state_t *ent, char *base)
-{
- int n;
- char *p;
- struct model_s *mdl;
- char model[MAX_QPATH];
- char buffer[MAX_QPATH];
-
- // determine what model the client is using
- model[0] = 0;
- n = CS_PLAYERSKINS + ent->number - 1;
- if (cl.configstrings[n][0])
- {
- p = strchr(cl.configstrings[n], '\\');
- if (p)
- {
- p += 1;
- strcpy(model, p);
- p = strchr(model, '/');
- if (p)
- *p = 0;
- }
- }
- // if we can't figure it out, they're male
- if (!model[0])
- strcpy(model, "male");
-
- Com_sprintf (buffer, sizeof(buffer), "players/%s/%s", model, base+1);
- mdl = re.RegisterModel(buffer);
- if (!mdl) {
- // not found, try default weapon model
- Com_sprintf (buffer, sizeof(buffer), "players/%s/weapon.md2", model);
- mdl = re.RegisterModel(buffer);
- if (!mdl) {
- // no, revert to the male model
- Com_sprintf (buffer, sizeof(buffer), "players/%s/%s", "male", base+1);
- mdl = re.RegisterModel(buffer);
- if (!mdl) {
- // last try, default male weapon.md2
- Com_sprintf (buffer, sizeof(buffer), "players/male/weapon.md2");
- mdl = re.RegisterModel(buffer);
- }
- }
- }
-
- return mdl;
-}
-
-/*
-===============
-CL_AddPacketEntities
-
-===============
-*/
-void CL_AddPacketEntities (frame_t *frame)
-{
- entity_t ent;
- entity_state_t *s1;
- float autorotate;
- int i;
- int pnum;
- centity_t *cent;
- int autoanim;
- clientinfo_t *ci;
- unsigned int effects, renderfx;
-
- // bonus items rotate at a fixed rate
- autorotate = anglemod(cl.time/10);
-
- // brush models can auto animate their frames
- autoanim = 2*cl.time/1000;
-
- memset (&ent, 0, sizeof(ent));
-
- for (pnum = 0 ; pnum<frame->num_entities ; pnum++)
- {
- s1 = &cl_parse_entities[(frame->parse_entities+pnum)&(MAX_PARSE_ENTITIES-1)];
-
- cent = &cl_entities[s1->number];
-
- effects = s1->effects;
- renderfx = s1->renderfx;
-
- // set frame
- if (effects & EF_ANIM01)
- ent.frame = autoanim & 1;
- else if (effects & EF_ANIM23)
- ent.frame = 2 + (autoanim & 1);
- else if (effects & EF_ANIM_ALL)
- ent.frame = autoanim;
- else if (effects & EF_ANIM_ALLFAST)
- ent.frame = cl.time / 100;
- else
- ent.frame = s1->frame;
-
- // quad and pent can do different things on client
- if (effects & EF_PENT)
- {
- effects &= ~EF_PENT;
- effects |= EF_COLOR_SHELL;
- renderfx |= RF_SHELL_RED;
- }
-
- if (effects & EF_QUAD)
- {
- effects &= ~EF_QUAD;
- effects |= EF_COLOR_SHELL;
- renderfx |= RF_SHELL_BLUE;
- }
-//======
-// PMM
- if (effects & EF_DOUBLE)
- {
- effects &= ~EF_DOUBLE;
- effects |= EF_COLOR_SHELL;
- renderfx |= RF_SHELL_DOUBLE;
- }
-
- if (effects & EF_HALF_DAMAGE)
- {
- effects &= ~EF_HALF_DAMAGE;
- effects |= EF_COLOR_SHELL;
- renderfx |= RF_SHELL_HALF_DAM;
- }
-// pmm
-//======
- ent.oldframe = cent->prev.frame;
- ent.backlerp = 1.0 - cl.lerpfrac;
-
- if (renderfx & (RF_FRAMELERP|RF_BEAM))
- { // step origin discretely, because the frames
- // do the animation properly
- VectorCopy (cent->current.origin, ent.origin);
- VectorCopy (cent->current.old_origin, ent.oldorigin);
- }
- else
- { // interpolate origin
- for (i=0 ; i<3 ; i++)
- {
- ent.origin[i] = ent.oldorigin[i] = cent->prev.origin[i] + cl.lerpfrac *
- (cent->current.origin[i] - cent->prev.origin[i]);
- }
- }
-
- // create a new entity
-
- // tweak the color of beams
- if ( renderfx & RF_BEAM )
- { // the four beam colors are encoded in 32 bits of skinnum (hack)
- ent.alpha = 0.30;
- ent.skinnum = (s1->skinnum >> ((rand() % 4)*8)) & 0xff;
- ent.model = NULL;
- }
- else
- {
- // set skin
- if (s1->modelindex == 255)
- { // use custom player skin
- ent.skinnum = 0;
- ci = &cl.clientinfo[s1->skinnum & 0xff];
- ent.skin = ci->skin;
- ent.model = ci->model;
- if (!ent.skin || !ent.model)
- {
- ent.skin = cl.baseclientinfo.skin;
- ent.model = cl.baseclientinfo.model;
- }
-
-//============
-//PGM
- if (renderfx & RF_USE_DISGUISE)
- {
- if(!strncmp((char *)ent.skin, "players/male", 12))
- {
- ent.skin = re.RegisterSkin ("players/male/disguise.pcx");
- ent.model = re.RegisterModel ("players/male/tris.md2");
- }
- else if(!strncmp((char *)ent.skin, "players/female", 14))
- {
- ent.skin = re.RegisterSkin ("players/female/disguise.pcx");
- ent.model = re.RegisterModel ("players/female/tris.md2");
- }
- else if(!strncmp((char *)ent.skin, "players/cyborg", 14))
- {
- ent.skin = re.RegisterSkin ("players/cyborg/disguise.pcx");
- ent.model = re.RegisterModel ("players/cyborg/tris.md2");
- }
- }
-//PGM
-//============
- }
- else
- {
- ent.skinnum = s1->skinnum;
- ent.skin = NULL;
- ent.model = cl.model_draw[s1->modelindex];
- }
- }
-
- // only used for black hole model right now, FIXME: do better
- if (renderfx == RF_TRANSLUCENT)
- ent.alpha = 0.70;
-
- // render effects (fullbright, translucent, etc)
- if ((effects & EF_COLOR_SHELL))
- ent.flags = 0; // renderfx go on color shell entity
- else
- ent.flags = renderfx;
-
- // calculate angles
- if (effects & EF_ROTATE)
- { // some bonus items auto-rotate
- ent.angles[0] = 0;
- ent.angles[1] = autorotate;
- ent.angles[2] = 0;
- }
- // RAFAEL
- else if (effects & EF_SPINNINGLIGHTS)
- {
- ent.angles[0] = 0;
- ent.angles[1] = anglemod(cl.time/2) + s1->angles[1];
- ent.angles[2] = 180;
- {
- vec3_t forward;
- vec3_t start;
-
- AngleVectors (ent.angles, forward, NULL, NULL);
- VectorMA (ent.origin, 64, forward, start);
- V_AddLight (start, 100, 1, 0, 0);
- }
- }
- else
- { // interpolate angles
- float a1, a2;
-
- for (i=0 ; i<3 ; i++)
- {
- a1 = cent->current.angles[i];
- a2 = cent->prev.angles[i];
- ent.angles[i] = LerpAngle (a2, a1, cl.lerpfrac);
- }
- }
-
- if (s1->number == cl.playernum+1)
- {
- ent.flags |= RF_VIEWERMODEL; // only draw from mirrors
- // FIXME: still pass to refresh
-
- if (effects & EF_FLAG1)
- V_AddLight (ent.origin, 225, 1.0, 0.1, 0.1);
- else if (effects & EF_FLAG2)
- V_AddLight (ent.origin, 225, 0.1, 0.1, 1.0);
- else if (effects & EF_TAGTRAIL) //PGM
- V_AddLight (ent.origin, 225, 1.0, 1.0, 0.0); //PGM
- else if (effects & EF_TRACKERTRAIL) //PGM
- V_AddLight (ent.origin, 225, -1.0, -1.0, -1.0); //PGM
-
- continue;
- }
-
- // if set to invisible, skip
- if (!s1->modelindex)
- continue;
-
- if (effects & EF_BFG)
- {
- ent.flags |= RF_TRANSLUCENT;
- ent.alpha = 0.30;
- }
-
- // RAFAEL
- if (effects & EF_PLASMA)
- {
- ent.flags |= RF_TRANSLUCENT;
- ent.alpha = 0.6;
- }
-
- if (effects & EF_SPHERETRANS)
- {
- ent.flags |= RF_TRANSLUCENT;
- // PMM - *sigh* yet more EF overloading
- if (effects & EF_TRACKERTRAIL)
- ent.alpha = 0.6;
- else
- ent.alpha = 0.3;
- }
-//pmm
-
- // add to refresh list
- V_AddEntity (&ent);
-
- // color shells generate a seperate entity for the main model
- if (effects & EF_COLOR_SHELL)
- {
- ent.flags = renderfx | RF_TRANSLUCENT;
- ent.alpha = 0.30;
- V_AddEntity (&ent);
- }
-
- ent.skin = NULL; // never use a custom skin on others
- ent.skinnum = 0;
- ent.flags = 0;
- ent.alpha = 0;
-
- // duplicate for linked models
- if (s1->modelindex2)
- {
- if (s1->modelindex2 == 255)
- { // custom weapon
- ci = &cl.clientinfo[s1->skinnum & 0xff];
- i = (s1->skinnum >> 8); // 0 is default weapon model
- if (!cl_vwep->value || i > MAX_CLIENTWEAPONMODELS - 1)
- i = 0;
- ent.model = ci->weaponmodel[i];
- if (!ent.model) {
- if (i != 0)
- ent.model = ci->weaponmodel[0];
- if (!ent.model)
- ent.model = cl.baseclientinfo.weaponmodel[0];
- }
- }
- //PGM - hack to allow translucent linked models (defender sphere's shell)
- // set the high bit 0x80 on modelindex2 to enable translucency
- else if(s1->modelindex2 & 0x80)
- {
- ent.model = cl.model_draw[s1->modelindex2 & 0x7F];
- ent.alpha = 0.32;
- ent.flags = RF_TRANSLUCENT;
- }
- //PGM
- else
- ent.model = cl.model_draw[s1->modelindex2];
- V_AddEntity (&ent);
-
- //PGM - make sure these get reset.
- ent.flags = 0;
- ent.alpha = 0;
- //PGM
- }
- if (s1->modelindex3)
- {
- ent.model = cl.model_draw[s1->modelindex3];
- V_AddEntity (&ent);
- }
- if (s1->modelindex4)
- {
- ent.model = cl.model_draw[s1->modelindex4];
- V_AddEntity (&ent);
- }
-
- if ( effects & EF_POWERSCREEN )
- {
- ent.model = cl_mod_powerscreen;
- ent.oldframe = 0;
- ent.frame = 0;
- ent.flags |= (RF_TRANSLUCENT | RF_SHELL_GREEN);
- ent.alpha = 0.30;
- V_AddEntity (&ent);
- }
-
- // add automatic particle trails
- if ( (effects&~EF_ROTATE) )
- {
- if (effects & EF_ROCKET)
- {
- CL_RocketTrail (cent->lerp_origin, ent.origin, cent);
- V_AddLight (ent.origin, 200, 1, 1, 0);
- }
- // PGM - Do not reorder EF_BLASTER and EF_HYPERBLASTER.
- // EF_BLASTER | EF_TRACKER is a special case for EF_BLASTER2... Cheese!
- else if (effects & EF_BLASTER)
- {
-// CL_BlasterTrail (cent->lerp_origin, ent.origin);
-//PGM
- if (effects & EF_TRACKER) // lame... problematic?
- {
- CL_BlasterTrail2 (cent->lerp_origin, ent.origin);
- V_AddLight (ent.origin, 200, 0, 1, 0);
- }
- else
- {
- CL_BlasterTrail (cent->lerp_origin, ent.origin);
- V_AddLight (ent.origin, 200, 1, 1, 0);
- }
-//PGM
- }
- else if (effects & EF_HYPERBLASTER)
- {
- if (effects & EF_TRACKER) // PGM overloaded for blaster2.
- V_AddLight (ent.origin, 200, 0, 1, 0); // PGM
- else // PGM
- V_AddLight (ent.origin, 200, 1, 1, 0);
- }
- else if (effects & EF_GIB)
- {
- CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
- }
- else if (effects & EF_GRENADE)
- {
- CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
- }
- else if (effects & EF_FLIES)
- {
- CL_FlyEffect (cent, ent.origin);
- }
- else if (effects & EF_BFG)
- {
- static int bfg_lightramp[6] = {300, 400, 600, 300, 150, 75};
-
- if (effects & EF_ANIM_ALLFAST)
- {
- CL_BfgParticles (&ent);
- i = 200;
- }
- else
- {
- i = bfg_lightramp[s1->frame];
- }
- V_AddLight (ent.origin, i, 0, 1, 0);
- }
- // RAFAEL
- else if (effects & EF_TRAP)
- {
- ent.origin[2] += 32;
- CL_TrapParticles (&ent);
- i = (rand()%100) + 100;
- V_AddLight (ent.origin, i, 1, 0.8, 0.1);
- }
- else if (effects & EF_FLAG1)
- {
- CL_FlagTrail (cent->lerp_origin, ent.origin, 242);
- V_AddLight (ent.origin, 225, 1, 0.1, 0.1);
- }
- else if (effects & EF_FLAG2)
- {
- CL_FlagTrail (cent->lerp_origin, ent.origin, 115);
- V_AddLight (ent.origin, 225, 0.1, 0.1, 1);
- }
-//======
-//ROGUE
- else if (effects & EF_TAGTRAIL)
- {
- CL_TagTrail (cent->lerp_origin, ent.origin, 220);
- V_AddLight (ent.origin, 225, 1.0, 1.0, 0.0);
- }
- else if (effects & EF_TRACKERTRAIL)
- {
- if (effects & EF_TRACKER)
- {
- float intensity;
-
- intensity = 50 + (500 * (sin(cl.time/500.0) + 1.0));
- // FIXME - check out this effect in rendition
- if(vidref_val == VIDREF_GL)
- V_AddLight (ent.origin, intensity, -1.0, -1.0, -1.0);
- else
- V_AddLight (ent.origin, -1.0 * intensity, 1.0, 1.0, 1.0);
- }
- else
- {
- CL_Tracker_Shell (cent->lerp_origin);
- V_AddLight (ent.origin, 155, -1.0, -1.0, -1.0);
- }
- }
- else if (effects & EF_TRACKER)
- {
- CL_TrackerTrail (cent->lerp_origin, ent.origin, 0);
- // FIXME - check out this effect in rendition
- if(vidref_val == VIDREF_GL)
- V_AddLight (ent.origin, 200, -1, -1, -1);
- else
- V_AddLight (ent.origin, -200, 1, 1, 1);
- }
-//ROGUE
-//======
- // RAFAEL
- else if (effects & EF_GREENGIB)
- {
- CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
- }
- // RAFAEL
- else if (effects & EF_IONRIPPER)
- {
- CL_IonripperTrail (cent->lerp_origin, ent.origin);
- V_AddLight (ent.origin, 100, 1, 0.5, 0.5);
- }
- // RAFAEL
- else if (effects & EF_BLUEHYPERBLASTER)
- {
- V_AddLight (ent.origin, 200, 0, 0, 1);
- }
- // RAFAEL
- else if (effects & EF_PLASMA)
- {
- if (effects & EF_ANIM_ALLFAST)
- {
- CL_BlasterTrail (cent->lerp_origin, ent.origin);
- }
- V_AddLight (ent.origin, 130, 1, 0.5, 0.5);
- }
- }
-
- VectorCopy (ent.origin, cent->lerp_origin);
- }
-}
-
-
-
-/*
-==============
-CL_AddViewWeapon
-==============
-*/
-void CL_AddViewWeapon (player_state_t *ps, player_state_t *ops)
-{
- entity_t gun; // view model
- int i;
-
- // allow the gun to be completely removed
- if (!cl_gun->value)
- return;
-
- // don't draw gun if in wide angle view
- if (ps->fov > 90)
- return;
-
- memset (&gun, 0, sizeof(gun));
-
- if (gun_model)
- gun.model = gun_model; // development tool
- else
- gun.model = cl.model_draw[ps->gunindex];
- if (!gun.model)
- return;
-
- // set up gun position
- for (i=0 ; i<3 ; i++)
- {
- gun.origin[i] = cl.refdef.vieworg[i] + ops->gunoffset[i]
- + cl.lerpfrac * (ps->gunoffset[i] - ops->gunoffset[i]);
- gun.angles[i] = cl.refdef.viewangles[i] + LerpAngle (ops->gunangles[i],
- ps->gunangles[i], cl.lerpfrac);
- }
-
- if (gun_frame)
- {
- gun.frame = gun_frame; // development tool
- gun.oldframe = gun_frame; // development tool
- }
- else
- {
- gun.frame = ps->gunframe;
- if (gun.frame == 0)
- gun.oldframe = 0; // just changed weapons, don't lerp from old
- else
- gun.oldframe = ops->gunframe;
- }
-
- gun.flags = RF_MINLIGHT | RF_DEPTHHACK | RF_WEAPONMODEL;
- gun.backlerp = 1.0 - cl.lerpfrac;
- VectorCopy (gun.origin, gun.oldorigin); // don't lerp at all
- V_AddEntity (&gun);
-}
-
-
-/*
-===============
-CL_CalcViewValues
-
-Sets cl.refdef view values
-===============
-*/
-void CL_CalcViewValues (void)
-{
- int i;
- float lerp, backlerp;
- frame_t *oldframe;
- player_state_t *ps, *ops;
-
- // find the previous frame to interpolate from
- ps = &cl.frame.playerstate;
- i = (cl.frame.serverframe - 1) & UPDATE_MASK;
- oldframe = &cl.frames[i];
- if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid)
- oldframe = &cl.frame; // previous frame was dropped or involid
- ops = &oldframe->playerstate;
-
- // see if the player entity was teleported this frame
- if ( fabs(ops->pmove.origin[0] - ps->pmove.origin[0]) > 256*8
- || abs(ops->pmove.origin[1] - ps->pmove.origin[1]) > 256*8
- || abs(ops->pmove.origin[2] - ps->pmove.origin[2]) > 256*8)
- ops = ps; // don't interpolate
-
- lerp = cl.lerpfrac;
-
- // calculate the origin
- if ((cl_predict->value) && !(cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
- { // use predicted values
- unsigned delta;
-
- backlerp = 1.0 - lerp;
- for (i=0 ; i<3 ; i++)
- {
- cl.refdef.vieworg[i] = cl.predicted_origin[i] + ops->viewoffset[i]
- + cl.lerpfrac * (ps->viewoffset[i] - ops->viewoffset[i])
- - backlerp * cl.prediction_error[i];
- }
-
- // smooth out stair climbing
- delta = cls.realtime - cl.predicted_step_time;
- if (delta < 100)
- cl.refdef.vieworg[2] -= cl.predicted_step * (100 - delta) * 0.01;
- }
- else
- { // just use interpolated values
- for (i=0 ; i<3 ; i++)
- cl.refdef.vieworg[i] = ops->pmove.origin[i]*0.125 + ops->viewoffset[i]
- + lerp * (ps->pmove.origin[i]*0.125 + ps->viewoffset[i]
- - (ops->pmove.origin[i]*0.125 + ops->viewoffset[i]) );
- }
-
- // if not running a demo or on a locked frame, add the local angle movement
- if ( cl.frame.playerstate.pmove.pm_type < PM_DEAD )
- { // use predicted values
- for (i=0 ; i<3 ; i++)
- cl.refdef.viewangles[i] = cl.predicted_angles[i];
- }
- else
- { // just use interpolated values
- for (i=0 ; i<3 ; i++)
- cl.refdef.viewangles[i] = LerpAngle (ops->viewangles[i], ps->viewangles[i], lerp);
- }
-
- for (i=0 ; i<3 ; i++)
- cl.refdef.viewangles[i] += LerpAngle (ops->kick_angles[i], ps->kick_angles[i], lerp);
-
- AngleVectors (cl.refdef.viewangles, cl.v_forward, cl.v_right, cl.v_up);
-
- // interpolate field of view
- cl.refdef.fov_x = ops->fov + lerp * (ps->fov - ops->fov);
-
- // don't interpolate blend color
- for (i=0 ; i<4 ; i++)
- cl.refdef.blend[i] = ps->blend[i];
-
- // add the weapon
- CL_AddViewWeapon (ps, ops);
-}
-
-/*
-===============
-CL_AddEntities
-
-Emits all entities, particles, and lights to the refresh
-===============
-*/
-void CL_AddEntities (void)
-{
- if (cls.state != ca_active)
- return;
-
- if (cl.time > cl.frame.servertime)
- {
- if (cl_showclamp->value)
- Com_Printf ("high clamp %i\n", cl.time - cl.frame.servertime);
- cl.time = cl.frame.servertime;
- cl.lerpfrac = 1.0;
- }
- else if (cl.time < cl.frame.servertime - 100)
- {
- if (cl_showclamp->value)
- Com_Printf ("low clamp %i\n", cl.frame.servertime-100 - cl.time);
- cl.time = cl.frame.servertime - 100;
- cl.lerpfrac = 0;
- }
- else
- cl.lerpfrac = 1.0 - (cl.frame.servertime - cl.time) * 0.01;
-
- if (cl_timedemo->value)
- cl.lerpfrac = 1.0;
-
-// CL_AddPacketEntities (&cl.frame);
-// CL_AddTEnts ();
-// CL_AddParticles ();
-// CL_AddDLights ();
-// CL_AddLightStyles ();
-
- CL_CalcViewValues ();
- // PMM - moved this here so the heat beam has the right values for the vieworg, and can lock the beam to the gun
- CL_AddPacketEntities (&cl.frame);
-/*
- CL_AddProjectiles ();
-*/
- CL_AddTEnts ();
- CL_AddParticles ();
- CL_AddDLights ();
- CL_AddLightStyles ();
-}
-
-
-
-/*
-===============
-CL_GetEntitySoundOrigin
-
-Called to get the sound spatialization origin
-===============
-*/
-void CL_GetEntitySoundOrigin (int ent, vec3_t org)
-{
- centity_t *old;
-
- if (ent < 0 || ent >= MAX_EDICTS)
- Com_Error (ERR_DROP, "CL_GetEntitySoundOrigin: bad ent");
- old = &cl_entities[ent];
- VectorCopy (old->lerp_origin, org);
-
- // FIXME: bmodel issues...
-}
--- a/client/cl_fx.c
+++ /dev/null
@@ -1,2286 +1,0 @@
-// cl_fx.c -- entity effects parsing and management
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-void CL_LogoutEffect (vec3_t org, int type);
-void CL_ItemRespawnParticles (vec3_t org);
-
-static vec3_t avelocities [NUMVERTEXNORMALS];
-
-extern struct model_s *cl_mod_smoke;
-extern struct model_s *cl_mod_flash;
-
-/*
-==============================================================
-
-LIGHT STYLE MANAGEMENT
-
-==============================================================
-*/
-
-typedef struct
-{
- int length;
- float value[3];
- float map[MAX_QPATH];
-} clightstyle_t;
-
-clightstyle_t cl_lightstyle[MAX_LIGHTSTYLES];
-int lastofs;
-
-/*
-================
-CL_ClearLightStyles
-================
-*/
-void CL_ClearLightStyles (void)
-{
- memset (cl_lightstyle, 0, sizeof(cl_lightstyle));
- lastofs = -1;
-}
-
-/*
-================
-CL_RunLightStyles
-================
-*/
-void CL_RunLightStyles (void)
-{
- int ofs;
- int i;
- clightstyle_t *ls;
-
- ofs = cl.time / 100;
- if (ofs == lastofs)
- return;
- lastofs = ofs;
-
- for (i=0,ls=cl_lightstyle ; i<MAX_LIGHTSTYLES ; i++, ls++)
- {
- if (!ls->length)
- {
- ls->value[0] = ls->value[1] = ls->value[2] = 1.0;
- continue;
- }
- if (ls->length == 1)
- ls->value[0] = ls->value[1] = ls->value[2] = ls->map[0];
- else
- ls->value[0] = ls->value[1] = ls->value[2] = ls->map[ofs%ls->length];
- }
-}
-
-
-void CL_SetLightstyle (int i)
-{
- char *s;
- int j, k;
-
- s = cl.configstrings[i+CS_LIGHTS];
-
- j = strlen (s);
- if (j >= MAX_QPATH)
- Com_Error (ERR_DROP, "svc_lightstyle length=%i", j);
-
- cl_lightstyle[i].length = j;
-
- for (k=0 ; k<j ; k++)
- cl_lightstyle[i].map[k] = (float)(s[k]-'a')/(float)('m'-'a');
-}
-
-/*
-================
-CL_AddLightStyles
-================
-*/
-void CL_AddLightStyles (void)
-{
- int i;
- clightstyle_t *ls;
-
- for (i=0,ls=cl_lightstyle ; i<MAX_LIGHTSTYLES ; i++, ls++)
- V_AddLightStyle (i, ls->value[0], ls->value[1], ls->value[2]);
-}
-
-/*
-==============================================================
-
-DLIGHT MANAGEMENT
-
-==============================================================
-*/
-
-cdlight_t cl_dlights[MAX_DLIGHTS];
-
-/*
-================
-CL_ClearDlights
-================
-*/
-void CL_ClearDlights (void)
-{
- memset (cl_dlights, 0, sizeof(cl_dlights));
-}
-
-/*
-===============
-CL_AllocDlight
-
-===============
-*/
-cdlight_t *CL_AllocDlight (int key)
-{
- int i;
- cdlight_t *dl;
-
-// first look for an exact key match
- if (key)
- {
- dl = cl_dlights;
- for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
- {
- if (dl->key == key)
- {
- memset (dl, 0, sizeof(*dl));
- dl->key = key;
- return dl;
- }
- }
- }
-
-// then look for anything else
- dl = cl_dlights;
- for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
- {
- if (dl->die < cl.time)
- {
- memset (dl, 0, sizeof(*dl));
- dl->key = key;
- return dl;
- }
- }
-
- dl = &cl_dlights[0];
- memset (dl, 0, sizeof(*dl));
- dl->key = key;
- return dl;
-}
-
-/*
-===============
-CL_NewDlight
-===============
-*/
-void CL_NewDlight (int key, float x, float y, float z, float radius, float time)
-{
- cdlight_t *dl;
-
- dl = CL_AllocDlight (key);
- dl->origin[0] = x;
- dl->origin[1] = y;
- dl->origin[2] = z;
- dl->radius = radius;
- dl->die = cl.time + time;
-}
-
-
-/*
-===============
-CL_RunDLights
-
-===============
-*/
-void CL_RunDLights (void)
-{
- int i;
- cdlight_t *dl;
-
- dl = cl_dlights;
- for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
- {
- if (!dl->radius)
- continue;
-
- if (dl->die < cl.time)
- {
- dl->radius = 0;
- return;
- }
- dl->radius -= cls.frametime*dl->decay;
- if (dl->radius < 0)
- dl->radius = 0;
- }
-}
-
-/*
-==============
-CL_ParseMuzzleFlash
-==============
-*/
-void CL_ParseMuzzleFlash (void)
-{
- vec3_t fv, rv;
- cdlight_t *dl;
- int i, weapon;
- centity_t *pl;
- int silenced;
- float volume;
- char soundname[64];
-
- i = MSG_ReadShort (&net_message);
- if (i < 1 || i >= MAX_EDICTS)
- Com_Error (ERR_DROP, "CL_ParseMuzzleFlash: bad entity");
-
- weapon = MSG_ReadByte (&net_message);
- silenced = weapon & MZ_SILENCED;
- weapon &= ~MZ_SILENCED;
-
- pl = &cl_entities[i];
-
- dl = CL_AllocDlight (i);
- VectorCopy (pl->current.origin, dl->origin);
- AngleVectors (pl->current.angles, fv, rv, NULL);
- VectorMA (dl->origin, 18, fv, dl->origin);
- VectorMA (dl->origin, 16, rv, dl->origin);
- if (silenced)
- dl->radius = 100 + (rand()&31);
- else
- dl->radius = 200 + (rand()&31);
- dl->minlight = 32;
- dl->die = cl.time; // + 0.1;
-
- if (silenced)
- volume = 0.2;
- else
- volume = 1;
-
- switch (weapon)
- {
- case MZ_BLASTER:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0);
- break;
- case MZ_BLUEHYPERBLASTER:
- dl->color[0] = 0;dl->color[1] = 0;dl->color[2] = 1;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0);
- break;
- case MZ_HYPERBLASTER:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0);
- break;
- case MZ_MACHINEGUN:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
- break;
- case MZ_SHOTGUN:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/shotgf1b.wav"), volume, ATTN_NORM, 0);
- S_StartSound (NULL, i, CHAN_AUTO, S_RegisterSound("weapons/shotgr1b.wav"), volume, ATTN_NORM, 0.1);
- break;
- case MZ_SSHOTGUN:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/sshotf1b.wav"), volume, ATTN_NORM, 0);
- break;
- case MZ_CHAINGUN1:
- dl->radius = 200 + (rand()&31);
- dl->color[0] = 1;dl->color[1] = 0.25;dl->color[2] = 0;
- Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
- break;
- case MZ_CHAINGUN2:
- dl->radius = 225 + (rand()&31);
- dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0;
- dl->die = cl.time + 0.1; // long delay
- Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
- Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.05);
- break;
- case MZ_CHAINGUN3:
- dl->radius = 250 + (rand()&31);
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- dl->die = cl.time + 0.1; // long delay
- Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
- Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.033);
- Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.066);
- break;
- case MZ_RAILGUN:
- dl->color[0] = 0.5;dl->color[1] = 0.5;dl->color[2] = 1.0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/railgf1a.wav"), volume, ATTN_NORM, 0);
- break;
- case MZ_ROCKET:
- dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/rocklf1a.wav"), volume, ATTN_NORM, 0);
- S_StartSound (NULL, i, CHAN_AUTO, S_RegisterSound("weapons/rocklr1b.wav"), volume, ATTN_NORM, 0.1);
- break;
- case MZ_GRENADE:
- dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), volume, ATTN_NORM, 0);
- S_StartSound (NULL, i, CHAN_AUTO, S_RegisterSound("weapons/grenlr1b.wav"), volume, ATTN_NORM, 0.1);
- break;
- case MZ_BFG:
- dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/bfg__f1y.wav"), volume, ATTN_NORM, 0);
- break;
-
- case MZ_LOGIN:
- dl->color[0] = 0;dl->color[1] = 1; dl->color[2] = 0;
- dl->die = cl.time + 1.0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
- CL_LogoutEffect (pl->current.origin, weapon);
- break;
- case MZ_LOGOUT:
- dl->color[0] = 1;dl->color[1] = 0; dl->color[2] = 0;
- dl->die = cl.time + 1.0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
- CL_LogoutEffect (pl->current.origin, weapon);
- break;
- case MZ_RESPAWN:
- dl->color[0] = 1;dl->color[1] = 1; dl->color[2] = 0;
- dl->die = cl.time + 1.0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
- CL_LogoutEffect (pl->current.origin, weapon);
- break;
- // RAFAEL
- case MZ_PHALANX:
- dl->color[0] = 1;dl->color[1] = 0.5; dl->color[2] = 0.5;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/plasshot.wav"), volume, ATTN_NORM, 0);
- break;
- // RAFAEL
- case MZ_IONRIPPER:
- dl->color[0] = 1;dl->color[1] = 0.5; dl->color[2] = 0.5;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/rippfire.wav"), volume, ATTN_NORM, 0);
- break;
-
-// ======================
-// PGM
- case MZ_ETF_RIFLE:
- dl->color[0] = 0.9;dl->color[1] = 0.7;dl->color[2] = 0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/nail1.wav"), volume, ATTN_NORM, 0);
- break;
- case MZ_SHOTGUN2:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/shotg2.wav"), volume, ATTN_NORM, 0);
- break;
- case MZ_HEATBEAM:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- dl->die = cl.time + 100;
-// S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/bfg__l1a.wav"), volume, ATTN_NORM, 0);
- break;
- case MZ_BLASTER2:
- dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0;
- // FIXME - different sound for blaster2 ??
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0);
- break;
- case MZ_TRACKER:
- // negative flashes handled the same in gl/soft until CL_AddDLights
- dl->color[0] = -1;dl->color[1] = -1;dl->color[2] = -1;
- S_StartSound (NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/disint2.wav"), volume, ATTN_NORM, 0);
- break;
- case MZ_NUKE1:
- dl->color[0] = 1;dl->color[1] = 0;dl->color[2] = 0;
- dl->die = cl.time + 100;
- break;
- case MZ_NUKE2:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- dl->die = cl.time + 100;
- break;
- case MZ_NUKE4:
- dl->color[0] = 0;dl->color[1] = 0;dl->color[2] = 1;
- dl->die = cl.time + 100;
- break;
- case MZ_NUKE8:
- dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 1;
- dl->die = cl.time + 100;
- break;
-// PGM
-// ======================
- }
-}
-
-
-/*
-==============
-CL_ParseMuzzleFlash2
-==============
-*/
-void CL_ParseMuzzleFlash2 (void)
-{
- int ent;
- vec3_t origin;
- int flash_number;
- cdlight_t *dl;
- vec3_t forward, right;
- char soundname[64];
-
- ent = MSG_ReadShort (&net_message);
- if (ent < 1 || ent >= MAX_EDICTS)
- Com_Error (ERR_DROP, "CL_ParseMuzzleFlash2: bad entity");
-
- flash_number = MSG_ReadByte (&net_message);
-
- // locate the origin
- AngleVectors (cl_entities[ent].current.angles, forward, right, NULL);
- origin[0] = cl_entities[ent].current.origin[0] + forward[0] * monster_flash_offset[flash_number][0] + right[0] * monster_flash_offset[flash_number][1];
- origin[1] = cl_entities[ent].current.origin[1] + forward[1] * monster_flash_offset[flash_number][0] + right[1] * monster_flash_offset[flash_number][1];
- origin[2] = cl_entities[ent].current.origin[2] + forward[2] * monster_flash_offset[flash_number][0] + right[2] * monster_flash_offset[flash_number][1] + monster_flash_offset[flash_number][2];
-
- dl = CL_AllocDlight (ent);
- VectorCopy (origin, dl->origin);
- dl->radius = 200 + (rand()&31);
- dl->minlight = 32;
- dl->die = cl.time; // + 0.1;
-
- switch (flash_number)
- {
- case MZ2_INFANTRY_MACHINEGUN_1:
- case MZ2_INFANTRY_MACHINEGUN_2:
- case MZ2_INFANTRY_MACHINEGUN_3:
- case MZ2_INFANTRY_MACHINEGUN_4:
- case MZ2_INFANTRY_MACHINEGUN_5:
- case MZ2_INFANTRY_MACHINEGUN_6:
- case MZ2_INFANTRY_MACHINEGUN_7:
- case MZ2_INFANTRY_MACHINEGUN_8:
- case MZ2_INFANTRY_MACHINEGUN_9:
- case MZ2_INFANTRY_MACHINEGUN_10:
- case MZ2_INFANTRY_MACHINEGUN_11:
- case MZ2_INFANTRY_MACHINEGUN_12:
- case MZ2_INFANTRY_MACHINEGUN_13:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- CL_ParticleEffect (origin, vec3_origin, 0, 40);
- CL_SmokeAndFlash(origin);
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_SOLDIER_MACHINEGUN_1:
- case MZ2_SOLDIER_MACHINEGUN_2:
- case MZ2_SOLDIER_MACHINEGUN_3:
- case MZ2_SOLDIER_MACHINEGUN_4:
- case MZ2_SOLDIER_MACHINEGUN_5:
- case MZ2_SOLDIER_MACHINEGUN_6:
- case MZ2_SOLDIER_MACHINEGUN_7:
- case MZ2_SOLDIER_MACHINEGUN_8:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- CL_ParticleEffect (origin, vec3_origin, 0, 40);
- CL_SmokeAndFlash(origin);
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck3.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_GUNNER_MACHINEGUN_1:
- case MZ2_GUNNER_MACHINEGUN_2:
- case MZ2_GUNNER_MACHINEGUN_3:
- case MZ2_GUNNER_MACHINEGUN_4:
- case MZ2_GUNNER_MACHINEGUN_5:
- case MZ2_GUNNER_MACHINEGUN_6:
- case MZ2_GUNNER_MACHINEGUN_7:
- case MZ2_GUNNER_MACHINEGUN_8:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- CL_ParticleEffect (origin, vec3_origin, 0, 40);
- CL_SmokeAndFlash(origin);
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("gunner/gunatck2.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_ACTOR_MACHINEGUN_1:
- case MZ2_SUPERTANK_MACHINEGUN_1:
- case MZ2_SUPERTANK_MACHINEGUN_2:
- case MZ2_SUPERTANK_MACHINEGUN_3:
- case MZ2_SUPERTANK_MACHINEGUN_4:
- case MZ2_SUPERTANK_MACHINEGUN_5:
- case MZ2_SUPERTANK_MACHINEGUN_6:
- case MZ2_TURRET_MACHINEGUN: // PGM
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-
- CL_ParticleEffect (origin, vec3_origin, 0, 40);
- CL_SmokeAndFlash(origin);
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_BOSS2_MACHINEGUN_L1:
- case MZ2_BOSS2_MACHINEGUN_L2:
- case MZ2_BOSS2_MACHINEGUN_L3:
- case MZ2_BOSS2_MACHINEGUN_L4:
- case MZ2_BOSS2_MACHINEGUN_L5:
- case MZ2_CARRIER_MACHINEGUN_L1: // PMM
- case MZ2_CARRIER_MACHINEGUN_L2: // PMM
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-
- CL_ParticleEffect (origin, vec3_origin, 0, 40);
- CL_SmokeAndFlash(origin);
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NONE, 0);
- break;
-
- case MZ2_SOLDIER_BLASTER_1:
- case MZ2_SOLDIER_BLASTER_2:
- case MZ2_SOLDIER_BLASTER_3:
- case MZ2_SOLDIER_BLASTER_4:
- case MZ2_SOLDIER_BLASTER_5:
- case MZ2_SOLDIER_BLASTER_6:
- case MZ2_SOLDIER_BLASTER_7:
- case MZ2_SOLDIER_BLASTER_8:
- case MZ2_TURRET_BLASTER: // PGM
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck2.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_FLYER_BLASTER_1:
- case MZ2_FLYER_BLASTER_2:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("flyer/flyatck3.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_MEDIC_BLASTER_1:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("medic/medatck1.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_HOVER_BLASTER_1:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("hover/hovatck1.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_FLOAT_BLASTER_1:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("floater/fltatck1.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_SOLDIER_SHOTGUN_1:
- case MZ2_SOLDIER_SHOTGUN_2:
- case MZ2_SOLDIER_SHOTGUN_3:
- case MZ2_SOLDIER_SHOTGUN_4:
- case MZ2_SOLDIER_SHOTGUN_5:
- case MZ2_SOLDIER_SHOTGUN_6:
- case MZ2_SOLDIER_SHOTGUN_7:
- case MZ2_SOLDIER_SHOTGUN_8:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- CL_SmokeAndFlash(origin);
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck1.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_TANK_BLASTER_1:
- case MZ2_TANK_BLASTER_2:
- case MZ2_TANK_BLASTER_3:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_TANK_MACHINEGUN_1:
- case MZ2_TANK_MACHINEGUN_2:
- case MZ2_TANK_MACHINEGUN_3:
- case MZ2_TANK_MACHINEGUN_4:
- case MZ2_TANK_MACHINEGUN_5:
- case MZ2_TANK_MACHINEGUN_6:
- case MZ2_TANK_MACHINEGUN_7:
- case MZ2_TANK_MACHINEGUN_8:
- case MZ2_TANK_MACHINEGUN_9:
- case MZ2_TANK_MACHINEGUN_10:
- case MZ2_TANK_MACHINEGUN_11:
- case MZ2_TANK_MACHINEGUN_12:
- case MZ2_TANK_MACHINEGUN_13:
- case MZ2_TANK_MACHINEGUN_14:
- case MZ2_TANK_MACHINEGUN_15:
- case MZ2_TANK_MACHINEGUN_16:
- case MZ2_TANK_MACHINEGUN_17:
- case MZ2_TANK_MACHINEGUN_18:
- case MZ2_TANK_MACHINEGUN_19:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- CL_ParticleEffect (origin, vec3_origin, 0, 40);
- CL_SmokeAndFlash(origin);
- Com_sprintf(soundname, sizeof(soundname), "tank/tnkatk2%c.wav", 'a' + rand() % 5);
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound(soundname), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_CHICK_ROCKET_1:
- case MZ2_TURRET_ROCKET: // PGM
- dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("chick/chkatck2.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_TANK_ROCKET_1:
- case MZ2_TANK_ROCKET_2:
- case MZ2_TANK_ROCKET_3:
- dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck1.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_SUPERTANK_ROCKET_1:
- case MZ2_SUPERTANK_ROCKET_2:
- case MZ2_SUPERTANK_ROCKET_3:
- case MZ2_BOSS2_ROCKET_1:
- case MZ2_BOSS2_ROCKET_2:
- case MZ2_BOSS2_ROCKET_3:
- case MZ2_BOSS2_ROCKET_4:
- case MZ2_CARRIER_ROCKET_1:
-// case MZ2_CARRIER_ROCKET_2:
-// case MZ2_CARRIER_ROCKET_3:
-// case MZ2_CARRIER_ROCKET_4:
- dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0.2;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/rocket.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_GUNNER_GRENADE_1:
- case MZ2_GUNNER_GRENADE_2:
- case MZ2_GUNNER_GRENADE_3:
- case MZ2_GUNNER_GRENADE_4:
- dl->color[0] = 1;dl->color[1] = 0.5;dl->color[2] = 0;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("gunner/gunatck3.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_GLADIATOR_RAILGUN_1:
- // PMM
- case MZ2_CARRIER_RAILGUN:
- case MZ2_WIDOW_RAIL:
- // pmm
- dl->color[0] = 0.5;dl->color[1] = 0.5;dl->color[2] = 1.0;
- break;
-
-// --- Xian's shit starts ---
- case MZ2_MAKRON_BFG:
- dl->color[0] = 0.5;dl->color[1] = 1 ;dl->color[2] = 0.5;
- //S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("makron/bfg_fire.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_MAKRON_BLASTER_1:
- case MZ2_MAKRON_BLASTER_2:
- case MZ2_MAKRON_BLASTER_3:
- case MZ2_MAKRON_BLASTER_4:
- case MZ2_MAKRON_BLASTER_5:
- case MZ2_MAKRON_BLASTER_6:
- case MZ2_MAKRON_BLASTER_7:
- case MZ2_MAKRON_BLASTER_8:
- case MZ2_MAKRON_BLASTER_9:
- case MZ2_MAKRON_BLASTER_10:
- case MZ2_MAKRON_BLASTER_11:
- case MZ2_MAKRON_BLASTER_12:
- case MZ2_MAKRON_BLASTER_13:
- case MZ2_MAKRON_BLASTER_14:
- case MZ2_MAKRON_BLASTER_15:
- case MZ2_MAKRON_BLASTER_16:
- case MZ2_MAKRON_BLASTER_17:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("makron/blaster.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_JORG_MACHINEGUN_L1:
- case MZ2_JORG_MACHINEGUN_L2:
- case MZ2_JORG_MACHINEGUN_L3:
- case MZ2_JORG_MACHINEGUN_L4:
- case MZ2_JORG_MACHINEGUN_L5:
- case MZ2_JORG_MACHINEGUN_L6:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- CL_ParticleEffect (origin, vec3_origin, 0, 40);
- CL_SmokeAndFlash(origin);
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("boss3/xfire.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_JORG_MACHINEGUN_R1:
- case MZ2_JORG_MACHINEGUN_R2:
- case MZ2_JORG_MACHINEGUN_R3:
- case MZ2_JORG_MACHINEGUN_R4:
- case MZ2_JORG_MACHINEGUN_R5:
- case MZ2_JORG_MACHINEGUN_R6:
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- CL_ParticleEffect (origin, vec3_origin, 0, 40);
- CL_SmokeAndFlash(origin);
- break;
-
- case MZ2_JORG_BFG_1:
- dl->color[0] = 0.5;dl->color[1] = 1 ;dl->color[2] = 0.5;
- break;
-
- case MZ2_BOSS2_MACHINEGUN_R1:
- case MZ2_BOSS2_MACHINEGUN_R2:
- case MZ2_BOSS2_MACHINEGUN_R3:
- case MZ2_BOSS2_MACHINEGUN_R4:
- case MZ2_BOSS2_MACHINEGUN_R5:
- case MZ2_CARRIER_MACHINEGUN_R1: // PMM
- case MZ2_CARRIER_MACHINEGUN_R2: // PMM
-
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
-
- CL_ParticleEffect (origin, vec3_origin, 0, 40);
- CL_SmokeAndFlash(origin);
- break;
-
-// ======
-// ROGUE
- case MZ2_STALKER_BLASTER:
- case MZ2_DAEDALUS_BLASTER:
- case MZ2_MEDIC_BLASTER_2:
- case MZ2_WIDOW_BLASTER:
- case MZ2_WIDOW_BLASTER_SWEEP1:
- case MZ2_WIDOW_BLASTER_SWEEP2:
- case MZ2_WIDOW_BLASTER_SWEEP3:
- case MZ2_WIDOW_BLASTER_SWEEP4:
- case MZ2_WIDOW_BLASTER_SWEEP5:
- case MZ2_WIDOW_BLASTER_SWEEP6:
- case MZ2_WIDOW_BLASTER_SWEEP7:
- case MZ2_WIDOW_BLASTER_SWEEP8:
- case MZ2_WIDOW_BLASTER_SWEEP9:
- case MZ2_WIDOW_BLASTER_100:
- case MZ2_WIDOW_BLASTER_90:
- case MZ2_WIDOW_BLASTER_80:
- case MZ2_WIDOW_BLASTER_70:
- case MZ2_WIDOW_BLASTER_60:
- case MZ2_WIDOW_BLASTER_50:
- case MZ2_WIDOW_BLASTER_40:
- case MZ2_WIDOW_BLASTER_30:
- case MZ2_WIDOW_BLASTER_20:
- case MZ2_WIDOW_BLASTER_10:
- case MZ2_WIDOW_BLASTER_0:
- case MZ2_WIDOW_BLASTER_10L:
- case MZ2_WIDOW_BLASTER_20L:
- case MZ2_WIDOW_BLASTER_30L:
- case MZ2_WIDOW_BLASTER_40L:
- case MZ2_WIDOW_BLASTER_50L:
- case MZ2_WIDOW_BLASTER_60L:
- case MZ2_WIDOW_BLASTER_70L:
- case MZ2_WIDOW_RUN_1:
- case MZ2_WIDOW_RUN_2:
- case MZ2_WIDOW_RUN_3:
- case MZ2_WIDOW_RUN_4:
- case MZ2_WIDOW_RUN_5:
- case MZ2_WIDOW_RUN_6:
- case MZ2_WIDOW_RUN_7:
- case MZ2_WIDOW_RUN_8:
- dl->color[0] = 0;dl->color[1] = 1;dl->color[2] = 0;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_WIDOW_DISRUPTOR:
- dl->color[0] = -1;dl->color[1] = -1;dl->color[2] = -1;
- S_StartSound (NULL, ent, CHAN_WEAPON, S_RegisterSound("weapons/disint2.wav"), 1, ATTN_NORM, 0);
- break;
-
- case MZ2_WIDOW_PLASMABEAM:
- case MZ2_WIDOW2_BEAMER_1:
- case MZ2_WIDOW2_BEAMER_2:
- case MZ2_WIDOW2_BEAMER_3:
- case MZ2_WIDOW2_BEAMER_4:
- case MZ2_WIDOW2_BEAMER_5:
- case MZ2_WIDOW2_BEAM_SWEEP_1:
- case MZ2_WIDOW2_BEAM_SWEEP_2:
- case MZ2_WIDOW2_BEAM_SWEEP_3:
- case MZ2_WIDOW2_BEAM_SWEEP_4:
- case MZ2_WIDOW2_BEAM_SWEEP_5:
- case MZ2_WIDOW2_BEAM_SWEEP_6:
- case MZ2_WIDOW2_BEAM_SWEEP_7:
- case MZ2_WIDOW2_BEAM_SWEEP_8:
- case MZ2_WIDOW2_BEAM_SWEEP_9:
- case MZ2_WIDOW2_BEAM_SWEEP_10:
- case MZ2_WIDOW2_BEAM_SWEEP_11:
- dl->radius = 300 + (rand()&100);
- dl->color[0] = 1;dl->color[1] = 1;dl->color[2] = 0;
- dl->die = cl.time + 200;
- break;
-// ROGUE
-// ======
-
-// --- Xian's shit ends ---
-
- }
-}
-
-
-/*
-===============
-CL_AddDLights
-
-===============
-*/
-void CL_AddDLights (void)
-{
- int i;
- cdlight_t *dl;
-
- dl = cl_dlights;
-
-//=====
-//PGM
- if(vidref_val == VIDREF_GL)
- {
- for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
- {
- if (!dl->radius)
- continue;
- V_AddLight (dl->origin, dl->radius,
- dl->color[0], dl->color[1], dl->color[2]);
- }
- }
- else
- {
- for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
- {
- if (!dl->radius)
- continue;
-
- // negative light in software. only black allowed
- if ((dl->color[0] < 0) || (dl->color[1] < 0) || (dl->color[2] < 0))
- {
- dl->radius = -(dl->radius);
- dl->color[0] = 1;
- dl->color[1] = 1;
- dl->color[2] = 1;
- }
- V_AddLight (dl->origin, dl->radius,
- dl->color[0], dl->color[1], dl->color[2]);
- }
- }
-//PGM
-//=====
-}
-
-
-
-/*
-==============================================================
-
-PARTICLE MANAGEMENT
-
-==============================================================
-*/
-
-/*
-// THIS HAS BEEN RELOCATED TO CLIENT.H
-typedef struct particle_s
-{
- struct particle_s *next;
-
- float time;
-
- vec3_t org;
- vec3_t vel;
- vec3_t accel;
- float color;
- float colorvel;
- float alpha;
- float alphavel;
-} cparticle_t;
-
-
-#define PARTICLE_GRAVITY 40
-*/
-
-cparticle_t *active_particles, *free_particles;
-
-cparticle_t particles[MAX_PARTICLES];
-int cl_numparticles = MAX_PARTICLES;
-
-
-/*
-===============
-CL_ClearParticles
-===============
-*/
-void CL_ClearParticles (void)
-{
- int i;
-
- free_particles = &particles[0];
- active_particles = NULL;
-
- for (i=0 ;i<cl_numparticles ; i++)
- particles[i].next = &particles[i+1];
- particles[cl_numparticles-1].next = NULL;
-}
-
-
-/*
-===============
-CL_ParticleEffect
-
-Wall impact puffs
-===============
-*/
-void CL_ParticleEffect (vec3_t org, vec3_t dir, int color, int count)
-{
- int i, j;
- cparticle_t *p;
- float d;
-
- for (i=0 ; i<count ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = color + (rand()&7);
-
- d = rand()&31;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
- p->vel[j] = crand()*20;
- }
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
- }
-}
-
-
-/*
-===============
-CL_ParticleEffect2
-===============
-*/
-void CL_ParticleEffect2 (vec3_t org, vec3_t dir, int color, int count)
-{
- int i, j;
- cparticle_t *p;
- float d;
-
- for (i=0 ; i<count ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = color;
-
- d = rand()&7;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
- p->vel[j] = crand()*20;
- }
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
- }
-}
-
-
-// RAFAEL
-/*
-===============
-CL_ParticleEffect3
-===============
-*/
-void CL_ParticleEffect3 (vec3_t org, vec3_t dir, int color, int count)
-{
- int i, j;
- cparticle_t *p;
- float d;
-
- for (i=0 ; i<count ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = color;
-
- d = rand()&7;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
- p->vel[j] = crand()*20;
- }
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = PARTICLE_GRAVITY;
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
- }
-}
-
-/*
-===============
-CL_TeleporterParticles
-===============
-*/
-void CL_TeleporterParticles (entity_state_t *ent)
-{
- int i, j;
- cparticle_t *p;
-
- for (i=0 ; i<8 ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = 0xdb;
-
- for (j=0 ; j<2 ; j++)
- {
- p->org[j] = ent->origin[j] - 16 + (rand()&31);
- p->vel[j] = crand()*14;
- }
-
- p->org[2] = ent->origin[2] - 8 + (rand()&7);
- p->vel[2] = 80 + (rand()&7);
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- p->alpha = 1.0;
-
- p->alphavel = -0.5;
- }
-}
-
-
-/*
-===============
-CL_LogoutEffect
-
-===============
-*/
-void CL_LogoutEffect (vec3_t org, int type)
-{
- int i, j;
- cparticle_t *p;
-
- for (i=0 ; i<500 ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
-
- if (type == MZ_LOGIN)
- p->color = 0xd0 + (rand()&7); // green
- else if (type == MZ_LOGOUT)
- p->color = 0x40 + (rand()&7); // red
- else
- p->color = 0xe0 + (rand()&7); // yellow
-
- p->org[0] = org[0] - 16 + qfrand()*32;
- p->org[1] = org[1] - 16 + qfrand()*32;
- p->org[2] = org[2] - 24 + qfrand()*56;
-
- for (j=0 ; j<3 ; j++)
- p->vel[j] = crand()*20;
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (1.0 + qfrand()*0.3);
- }
-}
-
-
-/*
-===============
-CL_ItemRespawnParticles
-
-===============
-*/
-void CL_ItemRespawnParticles (vec3_t org)
-{
- int i, j;
- cparticle_t *p;
-
- for (i=0 ; i<64 ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
-
- p->color = 0xd4 + (rand()&3); // green
-
- p->org[0] = org[0] + crand()*8;
- p->org[1] = org[1] + crand()*8;
- p->org[2] = org[2] + crand()*8;
-
- for (j=0 ; j<3 ; j++)
- p->vel[j] = crand()*8;
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY*0.2;
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (1.0 + qfrand()*0.3);
- }
-}
-
-
-/*
-===============
-CL_ExplosionParticles
-===============
-*/
-void CL_ExplosionParticles (vec3_t org)
-{
- int i, j;
- cparticle_t *p;
-
- for (i=0 ; i<256 ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = 0xe0 + (rand()&7);
-
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + ((rand()%32)-16);
- p->vel[j] = (rand()%384)-192;
- }
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- p->alpha = 1.0;
-
- p->alphavel = -0.8 / (0.5 + qfrand()*0.3);
- }
-}
-
-
-/*
-===============
-CL_BigTeleportParticles
-===============
-*/
-void CL_BigTeleportParticles (vec3_t org)
-{
- int i;
- cparticle_t *p;
- float angle, dist;
- static int colortable[4] = {2*8,13*8,21*8,18*8};
-
- for (i=0 ; i<4096 ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
-
- p->color = colortable[rand()&3];
-
- angle = M_PI*2*(rand()&1023)/1023.0;
- dist = rand()&31;
- p->org[0] = org[0] + cos(angle)*dist;
- p->vel[0] = cos(angle)*(70+(rand()&63));
- p->accel[0] = -cos(angle)*100;
-
- p->org[1] = org[1] + sin(angle)*dist;
- p->vel[1] = sin(angle)*(70+(rand()&63));
- p->accel[1] = -sin(angle)*100;
-
- p->org[2] = org[2] + 8 + (rand()%90);
- p->vel[2] = -100 + (rand()&31);
- p->accel[2] = PARTICLE_GRAVITY*4;
- p->alpha = 1.0;
-
- p->alphavel = -0.3 / (0.5 + qfrand()*0.3);
- }
-}
-
-
-/*
-===============
-CL_BlasterParticles
-
-Wall impact puffs
-===============
-*/
-void CL_BlasterParticles (vec3_t org, vec3_t dir)
-{
- int i, j;
- cparticle_t *p;
- float d;
- int count;
-
- count = 40;
- for (i=0 ; i<count ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = 0xe0 + (rand()&7);
-
- d = rand()&15;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
- p->vel[j] = dir[j] * 30 + crand()*40;
- }
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
- }
-}
-
-
-/*
-===============
-CL_BlasterTrail
-
-===============
-*/
-void CL_BlasterTrail (vec3_t start, vec3_t end)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- int dec;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- dec = 5;
- VectorScale (vec, 5, vec);
-
- // FIXME: this is a really silly way to have a loop
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (0.3+qfrand()*0.2);
- p->color = 0xe0;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand();
- p->vel[j] = crand()*5;
- p->accel[j] = 0;
- }
-
- VectorAdd (move, vec, move);
- }
-}
-
-/*
-===============
-CL_QuadTrail
-
-===============
-*/
-void CL_QuadTrail (vec3_t start, vec3_t end)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- int dec;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- dec = 5;
- VectorScale (vec, 5, vec);
-
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (0.8+qfrand()*0.2);
- p->color = 115;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*16;
- p->vel[j] = crand()*5;
- p->accel[j] = 0;
- }
-
- VectorAdd (move, vec, move);
- }
-}
-
-/*
-===============
-CL_FlagTrail
-
-===============
-*/
-void CL_FlagTrail (vec3_t start, vec3_t end, float color)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- int dec;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- dec = 5;
- VectorScale (vec, 5, vec);
-
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (0.8+qfrand()*0.2);
- p->color = color;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*16;
- p->vel[j] = crand()*5;
- p->accel[j] = 0;
- }
-
- VectorAdd (move, vec, move);
- }
-}
-
-/*
-===============
-CL_DiminishingTrail
-
-===============
-*/
-void CL_DiminishingTrail (vec3_t start, vec3_t end, centity_t *old, int flags)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- float dec;
- float orgscale;
- float velscale;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- dec = 0.5;
- VectorScale (vec, dec, vec);
-
- if (old->trailcount > 900)
- {
- orgscale = 4;
- velscale = 15;
- }
- else if (old->trailcount > 800)
- {
- orgscale = 2;
- velscale = 10;
- }
- else
- {
- orgscale = 1;
- velscale = 5;
- }
-
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
-
- // drop less particles as it flies
- if ((rand()&1023) < old->trailcount)
- {
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- if (flags & EF_GIB)
- {
- p->alpha = 1.0;
- p->alphavel = -1.0 / (1+qfrand()*0.4);
- p->color = 0xe8 + (rand()&7);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*orgscale;
- p->vel[j] = crand()*velscale;
- p->accel[j] = 0;
- }
- p->vel[2] -= PARTICLE_GRAVITY;
- }
- else if (flags & EF_GREENGIB)
- {
- p->alpha = 1.0;
- p->alphavel = -1.0 / (1+qfrand()*0.4);
- p->color = 0xdb + (rand()&7);
- for (j=0; j< 3; j++)
- {
- p->org[j] = move[j] + crand()*orgscale;
- p->vel[j] = crand()*velscale;
- p->accel[j] = 0;
- }
- p->vel[2] -= PARTICLE_GRAVITY;
- }
- else
- {
- p->alpha = 1.0;
- p->alphavel = -1.0 / (1+qfrand()*0.2);
- p->color = 4 + (rand()&7);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*orgscale;
- p->vel[j] = crand()*velscale;
- }
- p->accel[2] = 20;
- }
- }
-
- old->trailcount -= 5;
- if (old->trailcount < 100)
- old->trailcount = 100;
- VectorAdd (move, vec, move);
- }
-}
-
-void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up)
-{
- float d;
-
- // this rotate and negat guarantees a vector
- // not colinear with the original
- right[1] = -forward[0];
- right[2] = forward[1];
- right[0] = forward[2];
-
- d = DotProduct (right, forward);
- VectorMA (right, -d, forward, right);
- VectorNormalize (right);
- CrossProduct (right, forward, up);
-}
-
-/*
-===============
-CL_RocketTrail
-
-===============
-*/
-void CL_RocketTrail (vec3_t start, vec3_t end, centity_t *old)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- float dec;
-
- // smoke
- CL_DiminishingTrail (start, end, old, EF_ROCKET);
-
- // fire
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- dec = 1;
- VectorScale (vec, dec, vec);
-
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
-
- if ( (rand()&7) == 0)
- {
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- VectorClear (p->accel);
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (1+qfrand()*0.2);
- p->color = 0xdc + (rand()&3);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*5;
- p->vel[j] = crand()*20;
- }
- p->accel[2] = -PARTICLE_GRAVITY;
- }
- VectorAdd (move, vec, move);
- }
-}
-
-/*
-===============
-CL_RailTrail
-
-===============
-*/
-void CL_RailTrail (vec3_t start, vec3_t end)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- float dec;
- vec3_t right, up;
- int i;
- float d, c, s;
- vec3_t dir;
- byte clr = 0x74;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- MakeNormalVectors (vec, right, up);
-
- for (i=0 ; i<len ; i++)
- {
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- VectorClear (p->accel);
-
- d = i * 0.1;
- c = cos(d);
- s = sin(d);
-
- VectorScale (right, c, dir);
- VectorMA (dir, s, up, dir);
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (1+qfrand()*0.2);
- p->color = clr + (rand()&7);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + dir[j]*3;
- p->vel[j] = dir[j]*6;
- }
-
- VectorAdd (move, vec, move);
- }
-
- dec = 0.75;
- VectorScale (vec, dec, vec);
- VectorCopy (start, move);
-
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- VectorClear (p->accel);
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (0.6+qfrand()*0.2);
- p->color = 0x0 + rand()&15;
-
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*3;
- p->vel[j] = crand()*3;
- p->accel[j] = 0;
- }
-
- VectorAdd (move, vec, move);
- }
-}
-
-// RAFAEL
-/*
-===============
-CL_IonripperTrail
-===============
-*/
-void CL_IonripperTrail (vec3_t start, vec3_t ent)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- int dec;
- int left = 0;
-
- VectorCopy (start, move);
- VectorSubtract (ent, start, vec);
- len = VectorNormalize (vec);
-
- dec = 5;
- VectorScale (vec, 5, vec);
-
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
- p->alpha = 0.5;
- p->alphavel = -1.0 / (0.3 + qfrand() * 0.2);
- p->color = 0xe4 + (rand()&3);
-
- for (j=0; j<3; j++)
- {
- p->org[j] = move[j];
- p->accel[j] = 0;
- }
- if (left)
- {
- left = 0;
- p->vel[0] = 10;
- }
- else
- {
- left = 1;
- p->vel[0] = -10;
- }
-
- p->vel[1] = 0;
- p->vel[2] = 0;
-
- VectorAdd (move, vec, move);
- }
-}
-
-
-/*
-===============
-CL_BubbleTrail
-
-===============
-*/
-void CL_BubbleTrail (vec3_t start, vec3_t end)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int i, j;
- cparticle_t *p;
- float dec;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- dec = 32;
- VectorScale (vec, dec, vec);
-
- for (i=0 ; i<len ; i+=dec)
- {
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- VectorClear (p->accel);
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (1+qfrand()*0.2);
- p->color = 4 + (rand()&7);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*2;
- p->vel[j] = crand()*5;
- }
- p->vel[2] += 6;
-
- VectorAdd (move, vec, move);
- }
-}
-
-
-/*
-===============
-CL_FlyParticles
-===============
-*/
-
-#define BEAMLENGTH 16
-
-void CL_FlyParticles (vec3_t origin, int count)
-{
- int i;
- cparticle_t *p;
- float angle;
- float sp, sy, cp, cy;
- vec3_t forward;
- float dist;
- float ltime;
-
-
- if (count > NUMVERTEXNORMALS)
- count = NUMVERTEXNORMALS;
-
- if (!avelocities[0][0])
- {
- for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
- avelocities[0][i] = (rand()&255) * 0.01;
- }
-
-
- ltime = (float)cl.time / 1000.0;
- for (i=0 ; i<count ; i+=2)
- {
- angle = ltime * avelocities[i][0];
- sy = sin(angle);
- cy = cos(angle);
- angle = ltime * avelocities[i][1];
- sp = sin(angle);
- cp = cos(angle);
- /*
- angle = ltime * avelocities[i][2];
- sr = sin(angle);
- cr = cos(angle);
- */
-
- forward[0] = cp*cy;
- forward[1] = cp*sy;
- forward[2] = -sp;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
-
- dist = sin(ltime + i)*64;
- p->org[0] = origin[0] + bytedirs[i][0]*dist + forward[0]*BEAMLENGTH;
- p->org[1] = origin[1] + bytedirs[i][1]*dist + forward[1]*BEAMLENGTH;
- p->org[2] = origin[2] + bytedirs[i][2]*dist + forward[2]*BEAMLENGTH;
-
- VectorClear (p->vel);
- VectorClear (p->accel);
-
- p->color = 0;
- p->colorvel = 0;
-
- p->alpha = 1;
- p->alphavel = -100;
- }
-}
-
-void CL_FlyEffect (centity_t *ent, vec3_t origin)
-{
- int n;
- int count;
- int starttime;
-
- if (ent->fly_stoptime < cl.time)
- {
- starttime = cl.time;
- ent->fly_stoptime = cl.time + 60000;
- }
- else
- {
- starttime = ent->fly_stoptime - 60000;
- }
-
- n = cl.time - starttime;
- if (n < 20000)
- count = n * 162 / 20000.0;
- else
- {
- n = ent->fly_stoptime - cl.time;
- if (n < 20000)
- count = n * 162 / 20000.0;
- else
- count = 162;
- }
-
- CL_FlyParticles (origin, count);
-}
-
-
-/*
-===============
-CL_BfgParticles
-===============
-*/
-
-void CL_BfgParticles (entity_t *ent)
-{
- int i;
- cparticle_t *p;
- float angle;
- float sp, sy, cp, cy;
- vec3_t forward;
- float dist;
- vec3_t v;
- float ltime;
-
- if (!avelocities[0][0])
- {
- for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
- avelocities[0][i] = (rand()&255) * 0.01;
- }
-
-
- ltime = (float)cl.time / 1000.0;
- for (i=0 ; i<NUMVERTEXNORMALS ; i++)
- {
- angle = ltime * avelocities[i][0];
- sy = sin(angle);
- cy = cos(angle);
- angle = ltime * avelocities[i][1];
- sp = sin(angle);
- cp = cos(angle);
- /*
- angle = ltime * avelocities[i][2];
- sr = sin(angle);
- cr = cos(angle);
- */
-
- forward[0] = cp*cy;
- forward[1] = cp*sy;
- forward[2] = -sp;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
-
- dist = sin(ltime + i)*64;
- p->org[0] = ent->origin[0] + bytedirs[i][0]*dist + forward[0]*BEAMLENGTH;
- p->org[1] = ent->origin[1] + bytedirs[i][1]*dist + forward[1]*BEAMLENGTH;
- p->org[2] = ent->origin[2] + bytedirs[i][2]*dist + forward[2]*BEAMLENGTH;
-
- VectorClear (p->vel);
- VectorClear (p->accel);
-
- VectorSubtract (p->org, ent->origin, v);
- dist = VectorLength(v) / 90.0;
- p->color = floor (0xd0 + dist * 7);
- p->colorvel = 0;
-
- p->alpha = 1.0 - dist;
- p->alphavel = -100;
- }
-}
-
-
-/*
-===============
-CL_TrapParticles
-===============
-*/
-// RAFAEL
-void CL_TrapParticles (entity_t *ent)
-{
- vec3_t move;
- vec3_t vec;
- vec3_t start, end;
- float len;
- int j;
- cparticle_t *p;
- int dec;
-
- ent->origin[2]-=14;
- VectorCopy (ent->origin, start);
- VectorCopy (ent->origin, end);
- end[2]+=64;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- dec = 5;
- VectorScale (vec, 5, vec);
-
- // FIXME: this is a really silly way to have a loop
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (0.3+qfrand()*0.2);
- p->color = 0xe0;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand();
- p->vel[j] = crand()*15;
- p->accel[j] = 0;
- }
- p->accel[2] = PARTICLE_GRAVITY;
-
- VectorAdd (move, vec, move);
- }
-
- {
-
-
- int i, j, k;
- cparticle_t *p;
- float vel;
- vec3_t dir;
- vec3_t org;
-
-
- ent->origin[2]+=14;
- VectorCopy (ent->origin, org);
-
-
- for (i=-2 ; i<=2 ; i+=4)
- for (j=-2 ; j<=2 ; j+=4)
- for (k=-2 ; k<=4 ; k+=4)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = 0xe0 + (rand()&3);
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (0.3 + (rand()&7) * 0.02);
-
- p->org[0] = org[0] + i + ((rand()&23) * crand());
- p->org[1] = org[1] + j + ((rand()&23) * crand());
- p->org[2] = org[2] + k + ((rand()&23) * crand());
-
- dir[0] = j * 8;
- dir[1] = i * 8;
- dir[2] = k * 8;
-
- VectorNormalize (dir);
- vel = 50 + rand()&63;
- VectorScale (dir, vel, p->vel);
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- }
- }
-}
-
-
-/*
-===============
-CL_BFGExplosionParticles
-===============
-*/
-//FIXME combined with CL_ExplosionParticles
-void CL_BFGExplosionParticles (vec3_t org)
-{
- int i, j;
- cparticle_t *p;
-
- for (i=0 ; i<256 ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = 0xd0 + (rand()&7);
-
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + ((rand()%32)-16);
- p->vel[j] = (rand()%384)-192;
- }
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- p->alpha = 1.0;
-
- p->alphavel = -0.8 / (0.5 + qfrand()*0.3);
- }
-}
-
-
-/*
-===============
-CL_TeleportParticles
-
-===============
-*/
-void CL_TeleportParticles (vec3_t org)
-{
- int i, j, k;
- cparticle_t *p;
- float vel;
- vec3_t dir;
-
- for (i=-16 ; i<=16 ; i+=4)
- for (j=-16 ; j<=16 ; j+=4)
- for (k=-16 ; k<=32 ; k+=4)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = 7 + (rand()&7);
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (0.3 + (rand()&7) * 0.02);
-
- p->org[0] = org[0] + i + (rand()&3);
- p->org[1] = org[1] + j + (rand()&3);
- p->org[2] = org[2] + k + (rand()&3);
-
- dir[0] = j*8;
- dir[1] = i*8;
- dir[2] = k*8;
-
- VectorNormalize (dir);
- vel = 50 + (rand()&63);
- VectorScale (dir, vel, p->vel);
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- }
-}
-
-
-/*
-===============
-CL_AddParticles
-===============
-*/
-void CL_AddParticles (void)
-{
- cparticle_t *p, *next;
- float alpha;
- float time = 0, time2;
- vec3_t org;
- int color;
- cparticle_t *active, *tail;
-
- active = NULL;
- tail = NULL;
-
- for (p=active_particles ; p ; p=next)
- {
- next = p->next;
-
- // PMM - added INSTANT_PARTICLE handling for heat beam
- if (p->alphavel != INSTANT_PARTICLE)
- {
- time = (cl.time - p->time)*0.001;
- alpha = p->alpha + time*p->alphavel;
- if (alpha <= 0)
- { // faded out
- p->next = free_particles;
- free_particles = p;
- continue;
- }
- }
- else
- {
- alpha = p->alpha;
- }
-
- p->next = NULL;
- if (!tail)
- active = tail = p;
- else
- {
- tail->next = p;
- tail = p;
- }
-
- if (alpha > 1.0)
- alpha = 1;
- color = p->color;
-
- time2 = time*time;
-
- org[0] = p->org[0] + p->vel[0]*time + p->accel[0]*time2;
- org[1] = p->org[1] + p->vel[1]*time + p->accel[1]*time2;
- org[2] = p->org[2] + p->vel[2]*time + p->accel[2]*time2;
-
- V_AddParticle (org, color, alpha);
- // PMM
- if (p->alphavel == INSTANT_PARTICLE)
- {
- p->alphavel = 0.0;
- p->alpha = 0.0;
- }
- }
-
- active_particles = active;
-}
-
-
-/*
-==============
-CL_EntityEvent
-
-An entity has just been parsed that has an event value
-
-the female events are there for backwards compatability
-==============
-*/
-extern struct sfx_s *cl_sfx_footsteps[4];
-
-void CL_EntityEvent (entity_state_t *ent)
-{
- switch (ent->event)
- {
- case EV_ITEM_RESPAWN:
- S_StartSound (NULL, ent->number, CHAN_WEAPON, S_RegisterSound("items/respawn1.wav"), 1, ATTN_IDLE, 0);
- CL_ItemRespawnParticles (ent->origin);
- break;
- case EV_PLAYER_TELEPORT:
- S_StartSound (NULL, ent->number, CHAN_WEAPON, S_RegisterSound("misc/tele1.wav"), 1, ATTN_IDLE, 0);
- CL_TeleportParticles (ent->origin);
- break;
- case EV_FOOTSTEP:
- if (cl_footsteps->value)
- S_StartSound (NULL, ent->number, CHAN_BODY, cl_sfx_footsteps[rand()&3], 1, ATTN_NORM, 0);
- break;
- case EV_FALLSHORT:
- S_StartSound (NULL, ent->number, CHAN_AUTO, S_RegisterSound ("player/land1.wav"), 1, ATTN_NORM, 0);
- break;
- case EV_FALL:
- S_StartSound (NULL, ent->number, CHAN_AUTO, S_RegisterSound ("*fall2.wav"), 1, ATTN_NORM, 0);
- break;
- case EV_FALLFAR:
- S_StartSound (NULL, ent->number, CHAN_AUTO, S_RegisterSound ("*fall1.wav"), 1, ATTN_NORM, 0);
- break;
- }
-}
-
-
-/*
-==============
-CL_ClearEffects
-
-==============
-*/
-void CL_ClearEffects (void)
-{
- CL_ClearParticles ();
- CL_ClearDlights ();
- CL_ClearLightStyles ();
-}
--- a/client/cl_input.c
+++ /dev/null
@@ -1,525 +1,0 @@
-// cl.input.c -- builds an intended movement command to send to the server
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-cvar_t *cl_nodelta;
-
-unsigned frame_msec;
-unsigned old_sys_frame_time;
-
-/*
-===============================================================================
-
-KEY BUTTONS
-
-Continuous button event tracking is complicated by the fact that two different
-input sources (say, mouse button 1 and the control key) can both press the
-same button, but the button should only be released when both of the
-pressing key have been released.
-
-When a key event issues a button command (+forward, +attack, etc), it appends
-its key number as a parameter to the command so it can be matched up with
-the release.
-
-state bit 0 is the current state of the key
-state bit 1 is edge triggered on the up to down transition
-state bit 2 is edge triggered on the down to up transition
-
-
-Key_Event (int key, qboolean down, unsigned time);
-
- +mlook src time
-
-===============================================================================
-*/
-
-
-kbutton_t in_klook;
-kbutton_t in_left, in_right, in_forward, in_back;
-kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright;
-kbutton_t in_strafe, in_speed, in_use, in_attack;
-kbutton_t in_up, in_down;
-
-int in_impulse;
-
-
-void KeyDown (kbutton_t *b)
-{
- int k;
- char *c;
-
- c = Cmd_Argv(1);
- if (c[0])
- k = atoi(c);
- else
- k = -1; // typed manually at the console for continuous down
-
- if (k == b->down[0] || k == b->down[1])
- return; // repeating key
-
- if (!b->down[0])
- b->down[0] = k;
- else if (!b->down[1])
- b->down[1] = k;
- else
- {
- Com_Printf ("Three keys down for a button!\n");
- return;
- }
-
- if (b->state & 1)
- return; // still down
-
- // save timestamp
- c = Cmd_Argv(2);
- b->downtime = atoi(c);
- if (!b->downtime)
- b->downtime = sys_frame_time - 100;
-
- b->state |= 1 + 2; // down + impulse down
-}
-
-void KeyUp (kbutton_t *b)
-{
- int k;
- char *c;
- unsigned uptime;
-
- c = Cmd_Argv(1);
- if (c[0])
- k = atoi(c);
- else
- { // typed manually at the console, assume for unsticking, so clear all
- b->down[0] = b->down[1] = 0;
- b->state = 4; // impulse up
- return;
- }
-
- if (b->down[0] == k)
- b->down[0] = 0;
- else if (b->down[1] == k)
- b->down[1] = 0;
- else
- return; // key up without coresponding down (menu pass through)
- if (b->down[0] || b->down[1])
- return; // some other key is still holding it down
-
- if (!(b->state & 1))
- return; // still up (this should not happen)
-
- // save timestamp
- c = Cmd_Argv(2);
- uptime = atoi(c);
- if (uptime)
- b->msec += uptime - b->downtime;
- else
- b->msec += 10;
-
- b->state &= ~1; // now up
- b->state |= 4; // impulse up
-}
-
-void IN_KLookDown (void) {KeyDown(&in_klook);}
-void IN_KLookUp (void) {KeyUp(&in_klook);}
-void IN_UpDown(void) {KeyDown(&in_up);}
-void IN_UpUp(void) {KeyUp(&in_up);}
-void IN_DownDown(void) {KeyDown(&in_down);}
-void IN_DownUp(void) {KeyUp(&in_down);}
-void IN_LeftDown(void) {KeyDown(&in_left);}
-void IN_LeftUp(void) {KeyUp(&in_left);}
-void IN_RightDown(void) {KeyDown(&in_right);}
-void IN_RightUp(void) {KeyUp(&in_right);}
-void IN_ForwardDown(void) {KeyDown(&in_forward);}
-void IN_ForwardUp(void) {KeyUp(&in_forward);}
-void IN_BackDown(void) {KeyDown(&in_back);}
-void IN_BackUp(void) {KeyUp(&in_back);}
-void IN_LookupDown(void) {KeyDown(&in_lookup);}
-void IN_LookupUp(void) {KeyUp(&in_lookup);}
-void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
-void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
-void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
-void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
-void IN_MoverightDown(void) {KeyDown(&in_moveright);}
-void IN_MoverightUp(void) {KeyUp(&in_moveright);}
-
-void IN_SpeedDown(void) {KeyDown(&in_speed);}
-void IN_SpeedUp(void) {KeyUp(&in_speed);}
-void IN_StrafeDown(void) {KeyDown(&in_strafe);}
-void IN_StrafeUp(void) {KeyUp(&in_strafe);}
-
-void IN_AttackDown(void) {KeyDown(&in_attack);}
-void IN_AttackUp(void) {KeyUp(&in_attack);}
-
-void IN_UseDown (void) {KeyDown(&in_use);}
-void IN_UseUp (void) {KeyUp(&in_use);}
-
-void IN_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));}
-
-/*
-===============
-CL_KeyState
-
-Returns the fraction of the frame that the key was down
-===============
-*/
-float CL_KeyState (kbutton_t *key)
-{
- float val;
- int msec;
-
- key->state &= 1; // clear impulses
-
- msec = key->msec;
- key->msec = 0;
-
- if (key->state)
- { // still down
- msec += sys_frame_time - key->downtime;
- key->downtime = sys_frame_time;
- }
-
-/*
- if (msec)
- {
- Com_Printf ("%i ", msec);
- }
-*/
-
- val = (float)msec / frame_msec;
- if (val < 0)
- val = 0;
- if (val > 1)
- val = 1;
-
- return val;
-}
-
-
-
-
-//==========================================================================
-
-cvar_t *cl_upspeed;
-cvar_t *cl_forwardspeed;
-cvar_t *cl_sidespeed;
-
-cvar_t *cl_yawspeed;
-cvar_t *cl_pitchspeed;
-
-cvar_t *cl_run;
-
-cvar_t *cl_anglespeedkey;
-
-
-/*
-================
-CL_AdjustAngles
-
-Moves the local angle positions
-================
-*/
-void CL_AdjustAngles (void)
-{
- float speed;
- float up, down;
-
- if (in_speed.state & 1)
- speed = cls.frametime * cl_anglespeedkey->value;
- else
- speed = cls.frametime;
-
- if (!(in_strafe.state & 1))
- {
- cl.viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right);
- cl.viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left);
- }
- if (in_klook.state & 1)
- {
- cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_forward);
- cl.viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_back);
- }
-
- up = CL_KeyState (&in_lookup);
- down = CL_KeyState(&in_lookdown);
-
- cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * up;
- cl.viewangles[PITCH] += speed*cl_pitchspeed->value * down;
-}
-
-/*
-================
-CL_BaseMove
-
-Send the intended movement message to the server
-================
-*/
-void CL_BaseMove (usercmd_t *cmd)
-{
- CL_AdjustAngles ();
-
- memset (cmd, 0, sizeof(*cmd));
-
- VectorCopy (cl.viewangles, cmd->angles);
- if (in_strafe.state & 1)
- {
- cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_right);
- cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_left);
- }
-
- cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_moveright);
- cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_moveleft);
-
- cmd->upmove += cl_upspeed->value * CL_KeyState (&in_up);
- cmd->upmove -= cl_upspeed->value * CL_KeyState (&in_down);
-
- if (! (in_klook.state & 1) )
- {
- cmd->forwardmove += cl_forwardspeed->value * CL_KeyState (&in_forward);
- cmd->forwardmove -= cl_forwardspeed->value * CL_KeyState (&in_back);
- }
-
-//
-// adjust for speed key / running
-//
- if ( (in_speed.state & 1) ^ (int)(cl_run->value) )
- {
- cmd->forwardmove *= 2;
- cmd->sidemove *= 2;
- cmd->upmove *= 2;
- }
-}
-
-void CL_ClampPitch (void)
-{
- float pitch;
-
- pitch = SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]);
- if (pitch > 180)
- pitch -= 360;
- if (cl.viewangles[PITCH] + pitch > 89)
- cl.viewangles[PITCH] = 89 - pitch;
- if (cl.viewangles[PITCH] + pitch < -89)
- cl.viewangles[PITCH] = -89 - pitch;
-}
-
-/*
-==============
-CL_FinishMove
-==============
-*/
-void CL_FinishMove (usercmd_t *cmd)
-{
- int ms;
- int i;
-
-//
-// figure button bits
-//
- if ( in_attack.state & 3 )
- cmd->buttons |= BUTTON_ATTACK;
- in_attack.state &= ~2;
-
- if (in_use.state & 3)
- cmd->buttons |= BUTTON_USE;
- in_use.state &= ~2;
-
- if (anykeydown && cls.key_dest == key_game)
- cmd->buttons |= BUTTON_ANY;
-
- // send milliseconds of time to apply the move
- ms = cls.frametime * 1000;
- if (ms > 250)
- ms = 100; // time was unreasonable
- cmd->msec = ms;
-
- CL_ClampPitch ();
- for (i=0 ; i<3 ; i++)
- cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);
-
- cmd->impulse = in_impulse;
- in_impulse = 0;
-
-// send the ambient light level at the player's current position
- cmd->lightlevel = (byte)cl_lightlevel->value;
-}
-
-/*
-=================
-CL_CreateCmd
-=================
-*/
-usercmd_t CL_CreateCmd (void)
-{
- usercmd_t cmd;
-
- frame_msec = sys_frame_time - old_sys_frame_time;
- if (frame_msec < 1)
- frame_msec = 1;
- if (frame_msec > 200)
- frame_msec = 200;
-
- // get basic movement from keyboard
- CL_BaseMove (&cmd);
-
- // allow mice or other external controllers to add to the move
- IN_Move (&cmd);
-
- CL_FinishMove (&cmd);
-
- old_sys_frame_time = sys_frame_time;
-
-//cmd.impulse = cls.framecount;
-
- return cmd;
-}
-
-
-void IN_CenterView (void)
-{
- cl.viewangles[PITCH] = -SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]);
-}
-
-/*
-============
-CL_InitInput
-============
-*/
-void CL_InitInput (void)
-{
- Cmd_AddCommand ("centerview",IN_CenterView);
-
- Cmd_AddCommand ("+moveup",IN_UpDown);
- Cmd_AddCommand ("-moveup",IN_UpUp);
- Cmd_AddCommand ("+movedown",IN_DownDown);
- Cmd_AddCommand ("-movedown",IN_DownUp);
- Cmd_AddCommand ("+left",IN_LeftDown);
- Cmd_AddCommand ("-left",IN_LeftUp);
- Cmd_AddCommand ("+right",IN_RightDown);
- Cmd_AddCommand ("-right",IN_RightUp);
- Cmd_AddCommand ("+forward",IN_ForwardDown);
- Cmd_AddCommand ("-forward",IN_ForwardUp);
- Cmd_AddCommand ("+back",IN_BackDown);
- Cmd_AddCommand ("-back",IN_BackUp);
- Cmd_AddCommand ("+lookup", IN_LookupDown);
- Cmd_AddCommand ("-lookup", IN_LookupUp);
- Cmd_AddCommand ("+lookdown", IN_LookdownDown);
- Cmd_AddCommand ("-lookdown", IN_LookdownUp);
- Cmd_AddCommand ("+strafe", IN_StrafeDown);
- Cmd_AddCommand ("-strafe", IN_StrafeUp);
- Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
- Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
- Cmd_AddCommand ("+moveright", IN_MoverightDown);
- Cmd_AddCommand ("-moveright", IN_MoverightUp);
- Cmd_AddCommand ("+speed", IN_SpeedDown);
- Cmd_AddCommand ("-speed", IN_SpeedUp);
- Cmd_AddCommand ("+attack", IN_AttackDown);
- Cmd_AddCommand ("-attack", IN_AttackUp);
- Cmd_AddCommand ("+use", IN_UseDown);
- Cmd_AddCommand ("-use", IN_UseUp);
- Cmd_AddCommand ("impulse", IN_Impulse);
- Cmd_AddCommand ("+klook", IN_KLookDown);
- Cmd_AddCommand ("-klook", IN_KLookUp);
-
- cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0);
-}
-
-
-
-/*
-=================
-CL_SendCmd
-=================
-*/
-void CL_SendCmd (void)
-{
- sizebuf_t buf;
- byte data[128];
- int i;
- usercmd_t *cmd, *oldcmd;
- usercmd_t nullcmd;
- int checksumIndex;
-
- // build a command even if not connected
-
- // save this command off for prediction
- i = cls.netchan.outgoing_sequence & (CMD_BACKUP-1);
- cmd = &cl.cmds[i];
- cl.cmd_time[i] = cls.realtime; // for netgraph ping calculation
-
- *cmd = CL_CreateCmd ();
-
- cl.cmd = *cmd;
-
- if (cls.state == ca_disconnected || cls.state == ca_connecting)
- return;
-
- if ( cls.state == ca_connected)
- {
- if (cls.netchan.message.cursize || curtime - cls.netchan.last_sent > 1000 )
- Netchan_Transmit (&cls.netchan, 0, buf.data);
- return;
- }
-
- // send a userinfo update if needed
- if (userinfo_modified)
- {
- CL_FixUpGender();
- userinfo_modified = false;
- MSG_WriteByte (&cls.netchan.message, clc_userinfo);
- MSG_WriteString (&cls.netchan.message, Cvar_Userinfo() );
- }
-
- SZ_Init (&buf, data, sizeof(data));
-
- if (cmd->buttons && cl.cinematictime > 0 && !cl.attractloop
- && cls.realtime - cl.cinematictime > 1000)
- { // skip the rest of the cinematic
- SCR_FinishCinematic ();
- }
-
- // begin a client move command
- MSG_WriteByte (&buf, clc_move);
-
- // save the position for a checksum byte
- checksumIndex = buf.cursize;
- MSG_WriteByte (&buf, 0);
-
- // let the server know what the last frame we
- // got was, so the next message can be delta compressed
- if (cl_nodelta->value || !cl.frame.valid || cls.demowaiting)
- MSG_WriteLong (&buf, -1); // no compression
- else
- MSG_WriteLong (&buf, cl.frame.serverframe);
-
- // send this and the previous cmds in the message, so
- // if the last packet was dropped, it can be recovered
- i = (cls.netchan.outgoing_sequence-2) & (CMD_BACKUP-1);
- cmd = &cl.cmds[i];
- memset (&nullcmd, 0, sizeof(nullcmd));
- MSG_WriteDeltaUsercmd (&buf, &nullcmd, cmd);
- oldcmd = cmd;
-
- i = (cls.netchan.outgoing_sequence-1) & (CMD_BACKUP-1);
- cmd = &cl.cmds[i];
- MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
- oldcmd = cmd;
-
- i = (cls.netchan.outgoing_sequence) & (CMD_BACKUP-1);
- cmd = &cl.cmds[i];
- MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
-
- // calculate a checksum over the move commands
- buf.data[checksumIndex] = COM_BlockSequenceCRCByte(
- buf.data + checksumIndex + 1, buf.cursize - checksumIndex - 1,
- cls.netchan.outgoing_sequence);
-
- //
- // deliver the message
- //
- Netchan_Transmit (&cls.netchan, buf.cursize, buf.data);
-}
-
-
--- a/client/cl_inv.c
+++ /dev/null
@@ -1,126 +1,0 @@
-// cl_inv.c -- client inventory screen
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-/*
-================
-CL_ParseInventory
-================
-*/
-void CL_ParseInventory (void)
-{
- int i;
-
- for (i=0 ; i<MAX_ITEMS ; i++)
- cl.inventory[i] = MSG_ReadShort (&net_message);
-}
-
-
-/*
-================
-Inv_DrawString
-================
-*/
-void Inv_DrawString (int x, int y, char *string)
-{
- while (*string)
- {
- re.DrawChar (x, y, *string);
- x+=8;
- string++;
- }
-}
-
-void SetStringHighBit (char *s)
-{
- while (*s)
- *s++ |= 128;
-}
-
-/*
-================
-CL_DrawInventory
-================
-*/
-#define DISPLAY_ITEMS 17
-
-void CL_DrawInventory (void)
-{
- int i, j;
- int num, selected_num, item;
- int index[MAX_ITEMS];
- char string[1024];
- int x, y;
- char binding[1024];
- char *bind;
- int selected;
- int top;
-
- selected = cl.frame.playerstate.stats[STAT_SELECTED_ITEM];
-
- num = 0;
- selected_num = 0;
- for (i=0 ; i<MAX_ITEMS ; i++)
- {
- if (i==selected)
- selected_num = num;
- if (cl.inventory[i])
- {
- index[num] = i;
- num++;
- }
- }
-
- // determine scroll point
- top = selected_num - DISPLAY_ITEMS/2;
- if (num - top < DISPLAY_ITEMS)
- top = num - DISPLAY_ITEMS;
- if (top < 0)
- top = 0;
-
- x = (vid.width-256)/2;
- y = (vid.height-240)/2;
-
- // repaint everything next frame
- SCR_DirtyScreen ();
-
- re.DrawPic (x, y+8, "inventory");
-
- y += 24;
- x += 24;
- Inv_DrawString (x, y, "hotkey ### item");
- Inv_DrawString (x, y+8, "------ --- ----");
- y += 16;
- for (i=top ; i<num && i < top+DISPLAY_ITEMS ; i++)
- {
- item = index[i];
- // search for a binding
- Com_sprintf (binding, sizeof(binding), "use %s", cl.configstrings[CS_ITEMS+item]);
- bind = "";
- for (j=0 ; j<256 ; j++)
- if (keybindings[j] && !cistrcmp (keybindings[j], binding))
- {
- bind = Key_KeynumToString(j);
- break;
- }
-
- Com_sprintf (string, sizeof(string), "%6s %3i %s", bind, cl.inventory[item],
- cl.configstrings[CS_ITEMS+item] );
- if (item != selected)
- SetStringHighBit (string);
- else // draw a blinky cursor by the selected item
- {
- if ( (int)(cls.realtime*10) & 1)
- re.DrawChar (x-8, y, 15);
- }
- Inv_DrawString (x, y, string);
- y += 8;
- }
-
-
-}
-
-
--- a/client/cl_main.c
+++ /dev/null
@@ -1,1790 +1,0 @@
-// cl_main.c -- client main loop
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-cvar_t *adr0;
-cvar_t *adr1;
-cvar_t *adr2;
-cvar_t *adr3;
-cvar_t *adr4;
-cvar_t *adr5;
-cvar_t *adr6;
-cvar_t *adr7;
-cvar_t *adr8;
-
-cvar_t *cl_stereo_separation;
-cvar_t *cl_stereo;
-
-cvar_t *rcon_client_password;
-cvar_t *rcon_address;
-
-cvar_t *cl_noskins;
-cvar_t *cl_autoskins;
-cvar_t *cl_footsteps;
-cvar_t *cl_timeout;
-cvar_t *cl_predict;
-//cvar_t *cl_minfps;
-cvar_t *cl_maxfps;
-cvar_t *cl_gun;
-
-cvar_t *cl_add_particles;
-cvar_t *cl_add_lights;
-cvar_t *cl_add_entities;
-cvar_t *cl_add_blend;
-
-cvar_t *cl_shownet;
-cvar_t *cl_showmiss;
-cvar_t *cl_showclamp;
-
-cvar_t *cl_paused;
-cvar_t *cl_timedemo;
-
-cvar_t *cl_lightlevel;
-
-//
-// userinfo
-//
-cvar_t *info_password;
-cvar_t *info_spectator;
-cvar_t *name;
-cvar_t *skin;
-cvar_t *rate;
-cvar_t *fov;
-cvar_t *msg;
-cvar_t *hand;
-cvar_t *gender;
-cvar_t *gender_auto;
-
-cvar_t *cl_vwep;
-
-client_static_t cls;
-client_state_t cl;
-
-centity_t cl_entities[MAX_EDICTS];
-
-entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES];
-
-extern cvar_t *allow_download;
-extern cvar_t *allow_download_players;
-extern cvar_t *allow_download_models;
-extern cvar_t *allow_download_sounds;
-extern cvar_t *allow_download_maps;
-
-//======================================================================
-
-
-/*
-====================
-CL_WriteDemoMessage
-
-Dumps the current net message, prefixed by the length
-====================
-*/
-void CL_WriteDemoMessage (void)
-{
- int len, swlen;
-
- // the first eight bytes are just packet sequencing stuff
- len = net_message.cursize-8;
- swlen = LittleLong(len);
- fwrite (&swlen, 4, 1, cls.demofile);
- fwrite (net_message.data+8, len, 1, cls.demofile);
-}
-
-
-/*
-====================
-CL_Stop_f
-
-stop recording a demo
-====================
-*/
-void CL_Stop_f (void)
-{
- int len;
-
- if (!cls.demorecording)
- {
- Com_Printf ("Not recording a demo.\n");
- return;
- }
-
-// finish up
- len = -1;
- fwrite (&len, 4, 1, cls.demofile);
- fclose (cls.demofile);
- cls.demofile = NULL;
- cls.demorecording = false;
- Com_Printf ("Stopped demo.\n");
-}
-
-/*
-====================
-CL_Record_f
-
-record <demoname>
-
-Begins recording a demo from the current position
-====================
-*/
-void CL_Record_f (void)
-{
- char name[MAX_OSPATH];
- char buf_data[MAX_MSGLEN];
- sizebuf_t buf;
- int i;
- int len;
- entity_state_t *ent;
- entity_state_t nullstate;
-
- if (Cmd_Argc() != 2)
- {
- Com_Printf ("record <demoname>\n");
- return;
- }
-
- if (cls.demorecording)
- {
- Com_Printf ("Already recording.\n");
- return;
- }
-
- if (cls.state != ca_active)
- {
- Com_Printf ("You must be in a level to record.\n");
- return;
- }
-
- //
- // open the demo file
- //
- Com_sprintf (name, sizeof(name), "%s/demos/%s.dm2", FS_Gamedir(), Cmd_Argv(1));
-
- Com_Printf ("recording to %s.\n", name);
- FS_CreatePath (name);
- cls.demofile = fopen (name, "wb");
- if (!cls.demofile)
- {
- Com_Printf ("ERROR: couldn't open.\n");
- return;
- }
- cls.demorecording = true;
-
- // don't start saving messages until a non-delta compressed message is received
- cls.demowaiting = true;
-
- //
- // write out messages to hold the startup information
- //
- SZ_Init (&buf, (uchar *)buf_data, sizeof(buf_data));
-
- // send the serverdata
- MSG_WriteByte (&buf, svc_serverdata);
- MSG_WriteLong (&buf, PROTOCOL_VERSION);
- MSG_WriteLong (&buf, 0x10000 + cl.servercount);
- MSG_WriteByte (&buf, 1); // demos are always attract loops
- MSG_WriteString (&buf, cl.gamedir);
- MSG_WriteShort (&buf, cl.playernum);
-
- MSG_WriteString (&buf, cl.configstrings[CS_NAME]);
-
- // configstrings
- for (i=0 ; i<MAX_CONFIGSTRINGS ; i++)
- {
- if (cl.configstrings[i][0])
- {
- if (buf.cursize + strlen (cl.configstrings[i]) + 32 > buf.maxsize)
- { // write it out
- len = LittleLong (buf.cursize);
- fwrite (&len, 4, 1, cls.demofile);
- fwrite (buf.data, buf.cursize, 1, cls.demofile);
- buf.cursize = 0;
- }
-
- MSG_WriteByte (&buf, svc_configstring);
- MSG_WriteShort (&buf, i);
- MSG_WriteString (&buf, cl.configstrings[i]);
- }
-
- }
-
- // baselines
- memset (&nullstate, 0, sizeof(nullstate));
- for (i=0; i<MAX_EDICTS ; i++)
- {
- ent = &cl_entities[i].baseline;
- if (!ent->modelindex)
- continue;
-
- if (buf.cursize + 64 > buf.maxsize)
- { // write it out
- len = LittleLong (buf.cursize);
- fwrite (&len, 4, 1, cls.demofile);
- fwrite (buf.data, buf.cursize, 1, cls.demofile);
- buf.cursize = 0;
- }
-
- MSG_WriteByte (&buf, svc_spawnbaseline);
- MSG_WriteDeltaEntity (&nullstate, &cl_entities[i].baseline, &buf, true, true);
- }
-
- MSG_WriteByte (&buf, svc_stufftext);
- MSG_WriteString (&buf, "precache\n");
-
- // write it to the demo file
-
- len = LittleLong (buf.cursize);
- fwrite (&len, 4, 1, cls.demofile);
- fwrite (buf.data, buf.cursize, 1, cls.demofile);
-
- // the rest of the demo file will be individual frames
-}
-
-//======================================================================
-
-/*
-===================
-Cmd_ForwardToServer
-
-adds the current command line as a clc_stringcmd to the client message.
-things like godmode, noclip, etc, are commands directed to the server,
-so when they are typed in at the console, they will need to be forwarded.
-===================
-*/
-void Cmd_ForwardToServer (void)
-{
- char *cmd;
-
- cmd = Cmd_Argv(0);
- if (cls.state <= ca_connected || *cmd == '-' || *cmd == '+')
- {
- Com_Printf ("Unknown command \"%s\"\n", cmd);
- return;
- }
-
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- SZ_Print (&cls.netchan.message, cmd);
- if (Cmd_Argc() > 1)
- {
- SZ_Print (&cls.netchan.message, " ");
- SZ_Print (&cls.netchan.message, Cmd_Args());
- }
-}
-
-void
-CL_Setenv_f(void)
-{
- int i, l = 0, argc;
- char name[1024], val[1024], *env;
-
- argc = Cmd_Argc();
-
- if(argc > 2){
- strncpy(name, Cmd_Argv(1), sizeof name);
- for(i = 2; i < argc; i++){
- strncpy(val+l, Cmd_Argv(i), sizeof(name) - l - 2);
- val[sizeof(val)-2] = 0;
- strcat(val, " ");
- l = strlen(val);
- }
- putenv(name, val);
- }else if(argc == 2){
- env = getenv(Cmd_Argv(1));
- if(env){
- Com_Printf("%s=%s\n", Cmd_Argv(1), env);
- free(env);
- }else
- Com_Printf("%s undefined\n", Cmd_Argv(1), env);
- }
-}
-
-
-/*
-==================
-CL_ForwardToServer_f
-==================
-*/
-void CL_ForwardToServer_f (void)
-{
- if (cls.state != ca_connected && cls.state != ca_active)
- {
- Com_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
- return;
- }
-
- // don't forward the first argument
- if (Cmd_Argc() > 1)
- {
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- SZ_Print (&cls.netchan.message, Cmd_Args());
- }
-}
-
-
-/*
-==================
-CL_Pause_f
-==================
-*/
-void CL_Pause_f (void)
-{
- // never pause in multiplayer
- if (Cvar_VariableValue ("maxclients") > 1 || !Com_ServerState ())
- {
- Cvar_SetValue ("paused", 0);
- return;
- }
-
- Cvar_SetValue ("paused", !cl_paused->value);
-}
-
-/*
-==================
-CL_Quit_f
-==================
-*/
-void CL_Quit_f (void)
-{
- CL_Disconnect ();
- Com_Quit ();
-}
-
-/*
-================
-CL_Drop
-
-Called after an ERR_DROP was thrown
-================
-*/
-void CL_Drop (void)
-{
- if (cls.state == ca_uninitialized)
- return;
- if (cls.state == ca_disconnected)
- return;
-
- CL_Disconnect ();
-
- // drop loading plaque unless this is the initial game start
- if (cls.disable_servercount != -1)
- SCR_EndLoadingPlaque (); // get rid of loading plaque
-}
-
-
-/*
-=======================
-CL_SendConnectPacket
-
-We have gotten a challenge from the server, so try and
-connect.
-======================
-*/
-void CL_SendConnectPacket (void)
-{
- netadr_t adr;
- int port;
-
- if (!NET_StringToAdr (cls.servername, &adr))
- {
- Com_Printf ("Bad server address\n");
- cls.connect_time = 0;
- return;
- }
- if (adr.port == 0)
- adr.port = BigShort (PORT_SERVER);
-
- port = Cvar_VariableValue ("qport");
- userinfo_modified = false;
-
- Netchan_OutOfBandPrint (NS_CLIENT, adr, "connect %i %i %i \"%s\"\n",
- PROTOCOL_VERSION, port, cls.challenge, Cvar_Userinfo() );
-}
-
-/*
-=================
-CL_CheckForResend
-
-Resend a connect message if the last one has timed out
-=================
-*/
-void CL_CheckForResend (void)
-{
- netadr_t adr;
-
- // if the local server is running and we aren't
- // then connect
- if (cls.state == ca_disconnected && Com_ServerState() )
- {
- cls.state = ca_connecting;
- strncpy (cls.servername, "localhost", sizeof(cls.servername)-1);
- // we don't need a challenge on the localhost
- CL_SendConnectPacket ();
- return;
-// cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
- }
-
- // resend if we haven't gotten a reply yet
- if (cls.state != ca_connecting)
- return;
-
- if (cls.realtime - cls.connect_time < 3000)
- return;
-
- if (!NET_StringToAdr (cls.servername, &adr))
- {
- Com_Printf ("Bad server address\n");
- cls.state = ca_disconnected;
- return;
- }
- if (adr.port == 0)
- adr.port = BigShort (PORT_SERVER);
-
- cls.connect_time = cls.realtime; // for retransmit requests
-
- Com_Printf ("Connecting to %s...\n", cls.servername);
-
- Netchan_OutOfBandPrint (NS_CLIENT, adr, "getchallenge\n");
-}
-
-
-/*
-================
-CL_Connect_f
-
-================
-*/
-void CL_Connect_f (void)
-{
- char *server;
-
- if (Cmd_Argc() != 2)
- {
- Com_Printf ("usage: connect <server>\n");
- return;
- }
-
- if (Com_ServerState ())
- { // if running a local server, kill it and reissue
- SV_Shutdown (va("Server quit\n", msg), false);
- }
- else
- {
- CL_Disconnect ();
- }
-
- server = Cmd_Argv (1);
-
- NET_Config (true); // allow remote
-
- CL_Disconnect ();
-
- cls.state = ca_connecting;
- strncpy (cls.servername, server, sizeof(cls.servername)-1);
- cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
-}
-
-
-/*
-=====================
-CL_Rcon_f
-
- Send the rest of the command line over as
- an unconnected command.
-=====================
-*/
-void CL_Rcon_f (void)
-{
- char message[1024];
- int i;
- netadr_t to;
-
- if (!rcon_client_password->string)
- {
- Com_Printf ("You must set 'rcon_password' before\n"
- "issuing an rcon command.\n");
- return;
- }
-
- message[0] = (char)255;
- message[1] = (char)255;
- message[2] = (char)255;
- message[3] = (char)255;
- message[4] = 0;
-
- NET_Config (true); // allow remote
-
- strcat (message, "rcon ");
-
- strcat (message, rcon_client_password->string);
- strcat (message, " ");
-
- for (i=1 ; i<Cmd_Argc() ; i++)
- {
- strcat (message, Cmd_Argv(i));
- strcat (message, " ");
- }
-
- if (cls.state >= ca_connected)
- to = cls.netchan.remote_address;
- else
- {
- if (!strlen(rcon_address->string))
- {
- Com_Printf ("You must either be connected,\n"
- "or set the 'rcon_address' cvar\n"
- "to issue rcon commands\n");
-
- return;
- }
- NET_StringToAdr (rcon_address->string, &to);
- if (to.port == 0)
- to.port = BigShort (PORT_SERVER);
- }
-
- NET_SendPacket (NS_CLIENT, strlen(message)+1, message, to);
-}
-
-
-/*
-=====================
-CL_ClearState
-
-=====================
-*/
-void CL_ClearState (void)
-{
- S_StopAllSounds ();
- CL_ClearEffects ();
- CL_ClearTEnts ();
-
-// wipe the entire cl structure
- memset (&cl, 0, sizeof(cl));
- memset (cl_entities, 0, sizeof(cl_entities));
-
- SZ_Clear (&cls.netchan.message);
-
-}
-
-/*
-=====================
-CL_Disconnect
-
-Goes from a connected state to full screen console state
-Sends a disconnect message to the server
-This is also called on Com_Error, so it shouldn't cause any errors
-=====================
-*/
-void CL_Disconnect (void)
-{
- byte final[32];
-
- if (cls.state == ca_disconnected)
- return;
-
- if (cl_timedemo && cl_timedemo->value)
- {
- int time;
-
- time = Sys_Milliseconds () - cl.timedemo_start;
- if (time > 0)
- Com_Printf ("%i frames, %3.1f seconds: %3.1f fps\n", cl.timedemo_frames,
- time/1000.0, cl.timedemo_frames*1000.0 / time);
- }
-
- VectorClear (cl.refdef.blend);
- re.CinematicSetPalette(NULL);
-
- M_ForceMenuOff ();
-
- cls.connect_time = 0;
-
- SCR_StopCinematic ();
-
- if (cls.demorecording)
- CL_Stop_f ();
-
- // send a disconnect message to the server
- final[0] = clc_stringcmd;
- strcpy ((char *)final+1, "disconnect");
- Netchan_Transmit (&cls.netchan, strlen((char *)final), final);
- Netchan_Transmit (&cls.netchan, strlen((char *)final), final);
- Netchan_Transmit (&cls.netchan, strlen((char *)final), final);
-
- CL_ClearState ();
-
- // stop download
- if (cls.download) {
- fclose(cls.download);
- cls.download = NULL;
- }
-
- cls.state = ca_disconnected;
-}
-
-void CL_Disconnect_f (void)
-{
- Com_Error (ERR_DROP, "Disconnected from server");
-}
-
-
-/*
-====================
-CL_Packet_f
-
-packet <destination> <contents>
-
-Contents allows \n escape character
-====================
-*/
-void CL_Packet_f (void)
-{
- char send[2048];
- int i, l;
- char *in, *out;
- netadr_t adr;
-
- if (Cmd_Argc() != 3)
- {
- Com_Printf ("packet <destination> <contents>\n");
- return;
- }
-
- NET_Config (true); // allow remote
-
- if (!NET_StringToAdr (Cmd_Argv(1), &adr))
- {
- Com_Printf ("Bad address\n");
- return;
- }
- if (!adr.port)
- adr.port = BigShort (PORT_SERVER);
-
- in = Cmd_Argv(2);
- out = send+4;
- send[0] = send[1] = send[2] = send[3] = (char)0xff;
-
- l = strlen (in);
- for (i=0 ; i<l ; i++)
- {
- if (in[i] == '\\' && in[i+1] == 'n')
- {
- *out++ = '\n';
- i++;
- }
- else
- *out++ = in[i];
- }
- *out = 0;
-
- NET_SendPacket (NS_CLIENT, out-send, send, adr);
-}
-
-/*
-=================
-CL_Changing_f
-
-Just sent as a hint to the client that they should
-drop to full console
-=================
-*/
-void CL_Changing_f (void)
-{
- //ZOID
- //if we are downloading, we don't change! This so we don't suddenly stop downloading a map
- if (cls.download)
- return;
-
- SCR_BeginLoadingPlaque ();
- cls.state = ca_connected; // not active anymore, but not disconnected
- Com_Printf ("\nChanging map...\n");
-}
-
-
-/*
-=================
-CL_Reconnect_f
-
-The server is changing levels
-=================
-*/
-void CL_Reconnect_f (void)
-{
- //ZOID
- //if we are downloading, we don't change! This so we don't suddenly stop downloading a map
- if (cls.download)
- return;
-
- S_StopAllSounds ();
- if (cls.state == ca_connected) {
- Com_Printf ("reconnecting...\n");
- cls.state = ca_connected;
- MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
- MSG_WriteString (&cls.netchan.message, "new");
- return;
- }
-
- if (*cls.servername) {
- if (cls.state >= ca_connected) {
- CL_Disconnect();
- cls.connect_time = cls.realtime - 1500;
- } else
- cls.connect_time = -99999; // fire immediately
-
- cls.state = ca_connecting;
- Com_Printf ("reconnecting...\n");
- }
-}
-
-/*
-=================
-CL_ParseStatusMessage
-
-Handle a reply from a ping
-=================
-*/
-void CL_ParseStatusMessage (void)
-{
- char *s;
-
- s = MSG_ReadString(&net_message);
-
- Com_Printf ("%s\n", s);
- M_AddToServerList (net_from, s);
-}
-
-
-/*
-=================
-CL_PingServers_f
-=================
-*/
-void CL_PingServers_f (void)
-{
- int i;
- netadr_t adr;
- char name[32];
- char *adrstring;
- cvar_t *noudp;
- cvar_t *noipx;
-
- NET_Config (true); // allow remote
-
- // send a broadcast packet
- Com_Printf ("pinging broadcast...\n");
-
- noudp = Cvar_Get ("noudp", "0", CVAR_NOSET);
- if (!noudp->value)
- {
- adr.type = NA_BROADCAST;
- adr.port = BigShort(PORT_SERVER);
- Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
- }
-
- noipx = Cvar_Get ("noipx", "0", CVAR_NOSET);
- if (!noipx->value)
- {
- adr.type = NA_BROADCAST_IPX;
- adr.port = BigShort(PORT_SERVER);
- Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
- }
-
- // send a packet to each address book entry
- for (i=0 ; i<16 ; i++)
- {
- Com_sprintf (name, sizeof(name), "adr%i", i);
- adrstring = Cvar_VariableString (name);
- if (!adrstring || !adrstring[0])
- continue;
-
- Com_Printf ("pinging %s...\n", adrstring);
- if (!NET_StringToAdr (adrstring, &adr))
- {
- Com_Printf ("Bad address: %s\n", adrstring);
- continue;
- }
- if (!adr.port)
- adr.port = BigShort(PORT_SERVER);
- Netchan_OutOfBandPrint (NS_CLIENT, adr, va("info %i", PROTOCOL_VERSION));
- }
-}
-
-
-/*
-=================
-CL_Skins_f
-
-Load or download any custom player skins and models
-=================
-*/
-void CL_Skins_f (void)
-{
- int i;
-
- for (i=0 ; i<MAX_CLIENTS ; i++)
- {
- if (!cl.configstrings[CS_PLAYERSKINS+i][0])
- continue;
- Com_Printf ("client %i: %s\n", i, cl.configstrings[CS_PLAYERSKINS+i]);
- SCR_UpdateScreen ();
- Sys_SendKeyEvents (); // pump message loop
- CL_ParseClientinfo (i);
- }
-}
-
-
-/*
-=================
-CL_ConnectionlessPacket
-
-Responses to broadcasts, etc
-=================
-*/
-void CL_ConnectionlessPacket (void)
-{
- char *s;
- char *c;
-
- MSG_BeginReading (&net_message);
- MSG_ReadLong (&net_message); // skip the -1
-
- s = MSG_ReadStringLine (&net_message);
-
- Cmd_TokenizeString (s, false);
-
- c = Cmd_Argv(0);
-
- Com_Printf ("%s: %s\n", NET_AdrToString (net_from), c);
-
- // server connection
- if (!strcmp(c, "client_connect"))
- {
- if (cls.state == ca_connected)
- {
- Com_Printf ("Dup connect received. Ignored.\n");
- return;
- }
- Netchan_Setup (NS_CLIENT, &cls.netchan, net_from, cls.quakePort);
- MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
- MSG_WriteString (&cls.netchan.message, "new");
- cls.state = ca_connected;
- return;
- }
-
- // server responding to a status broadcast
- if (!strcmp(c, "info"))
- {
- CL_ParseStatusMessage ();
- return;
- }
-
- // remote command from gui front end
- if (!strcmp(c, "cmd"))
- {
- if (!NET_IsLocalAddress(net_from))
- {
- Com_Printf ("Command packet from remote host. Ignored.\n");
- return;
- }
- Sys_AppActivate ();
- s = MSG_ReadString (&net_message);
- Cbuf_AddText (s);
- Cbuf_AddText ("\n");
- return;
- }
- // print command from somewhere
- if (!strcmp(c, "print"))
- {
- s = MSG_ReadString (&net_message);
- Com_Printf ("%s", s);
- return;
- }
-
- // ping from somewhere
- if (!strcmp(c, "ping"))
- {
- Netchan_OutOfBandPrint (NS_CLIENT, net_from, "ack");
- return;
- }
-
- // challenge from the server we are connecting to
- if (!strcmp(c, "challenge"))
- {
- cls.challenge = atoi(Cmd_Argv(1));
- CL_SendConnectPacket ();
- return;
- }
-
- // echo request from server
- if (!strcmp(c, "echo"))
- {
- Netchan_OutOfBandPrint (NS_CLIENT, net_from, "%s", Cmd_Argv(1) );
- return;
- }
-
- Com_Printf ("Unknown command.\n");
-}
-
-
-/*
-=================
-CL_DumpPackets
-
-A vain attempt to help bad TCP stacks that cause problems
-when they overflow
-=================
-*/
-void CL_DumpPackets (void)
-{
- while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
- {
- Com_Printf ("dumnping a packet\n");
- }
-}
-
-/*
-=================
-CL_ReadPackets
-=================
-*/
-void CL_ReadPackets (void)
-{
- while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
- {
-// Com_Printf ("packet\n");
- //
- // remote command packet
- //
- if (*(int *)net_message.data == -1)
- {
- CL_ConnectionlessPacket ();
- continue;
- }
-
- if (cls.state == ca_disconnected || cls.state == ca_connecting)
- continue; // dump it if not connected
-
- if (net_message.cursize < 8)
- {
- Com_Printf ("%s: Runt packet\n",NET_AdrToString(net_from));
- continue;
- }
-
- //
- // packet from server
- //
- if (!NET_CompareAdr (net_from, cls.netchan.remote_address))
- {
- Com_DPrintf ("%s:sequenced packet without connection\n"
- ,NET_AdrToString(net_from));
- continue;
- }
- if (!Netchan_Process(&cls.netchan, &net_message))
- continue; // wasn't accepted for some reason
- CL_ParseServerMessage ();
- }
-
- //
- // check timeout
- //
- if (cls.state >= ca_connected
- && cls.realtime - cls.netchan.last_received > cl_timeout->value*1000)
- {
- if (++cl.timeoutcount > 5) // timeoutcount saves debugger
- {
- Com_Printf ("\nServer connection timed out.\n");
- CL_Disconnect ();
- return;
- }
- }
- else
- cl.timeoutcount = 0;
-
-}
-
-
-//=============================================================================
-
-/*
-==============
-CL_FixUpGender_f
-==============
-*/
-void CL_FixUpGender(void)
-{
- char *p;
- char sk[80];
-
- if (gender_auto->value) {
-
- if (gender->modified) {
- // was set directly, don't override the user
- gender->modified = false;
- return;
- }
-
- strncpy(sk, skin->string, sizeof(sk) - 1);
- if ((p = strchr(sk, '/')) != NULL)
- *p = 0;
- if (cistrcmp(sk, "male") == 0 || cistrcmp(sk, "cyborg") == 0)
- Cvar_Set ("gender", "male");
- else if (cistrcmp(sk, "female") == 0 || cistrcmp(sk, "crackhor") == 0)
- Cvar_Set ("gender", "female");
- else
- Cvar_Set ("gender", "none");
- gender->modified = false;
- }
-}
-
-/*
-==============
-CL_Userinfo_f
-==============
-*/
-void CL_Userinfo_f (void)
-{
- Com_Printf ("User info settings:\n");
- Info_Print (Cvar_Userinfo());
-}
-
-/*
-=================
-CL_Snd_Restart_f
-
-Restart the sound subsystem so it can pick up
-new parameters and flush all sounds
-=================
-*/
-void CL_Snd_Restart_f (void)
-{
- S_Shutdown ();
- S_Init ();
- CL_RegisterSounds ();
-}
-
-int precache_check; // for autodownload of precache items
-int precache_spawncount;
-int precache_tex;
-int precache_model_skin;
-
-byte *precache_model; // used for skin checking in alias models
-
-#define PLAYER_MULT 5
-
-// ENV_CNT is map load, ENV_CNT+1 is first env map
-#define ENV_CNT (CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT)
-#define TEXTURE_CNT (ENV_CNT+13)
-
-static const char *env_suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
-
-void CL_RequestNextDownload (void)
-{
- unsigned map_checksum; // for detecting cheater maps
- char fn[MAX_OSPATH];
- dmdl_t *pheader;
-
- if (cls.state != ca_connected)
- return;
-
- if (!allow_download->value && precache_check < ENV_CNT)
- precache_check = ENV_CNT;
-
-//ZOID
- if (precache_check == CS_MODELS) { // confirm map
- precache_check = CS_MODELS+2; // 0 isn't used
- if (allow_download_maps->value)
- if (!CL_CheckOrDownloadFile(cl.configstrings[CS_MODELS+1]))
- return; // started a download
- }
- if (precache_check >= CS_MODELS && precache_check < CS_MODELS+MAX_MODELS) {
- if (allow_download_models->value) {
- while (precache_check < CS_MODELS+MAX_MODELS &&
- cl.configstrings[precache_check][0]) {
- if (cl.configstrings[precache_check][0] == '*' ||
- cl.configstrings[precache_check][0] == '#') {
- precache_check++;
- continue;
- }
- if (precache_model_skin == 0) {
- if (!CL_CheckOrDownloadFile(cl.configstrings[precache_check])) {
- precache_model_skin = 1;
- return; // started a download
- }
- precache_model_skin = 1;
- }
-
- // checking for skins in the model
- if (!precache_model) {
-
- FS_LoadFile (cl.configstrings[precache_check], (void **)&precache_model);
- if (!precache_model) {
- precache_model_skin = 0;
- precache_check++;
- continue; // couldn't load it
- }
- if (LittleLong(*(unsigned *)precache_model) != IDALIASHEADER) {
- // not an alias model
- FS_FreeFile(precache_model);
- precache_model = 0;
- precache_model_skin = 0;
- precache_check++;
- continue;
- }
- pheader = (dmdl_t *)precache_model;
- if (LittleLong (pheader->version) != ALIAS_VERSION) {
- precache_check++;
- precache_model_skin = 0;
- continue; // couldn't load it
- }
- }
-
- pheader = (dmdl_t *)precache_model;
-
- while (precache_model_skin - 1 < LittleLong(pheader->num_skins)) {
- if (!CL_CheckOrDownloadFile((char *)precache_model +
- LittleLong(pheader->ofs_skins) +
- (precache_model_skin - 1)*MAX_SKINNAME)) {
- precache_model_skin++;
- return; // started a download
- }
- precache_model_skin++;
- }
- if (precache_model) {
- FS_FreeFile(precache_model);
- precache_model = 0;
- }
- precache_model_skin = 0;
- precache_check++;
- }
- }
- precache_check = CS_SOUNDS;
- }
- if (precache_check >= CS_SOUNDS && precache_check < CS_SOUNDS+MAX_SOUNDS) {
- if (allow_download_sounds->value) {
- if (precache_check == CS_SOUNDS)
- precache_check++; // zero is blank
- while (precache_check < CS_SOUNDS+MAX_SOUNDS &&
- cl.configstrings[precache_check][0]) {
- if (cl.configstrings[precache_check][0] == '*') {
- precache_check++;
- continue;
- }
- Com_sprintf(fn, sizeof(fn), "sound/%s", cl.configstrings[precache_check++]);
- if (!CL_CheckOrDownloadFile(fn))
- return; // started a download
- }
- }
- precache_check = CS_IMAGES;
- }
- if (precache_check >= CS_IMAGES && precache_check < CS_IMAGES+MAX_IMAGES) {
- if (precache_check == CS_IMAGES)
- precache_check++; // zero is blank
- while (precache_check < CS_IMAGES+MAX_IMAGES &&
- cl.configstrings[precache_check][0]) {
- Com_sprintf(fn, sizeof(fn), "pics/%s.pcx", cl.configstrings[precache_check++]);
- if (!CL_CheckOrDownloadFile(fn))
- return; // started a download
- }
- precache_check = CS_PLAYERSKINS;
- }
- // skins are special, since a player has three things to download:
- // model, weapon model and skin
- // so precache_check is now *3
- if (precache_check >= CS_PLAYERSKINS && precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
- if (allow_download_players->value) {
- while (precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
- int i, n;
- char model[MAX_QPATH], skin[MAX_QPATH], *p;
-
- i = (precache_check - CS_PLAYERSKINS)/PLAYER_MULT;
- n = (precache_check - CS_PLAYERSKINS)%PLAYER_MULT;
-
- if (!cl.configstrings[CS_PLAYERSKINS+i][0]) {
- precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
- continue;
- }
-
- if ((p = strchr(cl.configstrings[CS_PLAYERSKINS+i], '\\')) != NULL)
- p++;
- else
- p = cl.configstrings[CS_PLAYERSKINS+i];
- strcpy(model, p);
- p = strchr(model, '/');
- if (!p)
- p = strchr(model, '\\');
- if (p) {
- *p++ = 0;
- strcpy(skin, p);
- } else
- *skin = 0;
-
- switch (n) {
- case 0: // model
- Com_sprintf(fn, sizeof(fn), "players/%s/tris.md2", model);
- if (!CL_CheckOrDownloadFile(fn)) {
- precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 1;
- return; // started a download
- }
- /*FALL THROUGH*/
-
- case 1: // weapon model
- Com_sprintf(fn, sizeof(fn), "players/%s/weapon.md2", model);
- if (!CL_CheckOrDownloadFile(fn)) {
- precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 2;
- return; // started a download
- }
- /*FALL THROUGH*/
-
- case 2: // weapon skin
- Com_sprintf(fn, sizeof(fn), "players/%s/weapon.pcx", model);
- if (!CL_CheckOrDownloadFile(fn)) {
- precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 3;
- return; // started a download
- }
- /*FALL THROUGH*/
-
- case 3: // skin
- Com_sprintf(fn, sizeof(fn), "players/%s/%s.pcx", model, skin);
- if (!CL_CheckOrDownloadFile(fn)) {
- precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 4;
- return; // started a download
- }
- /*FALL THROUGH*/
-
- case 4: // skin_i
- Com_sprintf(fn, sizeof(fn), "players/%s/%s_i.pcx", model, skin);
- if (!CL_CheckOrDownloadFile(fn)) {
- precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 5;
- return; // started a download
- }
- // move on to next model
- precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
- }
- }
- }
- // precache phase completed
- precache_check = ENV_CNT;
- }
-
- if (precache_check == ENV_CNT) {
- precache_check = ENV_CNT + 1;
-
- CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
-
- if (map_checksum != atoi(cl.configstrings[CS_MAPCHECKSUM])) {
- Com_Error (ERR_DROP, "Local map version differs from server: %i != '%s'\n",
- map_checksum, cl.configstrings[CS_MAPCHECKSUM]);
- return;
- }
- }
-
- if (precache_check > ENV_CNT && precache_check < TEXTURE_CNT) {
- if (allow_download->value && allow_download_maps->value) {
- while (precache_check < TEXTURE_CNT) {
- int n = precache_check++ - ENV_CNT - 1;
-
- if (n & 1)
- Com_sprintf(fn, sizeof(fn), "env/%s%s.pcx",
- cl.configstrings[CS_SKY], env_suf[n/2]);
- else
- Com_sprintf(fn, sizeof(fn), "env/%s%s.tga",
- cl.configstrings[CS_SKY], env_suf[n/2]);
- if (!CL_CheckOrDownloadFile(fn))
- return; // started a download
- }
- }
- precache_check = TEXTURE_CNT;
- }
-
- if (precache_check == TEXTURE_CNT) {
- precache_check = TEXTURE_CNT+1;
- precache_tex = 0;
- }
-
- // confirm existance of textures, download any that don't exist
- if (precache_check == TEXTURE_CNT+1) {
- // from qcommon/cmodel.c
- extern int numtexinfo;
- extern mapsurface_t map_surfaces[];
-
- if (allow_download->value && allow_download_maps->value) {
- while (precache_tex < numtexinfo) {
- char fn[MAX_OSPATH];
-
- sprintf(fn, "textures/%s.wal", map_surfaces[precache_tex++].rname);
- if (!CL_CheckOrDownloadFile(fn))
- return; // started a download
- }
- }
- precache_check = TEXTURE_CNT+999;
- }
-
-//ZOID
- CL_RegisterSounds ();
- CL_PrepRefresh ();
-
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- MSG_WriteString (&cls.netchan.message, va("begin %i\n", precache_spawncount) );
-}
-
-/*
-=================
-CL_Precache_f
-
-The server will send this command right
-before allowing the client into the server
-=================
-*/
-void CL_Precache_f (void)
-{
- //Yet another hack to let old demos work
- //the old precache sequence
- if (Cmd_Argc() < 2) {
- unsigned map_checksum; // for detecting cheater maps
-
- CM_LoadMap (cl.configstrings[CS_MODELS+1], true, &map_checksum);
- CL_RegisterSounds ();
- CL_PrepRefresh ();
- return;
- }
-
- precache_check = CS_MODELS;
- precache_spawncount = atoi(Cmd_Argv(1));
- precache_model = 0;
- precache_model_skin = 0;
-
- CL_RequestNextDownload();
-}
-
-
-/*
-=================
-CL_InitLocal
-=================
-*/
-void CL_InitLocal (void)
-{
- cls.state = ca_disconnected;
- cls.realtime = Sys_Milliseconds ();
-
- CL_InitInput ();
-
- adr0 = Cvar_Get( "adr0", "", CVAR_ARCHIVE );
- adr1 = Cvar_Get( "adr1", "", CVAR_ARCHIVE );
- adr2 = Cvar_Get( "adr2", "", CVAR_ARCHIVE );
- adr3 = Cvar_Get( "adr3", "", CVAR_ARCHIVE );
- adr4 = Cvar_Get( "adr4", "", CVAR_ARCHIVE );
- adr5 = Cvar_Get( "adr5", "", CVAR_ARCHIVE );
- adr6 = Cvar_Get( "adr6", "", CVAR_ARCHIVE );
- adr7 = Cvar_Get( "adr7", "", CVAR_ARCHIVE );
- adr8 = Cvar_Get( "adr8", "", CVAR_ARCHIVE );
-
-//
-// register our variables
-//
- cl_stereo_separation = Cvar_Get( "cl_stereo_separation", "0.4", CVAR_ARCHIVE );
- cl_stereo = Cvar_Get( "cl_stereo", "0", 0 );
-
- cl_add_blend = Cvar_Get ("cl_blend", "1", 0);
- cl_add_lights = Cvar_Get ("cl_lights", "1", 0);
- cl_add_particles = Cvar_Get ("cl_particles", "1", 0);
- cl_add_entities = Cvar_Get ("cl_entities", "1", 0);
- cl_gun = Cvar_Get ("cl_gun", "1", 0);
- cl_footsteps = Cvar_Get ("cl_footsteps", "1", 0);
- cl_noskins = Cvar_Get ("cl_noskins", "0", 0);
- cl_autoskins = Cvar_Get ("cl_autoskins", "0", 0);
- cl_predict = Cvar_Get ("cl_predict", "1", 0);
-// cl_minfps = Cvar_Get ("cl_minfps", "5", 0);
- cl_maxfps = Cvar_Get ("cl_maxfps", "90", 0);
-
- cl_upspeed = Cvar_Get ("cl_upspeed", "200", 0);
- cl_forwardspeed = Cvar_Get ("cl_forwardspeed", "200", 0);
- cl_sidespeed = Cvar_Get ("cl_sidespeed", "200", 0);
- cl_yawspeed = Cvar_Get ("cl_yawspeed", "140", 0);
- cl_pitchspeed = Cvar_Get ("cl_pitchspeed", "150", 0);
- cl_anglespeedkey = Cvar_Get ("cl_anglespeedkey", "1.5", 0);
-
- cl_run = Cvar_Get ("cl_run", "0", CVAR_ARCHIVE);
-
- cl_shownet = Cvar_Get ("cl_shownet", "0", 0);
- cl_showmiss = Cvar_Get ("cl_showmiss", "0", 0);
- cl_showclamp = Cvar_Get ("showclamp", "0", 0);
- cl_timeout = Cvar_Get ("cl_timeout", "120", 0);
- cl_paused = Cvar_Get ("paused", "0", 0);
- cl_timedemo = Cvar_Get ("timedemo", "0", 0);
-
- rcon_client_password = Cvar_Get ("rcon_password", "", 0);
- rcon_address = Cvar_Get ("rcon_address", "", 0);
-
- cl_lightlevel = Cvar_Get ("r_lightlevel", "0", 0);
-
- //
- // userinfo
- //
- info_password = Cvar_Get ("password", "", CVAR_USERINFO);
- info_spectator = Cvar_Get ("spectator", "0", CVAR_USERINFO);
- name = Cvar_Get ("name", "unnamed", CVAR_USERINFO | CVAR_ARCHIVE);
- skin = Cvar_Get ("skin", "male/grunt", CVAR_USERINFO | CVAR_ARCHIVE);
- rate = Cvar_Get ("rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE); // FIXME
- msg = Cvar_Get ("msg", "1", CVAR_USERINFO | CVAR_ARCHIVE);
- hand = Cvar_Get ("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE);
- fov = Cvar_Get ("fov", "90", CVAR_USERINFO | CVAR_ARCHIVE);
- gender = Cvar_Get ("gender", "male", CVAR_USERINFO | CVAR_ARCHIVE);
- gender_auto = Cvar_Get ("gender_auto", "1", CVAR_ARCHIVE);
- gender->modified = false; // clear this so we know when user sets it manually
-
- cl_vwep = Cvar_Get ("cl_vwep", "1", CVAR_ARCHIVE);
-
-
- //
- // register our commands
- //
- Cmd_AddCommand ("cmd", CL_ForwardToServer_f);
- Cmd_AddCommand ("pause", CL_Pause_f);
- Cmd_AddCommand ("pingservers", CL_PingServers_f);
- Cmd_AddCommand ("skins", CL_Skins_f);
-
- Cmd_AddCommand ("userinfo", CL_Userinfo_f);
- Cmd_AddCommand ("snd_restart", CL_Snd_Restart_f);
-
- Cmd_AddCommand ("changing", CL_Changing_f);
- Cmd_AddCommand ("disconnect", CL_Disconnect_f);
- Cmd_AddCommand ("record", CL_Record_f);
- Cmd_AddCommand ("stop", CL_Stop_f);
-
- Cmd_AddCommand ("quit", CL_Quit_f);
-
- Cmd_AddCommand ("connect", CL_Connect_f);
- Cmd_AddCommand ("reconnect", CL_Reconnect_f);
-
- Cmd_AddCommand ("rcon", CL_Rcon_f);
-
-// Cmd_AddCommand ("packet", CL_Packet_f); // this is dangerous to leave in
-
- Cmd_AddCommand ("setenv", CL_Setenv_f );
-
- Cmd_AddCommand ("precache", CL_Precache_f);
-
- Cmd_AddCommand ("download", CL_Download_f);
-
- //
- // forward to server commands
- //
- // the only thing this does is allow command completion
- // to work -- all unknown commands are automatically
- // forwarded to the server
- Cmd_AddCommand ("wave", NULL);
- Cmd_AddCommand ("inven", NULL);
- Cmd_AddCommand ("kill", NULL);
- Cmd_AddCommand ("use", NULL);
- Cmd_AddCommand ("drop", NULL);
- Cmd_AddCommand ("say", NULL);
- Cmd_AddCommand ("say_team", NULL);
- Cmd_AddCommand ("info", NULL);
- Cmd_AddCommand ("prog", NULL);
- Cmd_AddCommand ("give", NULL);
- Cmd_AddCommand ("god", NULL);
- Cmd_AddCommand ("notarget", NULL);
- Cmd_AddCommand ("noclip", NULL);
- Cmd_AddCommand ("invuse", NULL);
- Cmd_AddCommand ("invprev", NULL);
- Cmd_AddCommand ("invnext", NULL);
- Cmd_AddCommand ("invdrop", NULL);
- Cmd_AddCommand ("weapnext", NULL);
- Cmd_AddCommand ("weapprev", NULL);
-}
-
-
-
-/*
-===============
-CL_WriteConfiguration
-
-Writes key bindings and archived cvars to config.cfg
-===============
-*/
-void CL_WriteConfiguration (void)
-{
- FILE *f;
- char path[MAX_QPATH];
-
- if (cls.state == ca_uninitialized)
- return;
-
- Com_sprintf (path, sizeof(path),"%s/config.cfg",FS_Gamedir());
- f = fopen (path, "w");
- if (!f)
- {
- Com_Printf ("Couldn't write config.cfg.\n");
- return;
- }
-
- fprintf (f, "// generated by quake, do not modify\n");
- Key_WriteBindings (f);
- fclose (f);
-
- Cvar_WriteVariables (path);
-}
-
-
-/*
-==================
-CL_FixCvarCheats
-
-==================
-*/
-
-typedef struct
-{
- char *name;
- char *value;
- cvar_t *var;
-} cheatvar_t;
-
-cheatvar_t cheatvars[] = {
- {"timescale", "1"},
- {"timedemo", "0"},
- {"r_drawworld", "1"},
- {"cl_testlights", "0"},
- {"r_fullbright", "0"},
- {"r_drawflat", "0"},
- {"paused", "0"},
- {"fixedtime", "0"},
- {"sw_draworder", "0"},
- {"gl_lightmap", "0"},
- {"gl_saturatelighting", "0"},
- {NULL, NULL}
-};
-
-int numcheatvars;
-
-void CL_FixCvarCheats (void)
-{
- int i;
- cheatvar_t *var;
-
- if ( !strcmp(cl.configstrings[CS_MAXCLIENTS], "1")
- || !cl.configstrings[CS_MAXCLIENTS][0] )
- return; // single player can cheat
-
- // find all the cvars if we haven't done it yet
- if (!numcheatvars)
- {
- while (cheatvars[numcheatvars].name)
- {
- cheatvars[numcheatvars].var = Cvar_Get (cheatvars[numcheatvars].name,
- cheatvars[numcheatvars].value, 0);
- numcheatvars++;
- }
- }
-
- // make sure they are all set to the proper values
- for (i=0, var = cheatvars ; i<numcheatvars ; i++, var++)
- {
- if ( strcmp (var->var->string, var->value) )
- {
- Cvar_Set (var->name, var->value);
- }
- }
-}
-
-//============================================================================
-
-/*
-==================
-CL_SendCommand
-
-==================
-*/
-void CL_SendCommand (void)
-{
- // get new key events
- Sys_SendKeyEvents ();
-
- // allow mice or other external controllers to add commands
- IN_Commands ();
-
- // process console commands
- Cbuf_Execute ();
-
- // fix any cheating cvars
- CL_FixCvarCheats ();
-
- // send intentions now
- CL_SendCmd ();
-
- // resend a connection request if necessary
- CL_CheckForResend ();
-}
-
-
-/*
-==================
-CL_Frame
-
-==================
-*/
-void CL_Frame (int msec)
-{
- static int extratime;
- static int lasttimecalled;
-
- if (dedicated->value)
- return;
-
- extratime += msec;
-
- if (!cl_timedemo->value)
- {
- if (cls.state == ca_connected && extratime < 100)
- return; // don't flood packets out while connecting
- if (extratime < 1000/cl_maxfps->value)
- return; // framerate is too high
- }
-
- // let the mouse activate or deactivate
- IN_Frame ();
-
- // decide the simulation time
- cls.frametime = extratime/1000.0;
- cl.time += extratime;
- cls.realtime = curtime;
-
- extratime = 0;
-/*
- if (cls.frametime > (1.0 / cl_minfps->value))
- cls.frametime = (1.0 / cl_minfps->value);
-*/
- if (cls.frametime > (1.0 / 5))
- cls.frametime = (1.0 / 5);
-
- // if in the debugger last frame, don't timeout
- if (msec > 5000)
- cls.netchan.last_received = Sys_Milliseconds ();
-
- // fetch results from server
- CL_ReadPackets ();
-
- // send a new command message to the server
- CL_SendCommand ();
-
- // predict all unacknowledged movements
- CL_PredictMovement ();
-
- // allow rendering DLL change
- VID_CheckChanges ();
- if (!cl.refresh_prepped && cls.state == ca_active)
- CL_PrepRefresh ();
-
- // update the screen
- if (host_speeds->value)
- time_before_ref = Sys_Milliseconds ();
- SCR_UpdateScreen ();
- if (host_speeds->value)
- time_after_ref = Sys_Milliseconds ();
-
- // update audio
- S_Update (cl.refdef.vieworg, cl.v_forward, cl.v_right, cl.v_up);
-
- CDAudio_Update();
-
- // advance local effects for next frame
- CL_RunDLights ();
- CL_RunLightStyles ();
- SCR_RunCinematic ();
- SCR_RunConsole ();
-
- cls.framecount++;
-
- if ( log_stats->value )
- {
- if ( cls.state == ca_active )
- {
- if ( !lasttimecalled )
- {
- lasttimecalled = Sys_Milliseconds();
- if ( log_stats_file )
- fprintf( log_stats_file, "0\n" );
- }
- else
- {
- int now = Sys_Milliseconds();
-
- if ( log_stats_file )
- fprintf( log_stats_file, "%d\n", now - lasttimecalled );
- lasttimecalled = now;
- }
- }
- }
-}
-
-
-//============================================================================
-
-/*
-====================
-CL_Init
-====================
-*/
-void CL_Init (void)
-{
- IN_Init();
-
- if(dedicated->value)
- return; // nothing running on the client
-
- // all archived variables will now be loaded
-
- Con_Init ();
- S_Init ();
- VID_Init ();
-
- V_Init ();
-
- net_message.data = net_message_buffer;
- net_message.maxsize = sizeof(net_message_buffer);
-
- M_Init ();
-
- SCR_Init ();
- cls.disable_screen = true; // don't draw yet
-
- CDAudio_Init ();
- CL_InitLocal ();
-
-// Cbuf_AddText ("exec autoexec.cfg\n");
- FS_ExecAutoexec ();
- Cbuf_Execute ();
-}
-
-
-/*
-===============
-CL_Shutdown
-
-FIXME: this is a callback from Sys_Quit and Com_Error. It would be better
-to run quit through here before the final handoff to the sys code.
-===============
-*/
-void CL_Shutdown(void)
-{
- static qboolean isdown = false;
-
- if (isdown)
- {
- printf ("recursive shutdown\n");
- return;
- }
- isdown = true;
-
- CL_WriteConfiguration ();
-
- CDAudio_Shutdown ();
- S_Shutdown();
- IN_Shutdown ();
- VID_Shutdown();
-}
-
-
--- a/client/cl_newfx.c
+++ /dev/null
@@ -1,1306 +1,0 @@
-// cl_newfx.c -- MORE entity effects parsing and management
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-extern cparticle_t *active_particles, *free_particles;
-extern cparticle_t particles[MAX_PARTICLES];
-extern int cl_numparticles;
-
-extern void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up);
-
-
-/*
-======
-vectoangles2 - this is duplicated in the game DLL, but I need it here.
-======
-*/
-void vectoangles2 (vec3_t value1, vec3_t angles)
-{
- float forward;
- float yaw, pitch;
-
- if (value1[1] == 0 && value1[0] == 0)
- {
- yaw = 0;
- if (value1[2] > 0)
- pitch = 90;
- else
- pitch = 270;
- }
- else
- {
- // PMM - fixed to correct for pitch of 0
- if (value1[0])
- yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
- else if (value1[1] > 0)
- yaw = 90;
- else
- yaw = 270;
-
- if (yaw < 0)
- yaw += 360;
-
- forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
- pitch = (atan2(value1[2], forward) * 180 / M_PI);
- if (pitch < 0)
- pitch += 360;
- }
-
- angles[PITCH] = -pitch;
- angles[YAW] = yaw;
- angles[ROLL] = 0;
-}
-
-//=============
-//=============
-void CL_Flashlight (int ent, vec3_t pos)
-{
- cdlight_t *dl;
-
- dl = CL_AllocDlight (ent);
- VectorCopy (pos, dl->origin);
- dl->radius = 400;
- dl->minlight = 250;
- dl->die = cl.time + 100;
- dl->color[0] = 1;
- dl->color[1] = 1;
- dl->color[2] = 1;
-}
-
-/*
-======
-CL_ColorFlash - flash of light
-======
-*/
-void CL_ColorFlash (vec3_t pos, int ent, int intensity, float r, float g, float b)
-{
- cdlight_t *dl;
-
- if((vidref_val == VIDREF_SOFT) && ((r < 0) || (g<0) || (b<0)))
- {
- intensity = -intensity;
- r = -r;
- g = -g;
- b = -b;
- }
-
- dl = CL_AllocDlight (ent);
- VectorCopy (pos, dl->origin);
- dl->radius = intensity;
- dl->minlight = 250;
- dl->die = cl.time + 100;
- dl->color[0] = r;
- dl->color[1] = g;
- dl->color[2] = b;
-}
-
-
-/*
-======
-CL_DebugTrail
-======
-*/
-void CL_DebugTrail (vec3_t start, vec3_t end)
-{
- vec3_t move;
- vec3_t vec;
- float len;
-// int j;
- cparticle_t *p;
- float dec;
- vec3_t right, up;
-// int i;
-// float d, c, s;
-// vec3_t dir;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- MakeNormalVectors (vec, right, up);
-
-// VectorScale(vec, RT2_SKIP, vec);
-
-// dec = 1.0;
-// dec = 0.75;
- dec = 3;
- VectorScale (vec, dec, vec);
- VectorCopy (start, move);
-
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- VectorClear (p->accel);
- VectorClear (p->vel);
- p->alpha = 1.0;
- p->alphavel = -0.1;
-// p->alphavel = 0;
- p->color = 0x74 + (rand()&7);
- VectorCopy (move, p->org);
-/*
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*2;
- p->vel[j] = crand()*3;
- p->accel[j] = 0;
- }
-*/
- VectorAdd (move, vec, move);
- }
-
-}
-
-/*
-===============
-CL_SmokeTrail
-===============
-*/
-void CL_SmokeTrail (vec3_t start, vec3_t end, int colorStart, int colorRun, int spacing)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- VectorScale (vec, spacing, vec);
-
- // FIXME: this is a really silly way to have a loop
- while (len > 0)
- {
- len -= spacing;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (1+qfrand()*0.5);
- p->color = colorStart + (rand() % colorRun);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*3;
- p->accel[j] = 0;
- }
- p->vel[2] = 20 + crand()*5;
-
- VectorAdd (move, vec, move);
- }
-}
-
-void CL_ForceWall (vec3_t start, vec3_t end, int color)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- VectorScale (vec, 4, vec);
-
- // FIXME: this is a really silly way to have a loop
- while (len > 0)
- {
- len -= 4;
-
- if (!free_particles)
- return;
-
- if (qfrand() > 0.3)
- {
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (3.0+qfrand()*0.5);
- p->color = color;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*3;
- p->accel[j] = 0;
- }
- p->vel[0] = 0;
- p->vel[1] = 0;
- p->vel[2] = -40 - (crand()*10);
- }
-
- VectorAdd (move, vec, move);
- }
-}
-
-void CL_FlameEffects (centity_t */*ent*/, vec3_t origin)
-{
- int n, count;
- int j;
- cparticle_t *p;
-
- count = rand() & 0xF;
-
- for(n=0;n<count;n++)
- {
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- VectorClear (p->accel);
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (1+qfrand()*0.2);
- p->color = 226 + (rand() % 4);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = origin[j] + crand()*5;
- p->vel[j] = crand()*5;
- }
- p->vel[2] = crand() * -10;
- p->accel[2] = -PARTICLE_GRAVITY;
- }
-
- count = rand() & 0x7;
-
- for(n=0;n<count;n++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (1+qfrand()*0.5);
- p->color = 0 + (rand() % 4);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = origin[j] + crand()*3;
- }
- p->vel[2] = 20 + crand()*5;
- }
-
-}
-
-
-/*
-===============
-CL_GenericParticleEffect
-===============
-*/
-void CL_GenericParticleEffect (vec3_t org, vec3_t dir, int color, int count, int numcolors, int dirspread, float alphavel)
-{
- int i, j;
- cparticle_t *p;
- float d;
-
- for (i=0 ; i<count ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- if (numcolors > 1)
- p->color = color + (rand() & numcolors);
- else
- p->color = color;
-
- d = rand() & dirspread;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
- p->vel[j] = crand()*20;
- }
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
-// VectorCopy (accel, p->accel);
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (0.5 + qfrand()*alphavel);
-// p->alphavel = alphavel;
- }
-}
-
-/*
-===============
-CL_BubbleTrail2 (lets you control the # of bubbles by setting the distance between the spawns)
-
-===============
-*/
-void CL_BubbleTrail2 (vec3_t start, vec3_t end, int dist)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int i, j;
- cparticle_t *p;
- float dec;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- dec = dist;
- VectorScale (vec, dec, vec);
-
- for (i=0 ; i<len ; i+=dec)
- {
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- VectorClear (p->accel);
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (1+qfrand()*0.1);
- p->color = 4 + (rand()&7);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*2;
- p->vel[j] = crand()*10;
- }
- p->org[2] -= 4;
-// p->vel[2] += 6;
- p->vel[2] += 20;
-
- VectorAdd (move, vec, move);
- }
-}
-
-//#define CORKSCREW 1
-//#define DOUBLE_SCREW 1
-#define RINGS 1
-//#define SPRAY 1
-
-#ifdef CORKSCREW
-void CL_Heatbeam (vec3_t start, vec3_t end)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j,k;
- cparticle_t *p;
- vec3_t right, up;
- int i;
- float d, c, s;
- vec3_t dir;
- float ltime;
- float step = 5.0;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
-// MakeNormalVectors (vec, right, up);
- VectorCopy (cl.v_right, right);
- VectorCopy (cl.v_up, up);
- VectorMA (move, -1, right, move);
- VectorMA (move, -1, up, move);
-
- VectorScale (vec, step, vec);
- ltime = (float) cl.time/1000.0;
-
-// for (i=0 ; i<len ; i++)
- for (i=0 ; i<len ; i+=step)
- {
- d = i * 0.1 - fmod(ltime,16.0)*M_PI;
- c = cos(d)/1.75;
- s = sin(d)/1.75;
-#ifdef DOUBLE_SCREW
- for (k=-1; k<2; k+=2)
- {
-#else
- k=1;
-#endif
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- VectorClear (p->accel);
-
- p->alpha = 0.5;
- // p->alphavel = -1.0 / (1+qfrand()*0.2);
- // only last one frame!
- p->alphavel = INSTANT_PARTICLE;
- // p->color = 0x74 + (rand()&7);
-// p->color = 223 - (rand()&7);
- p->color = 223;
-// p->color = 240;
-
- // trim it so it looks like it's starting at the origin
- if (i < 10)
- {
- VectorScale (right, c*(i/10.0)*k, dir);
- VectorMA (dir, s*(i/10.0)*k, up, dir);
- }
- else
- {
- VectorScale (right, c*k, dir);
- VectorMA (dir, s*k, up, dir);
- }
-
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + dir[j]*3;
- // p->vel[j] = dir[j]*6;
- p->vel[j] = 0;
- }
-#ifdef DOUBLE_SCREW
- }
-#endif
- VectorAdd (move, vec, move);
- }
-}
-#endif
-#ifdef RINGS
-//void CL_Heatbeam (vec3_t start, vec3_t end)
-void CL_Heatbeam (vec3_t start, vec3_t forward)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- vec3_t right, up;
- int i;
- float c, s;
- vec3_t dir;
- float ltime;
- float step = 32.0, rstep;
- float start_pt;
- float rot;
- float variance;
- vec3_t end;
-
- VectorMA (start, 4096, forward, end);
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- // FIXME - pmm - these might end up using old values?
-// MakeNormalVectors (vec, right, up);
- VectorCopy (cl.v_right, right);
- VectorCopy (cl.v_up, up);
- if (vidref_val == VIDREF_GL)
- { // GL mode
- VectorMA (move, -0.5, right, move);
- VectorMA (move, -0.5, up, move);
- }
- // otherwise assume SOFT
-
- ltime = (float) cl.time/1000.0;
- start_pt = fmod(ltime*96.0,step);
- VectorMA (move, start_pt, vec, move);
-
- VectorScale (vec, step, vec);
-
-// Com_Printf ("%f\n", ltime);
- rstep = M_PI/10.0;
- for (i=start_pt ; i<len ; i+=step)
- {
- if (i>step*5) // don't bother after the 5th ring
- break;
-
- for (rot = 0; rot < M_PI*2; rot += rstep)
- {
-
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- VectorClear (p->accel);
-// rot+= fmod(ltime, 12.0)*M_PI;
-// c = cos(rot)/2.0;
-// s = sin(rot)/2.0;
-// variance = 0.4 + ((float)rand()/(float)RAND_MAX) *0.2;
- variance = 0.5;
- c = cos(rot)*variance;
- s = sin(rot)*variance;
-
- // trim it so it looks like it's starting at the origin
- if (i < 10)
- {
- VectorScale (right, c*(i/10.0), dir);
- VectorMA (dir, s*(i/10.0), up, dir);
- }
- else
- {
- VectorScale (right, c, dir);
- VectorMA (dir, s, up, dir);
- }
-
- p->alpha = 0.5;
- // p->alphavel = -1.0 / (1+qfrand()*0.2);
- p->alphavel = -1000.0;
- // p->color = 0x74 + (rand()&7);
- p->color = 223 - (rand()&7);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + dir[j]*3;
- // p->vel[j] = dir[j]*6;
- p->vel[j] = 0;
- }
- }
- VectorAdd (move, vec, move);
- }
-}
-#endif
-#ifdef SPRAY
-void CL_Heatbeam (vec3_t start, vec3_t end)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- vec3_t forward, right, up;
- int i;
- float d, c, s;
- vec3_t dir;
- float ltime;
- float step = 32.0, rstep;
- float start_pt;
- float rot;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
-// MakeNormalVectors (vec, right, up);
- VectorCopy (cl.v_forward, forward);
- VectorCopy (cl.v_right, right);
- VectorCopy (cl.v_up, up);
- VectorMA (move, -0.5, right, move);
- VectorMA (move, -0.5, up, move);
-
- for (i=0; i<8; i++)
- {
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- VectorClear (p->accel);
-
- d = crand()*M_PI;
- c = cos(d)*30;
- s = sin(d)*30;
-
- p->alpha = 1.0;
- p->alphavel = -5.0 / (1+qfrand());
- p->color = 223 - (rand()&7);
-
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j];
- }
- VectorScale (vec, 450, p->vel);
- VectorMA (p->vel, c, right, p->vel);
- VectorMA (p->vel, s, up, p->vel);
- }
-/*
-
- ltime = (float) cl.time/1000.0;
- start_pt = fmod(ltime*16.0,step);
- VectorMA (move, start_pt, vec, move);
-
- VectorScale (vec, step, vec);
-
-// Com_Printf ("%f\n", ltime);
- rstep = M_PI/12.0;
- for (i=start_pt ; i<len ; i+=step)
- {
- if (i>step*5) // don't bother after the 5th ring
- break;
-
- for (rot = 0; rot < M_PI*2; rot += rstep)
- {
- if (!free_particles)
- return;
-
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- VectorClear (p->accel);
-// rot+= fmod(ltime, 12.0)*M_PI;
-// c = cos(rot)/2.0;
-// s = sin(rot)/2.0;
- c = cos(rot)/1.5;
- s = sin(rot)/1.5;
-
- // trim it so it looks like it's starting at the origin
- if (i < 10)
- {
- VectorScale (right, c*(i/10.0), dir);
- VectorMA (dir, s*(i/10.0), up, dir);
- }
- else
- {
- VectorScale (right, c, dir);
- VectorMA (dir, s, up, dir);
- }
-
- p->alpha = 0.5;
- // p->alphavel = -1.0 / (1+qfrand()*0.2);
- p->alphavel = -1000.0;
- // p->color = 0x74 + (rand()&7);
- p->color = 223 - (rand()&7);
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + dir[j]*3;
- // p->vel[j] = dir[j]*6;
- p->vel[j] = 0;
- }
- }
- VectorAdd (move, vec, move);
- }
-*/
-}
-#endif
-
-/*
-===============
-CL_ParticleSteamEffect
-
-Puffs with velocity along direction, with some randomness thrown in
-===============
-*/
-void CL_ParticleSteamEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude)
-{
- int i, j;
- cparticle_t *p;
- float d;
- vec3_t r, u;
-
-// vectoangles2 (dir, angle_dir);
-// AngleVectors (angle_dir, f, r, u);
-
- MakeNormalVectors (dir, r, u);
-
- for (i=0 ; i<count ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = color + (rand()&7);
-
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + magnitude*0.1*crand();
-// p->vel[j] = dir[j]*magnitude;
- }
- VectorScale (dir, magnitude, p->vel);
- d = crand()*magnitude/3;
- VectorMA (p->vel, d, r, p->vel);
- d = crand()*magnitude/3;
- VectorMA (p->vel, d, u, p->vel);
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY/2;
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
- }
-}
-
-void CL_ParticleSteamEffect2 (cl_sustain_t *self)
-//vec3_t org, vec3_t dir, int color, int count, int magnitude)
-{
- int i, j;
- cparticle_t *p;
- float d;
- vec3_t r, u;
- vec3_t dir;
-
-// vectoangles2 (dir, angle_dir);
-// AngleVectors (angle_dir, f, r, u);
-
- VectorCopy (self->dir, dir);
- MakeNormalVectors (dir, r, u);
-
- for (i=0 ; i<self->count ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = self->color + (rand()&7);
-
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = self->org[j] + self->magnitude*0.1*crand();
-// p->vel[j] = dir[j]*magnitude;
- }
- VectorScale (dir, self->magnitude, p->vel);
- d = crand()*self->magnitude/3;
- VectorMA (p->vel, d, r, p->vel);
- d = crand()*self->magnitude/3;
- VectorMA (p->vel, d, u, p->vel);
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY/2;
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
- }
- self->nextthink += self->thinkinterval;
-}
-
-/*
-===============
-CL_TrackerTrail
-===============
-*/
-void CL_TrackerTrail (vec3_t start, vec3_t end, int particleColor)
-{
- vec3_t move;
- vec3_t vec;
- vec3_t forward,right,up,angle_dir;
- float len;
- int j;
- cparticle_t *p;
- int dec;
- float dist;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- VectorCopy(vec, forward);
- vectoangles2 (forward, angle_dir);
- AngleVectors (angle_dir, forward, right, up);
-
- dec = 3;
- VectorScale (vec, 3, vec);
-
- // FIXME: this is a really silly way to have a loop
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -2.0;
- p->color = particleColor;
- dist = DotProduct(move, forward);
- VectorMA(move, 8 * cos(dist), up, p->org);
- for (j=0 ; j<3 ; j++)
- {
-// p->org[j] = move[j] + crand();
- p->vel[j] = 0;
- p->accel[j] = 0;
- }
- p->vel[2] = 5;
-
- VectorAdd (move, vec, move);
- }
-}
-
-void CL_Tracker_Shell(vec3_t origin)
-{
- vec3_t dir;
- int i;
- cparticle_t *p;
-
- for(i=0;i<300;i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = INSTANT_PARTICLE;
- p->color = 0;
-
- dir[0] = crand();
- dir[1] = crand();
- dir[2] = crand();
- VectorNormalize(dir);
-
- VectorMA(origin, 40, dir, p->org);
- }
-}
-
-void CL_MonsterPlasma_Shell(vec3_t origin)
-{
- vec3_t dir;
- int i;
- cparticle_t *p;
-
- for(i=0;i<40;i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = INSTANT_PARTICLE;
- p->color = 0xe0;
-
- dir[0] = crand();
- dir[1] = crand();
- dir[2] = crand();
- VectorNormalize(dir);
-
- VectorMA(origin, 10, dir, p->org);
-// VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
- }
-}
-
-void CL_Widowbeamout (cl_sustain_t *self)
-{
- vec3_t dir;
- int i;
- cparticle_t *p;
- static int colortable[4] = {2*8,13*8,21*8,18*8};
- float ratio;
-
- ratio = 1.0 - (((float)self->endtime - (float)cl.time)/2100.0);
-
- for(i=0;i<300;i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = INSTANT_PARTICLE;
- p->color = colortable[rand()&3];
-
- dir[0] = crand();
- dir[1] = crand();
- dir[2] = crand();
- VectorNormalize(dir);
-
- VectorMA(self->org, (45.0 * ratio), dir, p->org);
-// VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
- }
-}
-
-void CL_Nukeblast (cl_sustain_t *self)
-{
- vec3_t dir;
- int i;
- cparticle_t *p;
- static int colortable[4] = {110, 112, 114, 116};
- float ratio;
-
- ratio = 1.0 - (((float)self->endtime - (float)cl.time)/1000.0);
-
- for(i=0;i<700;i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = INSTANT_PARTICLE;
- p->color = colortable[rand()&3];
-
- dir[0] = crand();
- dir[1] = crand();
- dir[2] = crand();
- VectorNormalize(dir);
-
- VectorMA(self->org, (200.0 * ratio), dir, p->org);
-// VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p->org);
- }
-}
-
-void CL_WidowSplash (vec3_t org)
-{
- static int colortable[4] = {2*8,13*8,21*8,18*8};
- int i;
- cparticle_t *p;
- vec3_t dir;
-
- for (i=0 ; i<256 ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = colortable[rand()&3];
-
- dir[0] = crand();
- dir[1] = crand();
- dir[2] = crand();
- VectorNormalize(dir);
- VectorMA(org, 45.0, dir, p->org);
- VectorMA(vec3_origin, 40.0, dir, p->vel);
-
- p->accel[0] = p->accel[1] = 0;
- p->alpha = 1.0;
-
- p->alphavel = -0.8 / (0.5 + qfrand()*0.3);
- }
-
-}
-
-void CL_Tracker_Explode(vec3_t origin)
-{
- vec3_t dir, backdir;
- int i;
- cparticle_t *p;
-
- for(i=0;i<300;i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0;
- p->color = 0;
-
- dir[0] = crand();
- dir[1] = crand();
- dir[2] = crand();
- VectorNormalize(dir);
- VectorScale(dir, -1, backdir);
-
- VectorMA(origin, 64, dir, p->org);
- VectorScale(backdir, 64, p->vel);
- }
-
-}
-
-/*
-===============
-CL_TagTrail
-
-===============
-*/
-void CL_TagTrail (vec3_t start, vec3_t end, float color)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- int dec;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- dec = 5;
- VectorScale (vec, 5, vec);
-
- while (len >= 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (0.8+qfrand()*0.2);
- p->color = color;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand()*16;
- p->vel[j] = crand()*5;
- p->accel[j] = 0;
- }
-
- VectorAdd (move, vec, move);
- }
-}
-
-/*
-===============
-CL_ColorExplosionParticles
-===============
-*/
-void CL_ColorExplosionParticles (vec3_t org, int color, int run)
-{
- int i, j;
- cparticle_t *p;
-
- for (i=0 ; i<128 ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = color + (rand() % run);
-
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + ((rand()%32)-16);
- p->vel[j] = (rand()%256)-128;
- }
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- p->alpha = 1.0;
-
- p->alphavel = -0.4 / (0.6 + qfrand()*0.2);
- }
-}
-
-/*
-===============
-CL_ParticleSmokeEffect - like the steam effect, but unaffected by gravity
-===============
-*/
-void CL_ParticleSmokeEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude)
-{
- int i, j;
- cparticle_t *p;
- float d;
- vec3_t r, u;
-
- MakeNormalVectors (dir, r, u);
-
- for (i=0 ; i<count ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = color + (rand()&7);
-
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + magnitude*0.1*crand();
-// p->vel[j] = dir[j]*magnitude;
- }
- VectorScale (dir, magnitude, p->vel);
- d = crand()*magnitude/3;
- VectorMA (p->vel, d, r, p->vel);
- d = crand()*magnitude/3;
- VectorMA (p->vel, d, u, p->vel);
-
- p->accel[0] = p->accel[1] = p->accel[2] = 0;
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
- }
-}
-
-/*
-===============
-CL_BlasterParticles2
-
-Wall impact puffs (Green)
-===============
-*/
-void CL_BlasterParticles2 (vec3_t org, vec3_t dir, unsigned int color)
-{
- int i, j;
- cparticle_t *p;
- float d;
- int count;
-
- count = 40;
- for (i=0 ; i<count ; i++)
- {
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
-
- p->time = cl.time;
- p->color = color + (rand()&7);
-
- d = rand()&15;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = org[j] + ((rand()&7)-4) + d*dir[j];
- p->vel[j] = dir[j] * 30 + crand()*40;
- }
-
- p->accel[0] = p->accel[1] = 0;
- p->accel[2] = -PARTICLE_GRAVITY;
- p->alpha = 1.0;
-
- p->alphavel = -1.0 / (0.5 + qfrand()*0.3);
- }
-}
-
-/*
-===============
-CL_BlasterTrail2
-
-Green!
-===============
-*/
-void CL_BlasterTrail2 (vec3_t start, vec3_t end)
-{
- vec3_t move;
- vec3_t vec;
- float len;
- int j;
- cparticle_t *p;
- int dec;
-
- VectorCopy (start, move);
- VectorSubtract (end, start, vec);
- len = VectorNormalize (vec);
-
- dec = 5;
- VectorScale (vec, 5, vec);
-
- // FIXME: this is a really silly way to have a loop
- while (len > 0)
- {
- len -= dec;
-
- if (!free_particles)
- return;
- p = free_particles;
- free_particles = p->next;
- p->next = active_particles;
- active_particles = p;
- VectorClear (p->accel);
-
- p->time = cl.time;
-
- p->alpha = 1.0;
- p->alphavel = -1.0 / (0.3+qfrand()*0.2);
- p->color = 0xd0;
- for (j=0 ; j<3 ; j++)
- {
- p->org[j] = move[j] + crand();
- p->vel[j] = crand()*5;
- p->accel[j] = 0;
- }
-
- VectorAdd (move, vec, move);
- }
-}
--- a/client/cl_parse.c
+++ /dev/null
@@ -1,802 +1,0 @@
-// cl_parse.c -- parse a message received from the server
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-char *svc_strings[256] =
-{
- "svc_bad",
-
- "svc_muzzleflash",
- "svc_muzzlflash2",
- "svc_temp_entity",
- "svc_layout",
- "svc_inventory",
-
- "svc_nop",
- "svc_disconnect",
- "svc_reconnect",
- "svc_sound",
- "svc_print",
- "svc_stufftext",
- "svc_serverdata",
- "svc_configstring",
- "svc_spawnbaseline",
- "svc_centerprint",
- "svc_download",
- "svc_playerinfo",
- "svc_packetentities",
- "svc_deltapacketentities",
- "svc_frame"
-};
-
-//=============================================================================
-
-void CL_DownloadFileName(char *dest, int destlen, char *fn)
-{
- if (strncmp(fn, "players", 7) == 0)
- Com_sprintf (dest, destlen, "%s/%s", BASEDIRNAME, fn);
- else
- Com_sprintf (dest, destlen, "%s/%s", FS_Gamedir(), fn);
-}
-
-/*
-===============
-CL_CheckOrDownloadFile
-
-Returns true if the file exists, otherwise it attempts
-to start a download from the server.
-===============
-*/
-qboolean CL_CheckOrDownloadFile (char *filename)
-{
- FILE *fp;
- char name[MAX_OSPATH];
-
- if (strstr (filename, ".."))
- {
- Com_Printf ("Refusing to download a path with ..\n");
- return true;
- }
-
- if (FS_LoadFile (filename, NULL) != -1)
- { // it exists, no need to download
- return true;
- }
-
- strcpy (cls.downloadname, filename);
-
- // download to a temp name, and only rename
- // to the real name when done, so if interrupted
- // a runt file wont be left
- COM_StripExtension (cls.downloadname, cls.downloadtempname);
- strcat (cls.downloadtempname, ".tmp");
-
-//ZOID
- // check to see if we already have a tmp for this file, if so, try to resume
- // open the file if not opened yet
- CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
-
-// FS_CreatePath (name);
-
- fp = fopen (name, "r+b");
- if (fp) { // it exists
- int len;
- fseek(fp, 0, SEEK_END);
- len = ftell(fp);
-
- cls.download = fp;
-
- // give the server an offset to start the download
- Com_Printf ("Resuming %s\n", cls.downloadname);
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- MSG_WriteString (&cls.netchan.message,
- va("download %s %i", cls.downloadname, len));
- } else {
- Com_Printf ("Downloading %s\n", cls.downloadname);
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- MSG_WriteString (&cls.netchan.message,
- va("download %s", cls.downloadname));
- }
-
- cls.downloadnumber++;
-
- return false;
-}
-
-/*
-===============
-CL_Download_f
-
-Request a download from the server
-===============
-*/
-void CL_Download_f (void)
-{
- char filename[MAX_OSPATH];
-
- if (Cmd_Argc() != 2) {
- Com_Printf("Usage: download <filename>\n");
- return;
- }
-
- Com_sprintf(filename, sizeof(filename), "%s", Cmd_Argv(1));
-
- if (strstr (filename, ".."))
- {
- Com_Printf ("Refusing to download a path with ..\n");
- return;
- }
-
- if (FS_LoadFile (filename, NULL) != -1)
- { // it exists, no need to download
- Com_Printf("File already exists.\n");
- return;
- }
-
- strcpy (cls.downloadname, filename);
- Com_Printf ("Downloading %s\n", cls.downloadname);
-
- // download to a temp name, and only rename
- // to the real name when done, so if interrupted
- // a runt file wont be left
- COM_StripExtension (cls.downloadname, cls.downloadtempname);
- strcat (cls.downloadtempname, ".tmp");
-
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- MSG_WriteString (&cls.netchan.message,
- va("download %s", cls.downloadname));
-
- cls.downloadnumber++;
-}
-
-/*
-======================
-CL_RegisterSounds
-======================
-*/
-void CL_RegisterSounds (void)
-{
- int i;
-
- S_BeginRegistration ();
- CL_RegisterTEntSounds ();
- for (i=1 ; i<MAX_SOUNDS ; i++)
- {
- if (!cl.configstrings[CS_SOUNDS+i][0])
- break;
- cl.sound_precache[i] = S_RegisterSound (cl.configstrings[CS_SOUNDS+i]);
- Sys_SendKeyEvents (); // pump message loop
- }
- S_EndRegistration ();
-}
-
-static void
-rename(char *old, char *new)
-{
- char *p;
- Dir d;
-
- if((p = strrchr(new, '/')) == nil)
- p = new;
- else
- p++;
- nulldir(&d);
- d.name = p;
- if(dirwstat(old, &d) < 0)
- fprint(2, "rename: %r\n");
-}
-
-/*
-=====================
-CL_ParseDownload
-
-A download message has been received from the server
-=====================
-*/
-void CL_ParseDownload (void)
-{
- int size, percent;
- char name[MAX_OSPATH];
-
- // read the data
- size = MSG_ReadShort (&net_message);
- percent = MSG_ReadByte (&net_message);
- if (size == -1)
- {
- Com_Printf ("Server does not have this file.\n");
- if (cls.download)
- {
- // if here, we tried to resume a file but the server said no
- fclose (cls.download);
- cls.download = NULL;
- }
- CL_RequestNextDownload ();
- return;
- }
-
- // open the file if not opened yet
- if (!cls.download)
- {
- CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
-
- FS_CreatePath (name);
-
- cls.download = fopen (name, "wb");
- if (!cls.download)
- {
- net_message.readcount += size;
- Com_Printf ("Failed to open %s\n", cls.downloadtempname);
- CL_RequestNextDownload ();
- return;
- }
- }
-
- fwrite (net_message.data + net_message.readcount, 1, size, cls.download);
- net_message.readcount += size;
-
- if (percent != 100)
- {
- // request next block
-// change display routines by zoid
-/*
- Com_Printf (".");
- if (10*(percent/10) != cls.downloadpercent)
- {
- cls.downloadpercent = 10*(percent/10);
- Com_Printf ("%i%%", cls.downloadpercent);
- }
-*/
- cls.downloadpercent = percent;
-
- MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
- SZ_Print (&cls.netchan.message, "nextdl");
- }
- else
- {
- char oldn[MAX_OSPATH];
- char newn[MAX_OSPATH];
-
-// Com_Printf ("100%%\n");
-
- fclose (cls.download);
-
- // rename the temp file to it's final name
- CL_DownloadFileName(oldn, sizeof(oldn), cls.downloadtempname);
- CL_DownloadFileName(newn, sizeof(newn), cls.downloadname);
- rename (oldn, newn); /* FIXME */
-
- cls.download = NULL;
- cls.downloadpercent = 0;
-
- // get another file if needed
-
- CL_RequestNextDownload ();
- }
-}
-
-
-/*
-=====================================================================
-
- SERVER CONNECTING MESSAGES
-
-=====================================================================
-*/
-
-/*
-==================
-CL_ParseServerData
-==================
-*/
-void CL_ParseServerData (void)
-{
- extern cvar_t *fs_gamedirvar;
- char *str;
- int i;
-
- Com_DPrintf ("Serverdata packet received.\n");
-//
-// wipe the client_state_t struct
-//
- CL_ClearState ();
- cls.state = ca_connected;
-
-// parse protocol version number
- i = MSG_ReadLong (&net_message);
- cls.serverProtocol = i;
-
- // BIG HACK to let demos from release work with the 3.0x patch!!!
- if (Com_ServerState() && PROTOCOL_VERSION == 34)
- {
- }
- else if (i != PROTOCOL_VERSION)
- Com_Error (ERR_DROP,"Server returned version %i, not %i", i, PROTOCOL_VERSION);
-
- cl.servercount = MSG_ReadLong (&net_message);
- cl.attractloop = MSG_ReadByte (&net_message);
-
- // game directory
- str = MSG_ReadString (&net_message);
- strncpy (cl.gamedir, str, sizeof(cl.gamedir)-1);
-
- // set gamedir
- if ((*str && (!fs_gamedirvar->string || !*fs_gamedirvar->string || strcmp(fs_gamedirvar->string, str))) || (!*str && (fs_gamedirvar->string || *fs_gamedirvar->string)))
- Cvar_Set("game", str);
-
- // parse player entity number
- cl.playernum = MSG_ReadShort (&net_message);
-
- // get the full level name
- str = MSG_ReadString (&net_message);
-
- if (cl.playernum == -1)
- { // playing a cinematic or showing a pic, not a level
- SCR_PlayCinematic (str);
- }
- else
- {
- // seperate the printfs so the server message can have a color
- Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
- Com_Printf ("%c%s\n", 2, str);
-
- // need to prep refresh at next oportunity
- cl.refresh_prepped = false;
- }
-}
-
-/*
-==================
-CL_ParseBaseline
-==================
-*/
-void CL_ParseBaseline (void)
-{
- entity_state_t *es;
- int bits;
- int newnum;
- entity_state_t nullstate;
-
- memset (&nullstate, 0, sizeof(nullstate));
-
- newnum = CL_ParseEntityBits (&bits);
- es = &cl_entities[newnum].baseline;
- CL_ParseDelta (&nullstate, es, newnum, bits);
-}
-
-
-/*
-================
-CL_LoadClientinfo
-
-================
-*/
-void CL_LoadClientinfo (clientinfo_t *ci, char *s)
-{
- int i;
- char *t;
- char model_name[MAX_QPATH];
- char skin_name[MAX_QPATH];
- char model_filename[MAX_QPATH];
- char skin_filename[MAX_QPATH];
- char weapon_filename[MAX_QPATH];
-
- strncpy(ci->cinfo, s, sizeof(ci->cinfo));
- ci->cinfo[sizeof(ci->cinfo)-1] = 0;
-
- // isolate the player's name
- strncpy(ci->name, s, sizeof(ci->name));
- ci->name[sizeof(ci->name)-1] = 0;
- t = strstr (s, "\\");
- if (t)
- {
- ci->name[t-s] = 0;
- s = t+1;
- }
-
- if (cl_noskins->value || *s == 0)
- {
- Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
- Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/weapon.md2");
- Com_sprintf (skin_filename, sizeof(skin_filename), "players/male/grunt.pcx");
- Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/male/grunt_i.pcx");
- ci->model = re.RegisterModel (model_filename);
- memset(ci->weaponmodel, 0, sizeof(ci->weaponmodel));
- ci->weaponmodel[0] = re.RegisterModel (weapon_filename);
- ci->skin = re.RegisterSkin (skin_filename);
- ci->icon = re.RegisterPic (ci->iconname);
- }
- else
- {
- // isolate the model name
- strcpy (model_name, s);
- t = strstr(model_name, "/");
- if (!t)
- t = strstr(model_name, "\\");
- if (!t)
- t = model_name;
- *t = 0;
-
- // isolate the skin name
- strcpy (skin_name, s + strlen(model_name) + 1);
-
- // model file
- Com_sprintf (model_filename, sizeof(model_filename), "players/%s/tris.md2", model_name);
- ci->model = re.RegisterModel (model_filename);
- if (!ci->model)
- {
- strcpy(model_name, "male");
- Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
- ci->model = re.RegisterModel (model_filename);
- }
-
- // skin file
- Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
- ci->skin = re.RegisterSkin (skin_filename);
-
- // if we don't have the skin and the model wasn't male,
- // see if the male has it (this is for CTF's skins)
- if (!ci->skin && cistrcmp(model_name, "male"))
- {
- // change model to male
- strcpy(model_name, "male");
- Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
- ci->model = re.RegisterModel (model_filename);
-
- // see if the skin exists for the male model
- Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
- ci->skin = re.RegisterSkin (skin_filename);
- }
-
- // if we still don't have a skin, it means that the male model didn't have
- // it, so default to grunt
- if (!ci->skin) {
- // see if the skin exists for the male model
- Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/grunt.pcx", model_name, skin_name);
- ci->skin = re.RegisterSkin (skin_filename);
- }
-
- // weapon file
- for (i = 0; i < num_cl_weaponmodels; i++) {
- Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/%s/%s", model_name, cl_weaponmodels[i]);
- ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
- if (!ci->weaponmodel[i] && strcmp(model_name, "cyborg") == 0) {
- // try male
- Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/%s", cl_weaponmodels[i]);
- ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
- }
- if (!cl_vwep->value)
- break; // only one when vwep is off
- }
-
- // icon file
- Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/%s/%s_i.pcx", model_name, skin_name);
- ci->icon = re.RegisterPic (ci->iconname);
- }
-
- // must have loaded all data types to be valud
- if (!ci->skin || !ci->icon || !ci->model || !ci->weaponmodel[0])
- {
- ci->skin = NULL;
- ci->icon = NULL;
- ci->model = NULL;
- ci->weaponmodel[0] = NULL;
- return;
- }
-}
-
-/*
-================
-CL_ParseClientinfo
-
-Load the skin, icon, and model for a client
-================
-*/
-void CL_ParseClientinfo (int player)
-{
- char *s;
- clientinfo_t *ci;
-
- s = cl.configstrings[player+CS_PLAYERSKINS];
-
- ci = &cl.clientinfo[player];
-
- CL_LoadClientinfo (ci, s);
-}
-
-
-/*
-================
-CL_ParseConfigString
-================
-*/
-void CL_ParseConfigString (void)
-{
- int i;
- char *s;
-
- i = MSG_ReadShort (&net_message);
- if (i < 0 || i >= MAX_CONFIGSTRINGS)
- Com_Error (ERR_DROP, "configstring > MAX_CONFIGSTRINGS");
- s = MSG_ReadString(&net_message);
- strcpy (cl.configstrings[i], s);
-
- // do something apropriate
-
- if (i >= CS_LIGHTS && i < CS_LIGHTS+MAX_LIGHTSTYLES)
- CL_SetLightstyle (i - CS_LIGHTS);
- else if (i == CS_CDTRACK)
- {
- if (cl.refresh_prepped)
- CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
- }
- else if (i >= CS_MODELS && i < CS_MODELS+MAX_MODELS)
- {
- if (cl.refresh_prepped)
- {
- cl.model_draw[i-CS_MODELS] = re.RegisterModel (cl.configstrings[i]);
- if (cl.configstrings[i][0] == '*')
- cl.model_clip[i-CS_MODELS] = CM_InlineModel (cl.configstrings[i]);
- else
- cl.model_clip[i-CS_MODELS] = NULL;
- }
- }
- else if (i >= CS_SOUNDS && i < CS_SOUNDS+MAX_MODELS)
- {
- if (cl.refresh_prepped)
- cl.sound_precache[i-CS_SOUNDS] = S_RegisterSound (cl.configstrings[i]);
- }
- else if (i >= CS_IMAGES && i < CS_IMAGES+MAX_MODELS)
- {
- if (cl.refresh_prepped)
- cl.image_precache[i-CS_IMAGES] = re.RegisterPic (cl.configstrings[i]);
- }
- else if (i >= CS_PLAYERSKINS && i < CS_PLAYERSKINS+MAX_CLIENTS)
- {
- if (cl.refresh_prepped)
- CL_ParseClientinfo (i-CS_PLAYERSKINS);
- }
-}
-
-
-/*
-=====================================================================
-
-ACTION MESSAGES
-
-=====================================================================
-*/
-
-/*
-==================
-CL_ParseStartSoundPacket
-==================
-*/
-void CL_ParseStartSoundPacket(void)
-{
- vec3_t pos_v;
- float *pos;
- int channel, ent;
- int sound_num;
- float volume;
- float attenuation;
- int flags;
- float ofs;
-
- flags = MSG_ReadByte (&net_message);
- sound_num = MSG_ReadByte (&net_message);
-
- if (flags & SND_VOLUME)
- volume = MSG_ReadByte (&net_message) / 255.0;
- else
- volume = DEFAULT_SOUND_PACKET_VOLUME;
-
- if (flags & SND_ATTENUATION)
- attenuation = MSG_ReadByte (&net_message) / 64.0;
- else
- attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
-
- if (flags & SND_OFFSET)
- ofs = MSG_ReadByte (&net_message) / 1000.0;
- else
- ofs = 0;
-
- if (flags & SND_ENT)
- { // entity reletive
- channel = MSG_ReadShort(&net_message);
- ent = channel>>3;
- if (ent > MAX_EDICTS)
- Com_Error (ERR_DROP,"CL_ParseStartSoundPacket: ent = %i", ent);
-
- channel &= 7;
- }
- else
- {
- ent = 0;
- channel = 0;
- }
-
- if (flags & SND_POS)
- { // positioned in space
- MSG_ReadPos (&net_message, pos_v);
-
- pos = pos_v;
- }
- else // use entity number
- pos = NULL;
-
- if (!cl.sound_precache[sound_num])
- return;
-
- S_StartSound (pos, ent, channel, cl.sound_precache[sound_num], volume, attenuation, ofs);
-}
-
-
-void SHOWNET(char *s)
-{
- if (cl_shownet->value>=2)
- Com_Printf ("%3i:%s\n", net_message.readcount-1, s);
-}
-
-/*
-=====================
-CL_ParseServerMessage
-=====================
-*/
-void CL_ParseServerMessage (void)
-{
- int cmd;
- char *s;
- int i;
-
-//
-// if recording demos, copy the message out
-//
- if (cl_shownet->value == 1)
- Com_Printf ("%i ",net_message.cursize);
- else if (cl_shownet->value >= 2)
- Com_Printf ("------------------\n");
-
-
-//
-// parse the message
-//
- while (1)
- {
- if (net_message.readcount > net_message.cursize)
- {
- Com_Error (ERR_DROP,"CL_ParseServerMessage: Bad server message");
- break;
- }
-
- cmd = MSG_ReadByte (&net_message);
-
- if (cmd == -1)
- {
- SHOWNET("END OF MESSAGE");
- break;
- }
-
- if (cl_shownet->value>=2)
- {
- if (!svc_strings[cmd])
- Com_Printf ("%3i:BAD CMD %i\n", net_message.readcount-1,cmd);
- else
- SHOWNET(svc_strings[cmd]);
- }
-
- // other commands
- switch (cmd)
- {
- default:
- Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
- break;
-
- case svc_nop:
-// Com_Printf ("svc_nop\n");
- break;
-
- case svc_disconnect:
- Com_Error (ERR_DISCONNECT,"Server disconnected\n");
- break;
-
- case svc_reconnect:
- Com_Printf ("Server disconnected, reconnecting\n");
- if (cls.download) {
- //ZOID, close download
- fclose (cls.download);
- cls.download = NULL;
- }
- cls.state = ca_connecting;
- cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
- break;
-
- case svc_print:
- i = MSG_ReadByte (&net_message);
- if (i == PRINT_CHAT)
- {
- S_StartLocalSound ("misc/talk.wav");
- con.ormask = 128;
- }
- Com_Printf ("%s", MSG_ReadString (&net_message));
- con.ormask = 0;
- break;
-
- case svc_centerprint:
- SCR_CenterPrint (MSG_ReadString (&net_message));
- break;
-
- case svc_stufftext:
- s = MSG_ReadString (&net_message);
- Com_DPrintf ("stufftext: %s\n", s);
- Cbuf_AddText (s);
- break;
-
- case svc_serverdata:
- Cbuf_Execute (); // make sure any stuffed commands are done
- CL_ParseServerData ();
- break;
-
- case svc_configstring:
- CL_ParseConfigString ();
- break;
-
- case svc_sound:
- CL_ParseStartSoundPacket();
- break;
-
- case svc_spawnbaseline:
- CL_ParseBaseline ();
- break;
-
- case svc_temp_entity:
- CL_ParseTEnt ();
- break;
-
- case svc_muzzleflash:
- CL_ParseMuzzleFlash ();
- break;
-
- case svc_muzzleflash2:
- CL_ParseMuzzleFlash2 ();
- break;
-
- case svc_download:
- CL_ParseDownload ();
- break;
-
- case svc_frame:
- CL_ParseFrame ();
- break;
-
- case svc_inventory:
- CL_ParseInventory ();
- break;
-
- case svc_layout:
- s = MSG_ReadString (&net_message);
- strncpy (cl.layout, s, sizeof(cl.layout)-1);
- break;
-
- case svc_playerinfo:
- case svc_packetentities:
- case svc_deltapacketentities:
- Com_Error (ERR_DROP, "Out of place frame data");
- break;
- }
- }
-
- CL_AddNetgraph ();
-
- //
- // we don't know if it is ok to save a demo message until
- // after we have parsed the frame
- //
- if (cls.demorecording && !cls.demowaiting)
- CL_WriteDemoMessage ();
-
-}
-
-
--- a/client/cl_pred.c
+++ /dev/null
@@ -1,259 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-
-/*
-===================
-CL_CheckPredictionError
-===================
-*/
-void CL_CheckPredictionError (void)
-{
- int frame;
- int delta[3];
- int i;
- int len;
-
- if (!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
- return;
-
- // calculate the last usercmd_t we sent that the server has processed
- frame = cls.netchan.incoming_acknowledged;
- frame &= (CMD_BACKUP-1);
-
- // compare what the server returned with what we had predicted it to be
- VectorSubtract (cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame], delta);
-
- // save the prediction error for interpolation
- len = abs(delta[0]) + abs(delta[1]) + abs(delta[2]);
- if (len > 640) // 80 world units
- { // a teleport or something
- VectorClear (cl.prediction_error);
- }
- else
- {
- if (cl_showmiss->value && (delta[0] || delta[1] || delta[2]) )
- Com_Printf ("prediction miss on %i: %i\n", cl.frame.serverframe,
- delta[0] + delta[1] + delta[2]);
-
- VectorCopy (cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame]);
-
- // save for error itnerpolation
- for (i=0 ; i<3 ; i++)
- cl.prediction_error[i] = delta[i]*0.125;
- }
-}
-
-
-/*
-====================
-CL_ClipMoveToEntities
-
-====================
-*/
-void CL_ClipMoveToEntities ( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, trace_t *tr )
-{
- int i, x, zd, zu;
- trace_t trace;
- int headnode;
- float *angles;
- entity_state_t *ent;
- int num;
- cmodel_t *cmodel;
- vec3_t bmins, bmaxs;
-
- for (i=0 ; i<cl.frame.num_entities ; i++)
- {
- num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
- ent = &cl_parse_entities[num];
-
- if (!ent->solid)
- continue;
-
- if (ent->number == cl.playernum+1)
- continue;
-
- if (ent->solid == 31)
- { // special value for bmodel
- cmodel = cl.model_clip[ent->modelindex];
- if (!cmodel)
- continue;
- headnode = cmodel->headnode;
- angles = ent->angles;
- }
- else
- { // encoded bbox
- x = 8*(ent->solid & 31);
- zd = 8*((ent->solid>>5) & 31);
- zu = 8*((ent->solid>>10) & 63) - 32;
-
- bmins[0] = bmins[1] = -x;
- bmaxs[0] = bmaxs[1] = x;
- bmins[2] = -zd;
- bmaxs[2] = zu;
-
- headnode = CM_HeadnodeForBox (bmins, bmaxs);
- angles = vec3_origin; // boxes don't rotate
- }
-
- if (tr->allsolid)
- return;
-
- trace = CM_TransformedBoxTrace (start, end,
- mins, maxs, headnode, MASK_PLAYERSOLID,
- ent->origin, angles);
-
- if (trace.allsolid || trace.startsolid ||
- trace.fraction < tr->fraction)
- {
- trace.ent = (edict_t *)ent;
- if (tr->startsolid)
- {
- *tr = trace;
- tr->startsolid = true;
- }
- else
- *tr = trace;
- }
- else if (trace.startsolid)
- tr->startsolid = true;
- }
-}
-
-
-/*
-================
-CL_PMTrace
-================
-*/
-trace_t CL_PMTrace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
-{
- trace_t t;
-
- // check against world
- t = CM_BoxTrace (start, end, mins, maxs, 0, MASK_PLAYERSOLID);
- if (t.fraction < 1.0)
- t.ent = (edict_t *)1;
-
- // check all other solid models
- CL_ClipMoveToEntities (start, mins, maxs, end, &t);
-
- return t;
-}
-
-int CL_PMpointcontents (vec3_t point)
-{
- int i;
- entity_state_t *ent;
- int num;
- cmodel_t *cmodel;
- int contents;
-
- contents = CM_PointContents (point, 0);
-
- for (i=0 ; i<cl.frame.num_entities ; i++)
- {
- num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
- ent = &cl_parse_entities[num];
-
- if (ent->solid != 31) // special value for bmodel
- continue;
-
- cmodel = cl.model_clip[ent->modelindex];
- if (!cmodel)
- continue;
-
- contents |= CM_TransformedPointContents (point, cmodel->headnode, ent->origin, ent->angles);
- }
-
- return contents;
-}
-
-
-/*
-=================
-CL_PredictMovement
-
-Sets cl.predicted_origin and cl.predicted_angles
-=================
-*/
-void CL_PredictMovement (void)
-{
- int ack, current;
- int frame;
- int oldframe;
- usercmd_t *cmd;
- pmove_t pm;
- int i;
- int step;
- int oldz;
-
- if (cls.state != ca_active)
- return;
-
- if (cl_paused->value)
- return;
-
- if (!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
- { // just set angles
- for (i=0 ; i<3 ; i++)
- {
- cl.predicted_angles[i] = cl.viewangles[i] + SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[i]);
- }
- return;
- }
-
- ack = cls.netchan.incoming_acknowledged;
- current = cls.netchan.outgoing_sequence;
-
- // if we are too far out of date, just freeze
- if (current - ack >= CMD_BACKUP)
- {
- if (cl_showmiss->value)
- Com_Printf ("exceeded CMD_BACKUP\n");
- return;
- }
-
- // copy current state to pmove
- memset (&pm, 0, sizeof(pm));
- pm.trace = CL_PMTrace;
- pm.pointcontents = CL_PMpointcontents;
-
- pm_airaccelerate = atof(cl.configstrings[CS_AIRACCEL]);
-
- pm.s = cl.frame.playerstate.pmove;
-
-// SCR_DebugGraph (current - ack - 1, 0);
-
- // run frames
- while (++ack < current)
- {
- frame = ack & (CMD_BACKUP-1);
- cmd = &cl.cmds[frame];
-
- pm.cmd = *cmd;
- Pmove (&pm);
-
- // save for debug checking
- VectorCopy (pm.s.origin, cl.predicted_origins[frame]);
- }
-
- oldframe = (ack-2) & (CMD_BACKUP-1);
- oldz = cl.predicted_origins[oldframe][2];
- step = pm.s.origin[2] - oldz;
- if (step > 63 && step < 160 && (pm.s.pm_flags & PMF_ON_GROUND) )
- {
- cl.predicted_step = step * 0.125;
- cl.predicted_step_time = cls.realtime - cls.frametime * 500;
- }
-
-
- // copy results out for rendering
- cl.predicted_origin[0] = pm.s.origin[0]*0.125;
- cl.predicted_origin[1] = pm.s.origin[1]*0.125;
- cl.predicted_origin[2] = pm.s.origin[2]*0.125;
-
- VectorCopy (pm.viewangles, cl.predicted_angles);
-}
--- a/client/cl_scrn.c
+++ /dev/null
@@ -1,1381 +1,0 @@
-// cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc
-
-/*
-
- full screen console
- put up loading plaque
- blanked background with loading plaque
- blanked background with menu
- cinematics
- full screen image for quit and victory
-
- end of unit intermissions
-
- */
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-float scr_con_current; // aproaches scr_conlines at scr_conspeed
-float scr_conlines; // 0.0 to 1.0 lines of console to display
-
-qboolean scr_initialized; // ready to draw
-
-int scr_draw_loading;
-
-vrect_t scr_vrect; // position of render window on screen
-
-
-cvar_t *scr_viewsize;
-cvar_t *scr_conspeed;
-cvar_t *scr_centertime;
-cvar_t *scr_showturtle;
-cvar_t *scr_showpause;
-cvar_t *scr_printspeed;
-
-cvar_t *scr_netgraph;
-cvar_t *scr_timegraph;
-cvar_t *scr_debuggraph;
-cvar_t *scr_graphheight;
-cvar_t *scr_graphscale;
-cvar_t *scr_graphshift;
-cvar_t *scr_drawall;
-
-typedef struct
-{
- int x1, y1, x2, y2;
-} dirty_t;
-
-dirty_t scr_dirty, scr_old_dirty[2];
-
-char crosshair_pic[MAX_QPATH];
-int crosshair_width, crosshair_height;
-
-void SCR_TimeRefresh_f (void);
-void SCR_Loading_f (void);
-
-
-/*
-===============================================================================
-
-BAR GRAPHS
-
-===============================================================================
-*/
-
-/*
-==============
-CL_AddNetgraph
-
-A new packet was just parsed
-==============
-*/
-void CL_AddNetgraph (void)
-{
- int i;
- int in;
- int ping;
-
- // if using the debuggraph for something else, don't
- // add the net lines
- if (scr_debuggraph->value || scr_timegraph->value)
- return;
-
- for (i=0 ; i<cls.netchan.dropped ; i++)
- SCR_DebugGraph (30, 0x40);
-
- for (i=0 ; i<cl.surpressCount ; i++)
- SCR_DebugGraph (30, 0xdf);
-
- // see what the latency was on this packet
- in = cls.netchan.incoming_acknowledged & (CMD_BACKUP-1);
- ping = cls.realtime - cl.cmd_time[in];
- ping /= 30;
- if (ping > 30)
- ping = 30;
- SCR_DebugGraph (ping, 0xd0);
-}
-
-
-typedef struct
-{
- float value;
- int color;
-} graphsamp_t;
-
-static int current;
-static graphsamp_t values[1024];
-
-/*
-==============
-SCR_DebugGraph
-==============
-*/
-void SCR_DebugGraph (float value, int color)
-{
- values[current&1023].value = value;
- values[current&1023].color = color;
- current++;
-}
-
-/*
-==============
-SCR_DrawDebugGraph
-==============
-*/
-void SCR_DrawDebugGraph (void)
-{
- int a, x, y, w, i, h;
- float v;
- int color;
-
- //
- // draw the graph
- //
- w = scr_vrect.width;
-
- x = scr_vrect.x;
- y = scr_vrect.y+scr_vrect.height;
- re.DrawFill (x, y-scr_graphheight->value,
- w, scr_graphheight->value, 8);
-
- for (a=0 ; a<w ; a++)
- {
- i = (current-1-a+1024) & 1023;
- v = values[i].value;
- color = values[i].color;
- v = v*scr_graphscale->value + scr_graphshift->value;
-
- if (v < 0)
- v += scr_graphheight->value * (1+(int)(-v/scr_graphheight->value));
- h = (int)v % (int)scr_graphheight->value;
- re.DrawFill (x+w-1-a, y - h, 1, h, color);
- }
-}
-
-/*
-===============================================================================
-
-CENTER PRINTING
-
-===============================================================================
-*/
-
-char scr_centerstring[1024];
-float scr_centertime_start; // for slow victory printing
-float scr_centertime_off;
-int scr_center_lines;
-int scr_erase_center;
-
-/*
-==============
-SCR_CenterPrint
-
-Called for important messages that should stay in the center of the screen
-for a few moments
-==============
-*/
-void SCR_CenterPrint (char *str)
-{
- char *s;
- char line[64];
- int i, j, l;
-
- strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
- scr_centertime_off = scr_centertime->value;
- scr_centertime_start = cl.time;
-
- // count the number of lines for centering
- scr_center_lines = 1;
- s = str;
- while (*s)
- {
- if (*s == '\n')
- scr_center_lines++;
- s++;
- }
-
- // echo it to the console
- Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
-
- s = str;
- do
- {
- // scan the width of the line
- for (l=0 ; l<40 ; l++)
- if (s[l] == '\n' || !s[l])
- break;
- for (i=0 ; i<(40-l)/2 ; i++)
- line[i] = ' ';
-
- for (j=0 ; j<l ; j++)
- {
- line[i++] = s[j];
- }
-
- line[i] = '\n';
- line[i+1] = 0;
-
- Com_Printf ("%s", line);
-
- while (*s && *s != '\n')
- s++;
-
- if (!*s)
- break;
- s++; // skip the \n
- } while (1);
- Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
- Con_ClearNotify ();
-}
-
-
-void SCR_DrawCenterString (void)
-{
- char *start;
- int l;
- int j;
- int x, y;
- int remaining;
-
-// the finale prints the characters one at a time
- remaining = 9999;
-
- scr_erase_center = 0;
- start = scr_centerstring;
-
- if (scr_center_lines <= 4)
- y = vid.height*0.35;
- else
- y = 48;
-
- do
- {
- // scan the width of the line
- for (l=0 ; l<40 ; l++)
- if (start[l] == '\n' || !start[l])
- break;
- x = (vid.width - l*8)/2;
- SCR_AddDirtyPoint (x, y);
- for (j=0 ; j<l ; j++, x+=8)
- {
- re.DrawChar (x, y, start[j]);
- if (!remaining--)
- return;
- }
- SCR_AddDirtyPoint (x, y+8);
-
- y += 8;
-
- while (*start && *start != '\n')
- start++;
-
- if (!*start)
- break;
- start++; // skip the \n
- } while (1);
-}
-
-void SCR_CheckDrawCenterString (void)
-{
- scr_centertime_off -= cls.frametime;
-
- if (scr_centertime_off <= 0)
- return;
-
- SCR_DrawCenterString ();
-}
-
-//=============================================================================
-
-/*
-=================
-SCR_CalcVrect
-
-Sets scr_vrect, the coordinates of the rendered window
-=================
-*/
-static void SCR_CalcVrect (void)
-{
- int size;
-
- // bound viewsize
- if (scr_viewsize->value < 40)
- Cvar_Set ("viewsize","40");
- if (scr_viewsize->value > 100)
- Cvar_Set ("viewsize","100");
-
- size = scr_viewsize->value;
-
- scr_vrect.width = vid.width*size/100;
- scr_vrect.width &= ~7;
-
- scr_vrect.height = vid.height*size/100;
- scr_vrect.height &= ~1;
-
- scr_vrect.x = (vid.width - scr_vrect.width)/2;
- scr_vrect.y = (vid.height - scr_vrect.height)/2;
-}
-
-
-/*
-=================
-SCR_SizeUp_f
-
-Keybinding command
-=================
-*/
-void SCR_SizeUp_f (void)
-{
- Cvar_SetValue ("viewsize",scr_viewsize->value+10);
-}
-
-
-/*
-=================
-SCR_SizeDown_f
-
-Keybinding command
-=================
-*/
-void SCR_SizeDown_f (void)
-{
- Cvar_SetValue ("viewsize",scr_viewsize->value-10);
-}
-
-/*
-=================
-SCR_Sky_f
-
-Set a specific sky and rotation speed
-=================
-*/
-void SCR_Sky_f (void)
-{
- float rotate;
- vec3_t axis;
-
- if (Cmd_Argc() < 2)
- {
- Com_Printf ("Usage: sky <basename> <rotate> <axis x y z>\n");
- return;
- }
- if (Cmd_Argc() > 2)
- rotate = atof(Cmd_Argv(2));
- else
- rotate = 0;
- if (Cmd_Argc() == 6)
- {
- axis[0] = atof(Cmd_Argv(3));
- axis[1] = atof(Cmd_Argv(4));
- axis[2] = atof(Cmd_Argv(5));
- }
- else
- {
- axis[0] = 0;
- axis[1] = 0;
- axis[2] = 1;
- }
-
- re.SetSky (Cmd_Argv(1), rotate, axis);
-}
-
-//============================================================================
-
-/*
-==================
-SCR_Init
-==================
-*/
-void SCR_Init (void)
-{
- scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE);
- scr_conspeed = Cvar_Get ("scr_conspeed", "3", 0);
- scr_showturtle = Cvar_Get ("scr_showturtle", "0", 0);
- scr_showpause = Cvar_Get ("scr_showpause", "1", 0);
- scr_centertime = Cvar_Get ("scr_centertime", "2.5", 0);
- scr_printspeed = Cvar_Get ("scr_printspeed", "8", 0);
- scr_netgraph = Cvar_Get ("netgraph", "0", 0);
- scr_timegraph = Cvar_Get ("timegraph", "0", 0);
- scr_debuggraph = Cvar_Get ("debuggraph", "0", 0);
- scr_graphheight = Cvar_Get ("graphheight", "32", 0);
- scr_graphscale = Cvar_Get ("graphscale", "1", 0);
- scr_graphshift = Cvar_Get ("graphshift", "0", 0);
- scr_drawall = Cvar_Get ("scr_drawall", "0", 0);
-
-//
-// register our commands
-//
- Cmd_AddCommand ("timerefresh",SCR_TimeRefresh_f);
- Cmd_AddCommand ("loading",SCR_Loading_f);
- Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
- Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
- Cmd_AddCommand ("sky",SCR_Sky_f);
-
- scr_initialized = true;
-}
-
-
-/*
-==============
-SCR_DrawNet
-==============
-*/
-void SCR_DrawNet (void)
-{
- if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged
- < CMD_BACKUP-1)
- return;
-
- re.DrawPic (scr_vrect.x+64, scr_vrect.y, "net");
-}
-
-/*
-==============
-SCR_DrawPause
-==============
-*/
-void SCR_DrawPause (void)
-{
- int w, h;
-
- if (!scr_showpause->value) // turn off for screenshots
- return;
-
- if (!cl_paused->value)
- return;
-
- re.DrawGetPicSize (&w, &h, "pause");
- re.DrawPic ((vid.width-w)/2, vid.height/2 + 8, "pause");
-}
-
-/*
-==============
-SCR_DrawLoading
-==============
-*/
-void SCR_DrawLoading (void)
-{
- int w, h;
-
- if (!scr_draw_loading)
- return;
-
- scr_draw_loading = false;
- re.DrawGetPicSize (&w, &h, "loading");
- re.DrawPic ((vid.width-w)/2, (vid.height-h)/2, "loading");
-}
-
-//=============================================================================
-
-/*
-==================
-SCR_RunConsole
-
-Scroll it up or down
-==================
-*/
-void SCR_RunConsole (void)
-{
-// decide on the height of the console
- if (cls.key_dest == key_console)
- scr_conlines = 0.5; // half screen
- else
- scr_conlines = 0; // none visible
-
- if (scr_conlines < scr_con_current)
- {
- scr_con_current -= scr_conspeed->value*cls.frametime;
- if (scr_conlines > scr_con_current)
- scr_con_current = scr_conlines;
-
- }
- else if (scr_conlines > scr_con_current)
- {
- scr_con_current += scr_conspeed->value*cls.frametime;
- if (scr_conlines < scr_con_current)
- scr_con_current = scr_conlines;
- }
-
-}
-
-/*
-==================
-SCR_DrawConsole
-==================
-*/
-void SCR_DrawConsole (void)
-{
- Con_CheckResize ();
-
- if (cls.state == ca_disconnected || cls.state == ca_connecting)
- { // forced full screen console
- Con_DrawConsole (1.0);
- return;
- }
-
- if (cls.state != ca_active || !cl.refresh_prepped)
- { // connected, but can't render
- Con_DrawConsole (0.5);
- re.DrawFill (0, vid.height/2, vid.width, vid.height/2, 0);
- return;
- }
-
- if (scr_con_current)
- {
- Con_DrawConsole (scr_con_current);
- }
- else
- {
- if (cls.key_dest == key_game || cls.key_dest == key_message)
- Con_DrawNotify (); // only draw notify in game
- }
-}
-
-//=============================================================================
-
-/*
-================
-SCR_BeginLoadingPlaque
-================
-*/
-void SCR_BeginLoadingPlaque (void)
-{
- S_StopAllSounds ();
- cl.sound_prepped = false; // don't play ambients
- CDAudio_Stop ();
- if (cls.disable_screen)
- return;
- if (developer->value)
- return;
- if (cls.state == ca_disconnected)
- return; // if at console, don't bring up the plaque
- if (cls.key_dest == key_console)
- return;
- if (cl.cinematictime > 0)
- scr_draw_loading = 2; // clear to balack first
- else
- scr_draw_loading = 1;
- SCR_UpdateScreen ();
- cls.disable_screen = Sys_Milliseconds ();
- cls.disable_servercount = cl.servercount;
-}
-
-/*
-================
-SCR_EndLoadingPlaque
-================
-*/
-void SCR_EndLoadingPlaque (void)
-{
- cls.disable_screen = 0;
- Con_ClearNotify ();
-}
-
-/*
-================
-SCR_Loading_f
-================
-*/
-void SCR_Loading_f (void)
-{
- SCR_BeginLoadingPlaque ();
-}
-
-/*
-================
-SCR_TimeRefresh_f
-================
-*/
-int entitycmpfnc( const entity_t *a, const entity_t *b )
-{
- /*
- ** all other models are sorted by model then skin
- */
- if ( a->model == b->model )
- {
- return (uintptr)a->skin - (uintptr)b->skin;
- }
- else
- {
- return (uintptr)a->model - (uintptr)b->model;
- }
-}
-
-void SCR_TimeRefresh_f (void)
-{
- int i;
- int start, stop;
- float time;
-
- if ( cls.state != ca_active )
- return;
-
- start = Sys_Milliseconds ();
-
- if (Cmd_Argc() == 2)
- { // run without page flipping
- re.BeginFrame( 0 );
- for (i=0 ; i<128 ; i++)
- {
- cl.refdef.viewangles[1] = i/128.0*360.0;
- re.RenderFrame (&cl.refdef);
- }
- re.EndFrame();
- }
- else
- {
- for (i=0 ; i<128 ; i++)
- {
- cl.refdef.viewangles[1] = i/128.0*360.0;
-
- re.BeginFrame( 0 );
- re.RenderFrame (&cl.refdef);
- re.EndFrame();
- }
- }
-
- stop = Sys_Milliseconds ();
- time = (stop-start)/1000.0;
- Com_Printf ("%f seconds (%f fps)\n", time, 128/time);
-}
-
-/*
-=================
-SCR_AddDirtyPoint
-=================
-*/
-void SCR_AddDirtyPoint (int x, int y)
-{
- if (x < scr_dirty.x1)
- scr_dirty.x1 = x;
- if (x > scr_dirty.x2)
- scr_dirty.x2 = x;
- if (y < scr_dirty.y1)
- scr_dirty.y1 = y;
- if (y > scr_dirty.y2)
- scr_dirty.y2 = y;
-}
-
-void SCR_DirtyScreen (void)
-{
- SCR_AddDirtyPoint (0, 0);
- SCR_AddDirtyPoint (vid.width-1, vid.height-1);
-}
-
-/*
-==============
-SCR_TileClear
-
-Clear any parts of the tiled background that were drawn on last frame
-==============
-*/
-void SCR_TileClear (void)
-{
- int i;
- int top, bottom, left, right;
- dirty_t clear;
-
- if (scr_drawall->value)
- SCR_DirtyScreen (); // for power vr or broken page flippers...
-
- if (scr_con_current == 1.0)
- return; // full screen console
- if (scr_viewsize->value == 100)
- return; // full screen rendering
- if (cl.cinematictime > 0)
- return; // full screen cinematic
-
- // erase rect will be the union of the past three frames
- // so tripple buffering works properly
- clear = scr_dirty;
- for (i=0 ; i<2 ; i++)
- {
- if (scr_old_dirty[i].x1 < clear.x1)
- clear.x1 = scr_old_dirty[i].x1;
- if (scr_old_dirty[i].x2 > clear.x2)
- clear.x2 = scr_old_dirty[i].x2;
- if (scr_old_dirty[i].y1 < clear.y1)
- clear.y1 = scr_old_dirty[i].y1;
- if (scr_old_dirty[i].y2 > clear.y2)
- clear.y2 = scr_old_dirty[i].y2;
- }
-
- scr_old_dirty[1] = scr_old_dirty[0];
- scr_old_dirty[0] = scr_dirty;
-
- scr_dirty.x1 = 9999;
- scr_dirty.x2 = -9999;
- scr_dirty.y1 = 9999;
- scr_dirty.y2 = -9999;
-
- // don't bother with anything convered by the console)
- top = scr_con_current*vid.height;
- if (top >= clear.y1)
- clear.y1 = top;
-
- if (clear.y2 <= clear.y1)
- return; // nothing disturbed
-
- top = scr_vrect.y;
- bottom = top + scr_vrect.height-1;
- left = scr_vrect.x;
- right = left + scr_vrect.width-1;
-
- if (clear.y1 < top)
- { // clear above view screen
- i = clear.y2 < top-1 ? clear.y2 : top-1;
- re.DrawTileClear (clear.x1 , clear.y1,
- clear.x2 - clear.x1 + 1, i - clear.y1+1, "backtile");
- clear.y1 = top;
- }
- if (clear.y2 > bottom)
- { // clear below view screen
- i = clear.y1 > bottom+1 ? clear.y1 : bottom+1;
- re.DrawTileClear (clear.x1, i,
- clear.x2-clear.x1+1, clear.y2-i+1, "backtile");
- clear.y2 = bottom;
- }
- if (clear.x1 < left)
- { // clear left of view screen
- i = clear.x2 < left-1 ? clear.x2 : left-1;
- re.DrawTileClear (clear.x1, clear.y1,
- i-clear.x1+1, clear.y2 - clear.y1 + 1, "backtile");
- clear.x1 = left;
- }
- if (clear.x2 > right)
- { // clear left of view screen
- i = clear.x1 > right+1 ? clear.x1 : right+1;
- re.DrawTileClear (i, clear.y1,
- clear.x2-i+1, clear.y2 - clear.y1 + 1, "backtile");
- clear.x2 = right;
- }
-
-}
-
-
-//===============================================================
-
-
-#define STAT_MINUS 10 // num frame for '-' stats digit
-char *sb_nums[2][11] =
-{
- {"num_0", "num_1", "num_2", "num_3", "num_4", "num_5",
- "num_6", "num_7", "num_8", "num_9", "num_minus"},
- {"anum_0", "anum_1", "anum_2", "anum_3", "anum_4", "anum_5",
- "anum_6", "anum_7", "anum_8", "anum_9", "anum_minus"}
-};
-
-#define ICON_WIDTH 24
-#define ICON_HEIGHT 24
-#define CHAR_WIDTH 16
-#define ICON_SPACE 8
-
-
-
-/*
-================
-SizeHUDString
-
-Allow embedded \n in the string
-================
-*/
-void SizeHUDString (char *string, int *w, int *h)
-{
- int lines, width, current;
-
- lines = 1;
- width = 0;
-
- current = 0;
- while (*string)
- {
- if (*string == '\n')
- {
- lines++;
- current = 0;
- }
- else
- {
- current++;
- if (current > width)
- width = current;
- }
- string++;
- }
-
- *w = width * 8;
- *h = lines * 8;
-}
-
-void DrawHUDString (char *string, int x, int y, int centerwidth, int xor)
-{
- int margin;
- char line[1024];
- int width;
- int i;
-
- margin = x;
-
- while (*string)
- {
- // scan out one line of text from the string
- width = 0;
- while (*string && *string != '\n')
- line[width++] = *string++;
- line[width] = 0;
-
- if (centerwidth)
- x = margin + (centerwidth - width*8)/2;
- else
- x = margin;
- for (i=0 ; i<width ; i++)
- {
- re.DrawChar (x, y, line[i]^xor);
- x += 8;
- }
- if (*string)
- {
- string++; // skip the \n
- y += 8;
- }
- }
-}
-
-
-/*
-==============
-SCR_DrawField
-==============
-*/
-void SCR_DrawField (int x, int y, int color, int width, int value)
-{
- char num[16], *ptr;
- int l;
- int frame;
-
- if (width < 1)
- return;
-
- // draw number string
- if (width > 5)
- width = 5;
-
- SCR_AddDirtyPoint (x, y);
- SCR_AddDirtyPoint (x+width*CHAR_WIDTH+2, y+23);
-
- Com_sprintf (num, sizeof(num), "%i", value);
- l = strlen(num);
- if (l > width)
- l = width;
- x += 2 + CHAR_WIDTH*(width - l);
-
- ptr = num;
- while (*ptr && l)
- {
- if (*ptr == '-')
- frame = STAT_MINUS;
- else
- frame = *ptr -'0';
-
- re.DrawPic (x,y,sb_nums[color][frame]);
- x += CHAR_WIDTH;
- ptr++;
- l--;
- }
-}
-
-
-/*
-===============
-SCR_TouchPics
-
-Allows rendering code to cache all needed sbar graphics
-===============
-*/
-void SCR_TouchPics (void)
-{
- int i, j;
-
- for (i=0 ; i<2 ; i++)
- for (j=0 ; j<11 ; j++)
- re.RegisterPic (sb_nums[i][j]);
-
- if (crosshair->value)
- {
- if (crosshair->value > 3 || crosshair->value < 0)
- crosshair->value = 3;
-
- Com_sprintf (crosshair_pic, sizeof(crosshair_pic), "ch%i", (int)(crosshair->value));
- re.DrawGetPicSize (&crosshair_width, &crosshair_height, crosshair_pic);
- if (!crosshair_width)
- crosshair_pic[0] = 0;
- }
-}
-
-/*
-================
-SCR_ExecuteLayoutString
-
-================
-*/
-void SCR_ExecuteLayoutString (char *s)
-{
- int x, y;
- int value;
- char *token;
- int width;
- int index;
- clientinfo_t *ci;
-
- if (cls.state != ca_active || !cl.refresh_prepped)
- return;
-
- if (!s[0])
- return;
-
- x = 0;
- y = 0;
-
- while (s)
- {
- token = COM_Parse (&s);
- if (!strcmp(token, "xl"))
- {
- token = COM_Parse (&s);
- x = atoi(token);
- continue;
- }
- if (!strcmp(token, "xr"))
- {
- token = COM_Parse (&s);
- x = vid.width + atoi(token);
- continue;
- }
- if (!strcmp(token, "xv"))
- {
- token = COM_Parse (&s);
- x = vid.width/2 - 160 + atoi(token);
- continue;
- }
-
- if (!strcmp(token, "yt"))
- {
- token = COM_Parse (&s);
- y = atoi(token);
- continue;
- }
- if (!strcmp(token, "yb"))
- {
- token = COM_Parse (&s);
- y = vid.height + atoi(token);
- continue;
- }
- if (!strcmp(token, "yv"))
- {
- token = COM_Parse (&s);
- y = vid.height/2 - 120 + atoi(token);
- continue;
- }
-
- if (!strcmp(token, "pic"))
- { // draw a pic from a stat number
- token = COM_Parse (&s);
- value = cl.frame.playerstate.stats[atoi(token)];
- if (value >= MAX_IMAGES)
- Com_Error (ERR_DROP, "Pic >= MAX_IMAGES");
- if (cl.configstrings[CS_IMAGES+value])
- {
- SCR_AddDirtyPoint (x, y);
- SCR_AddDirtyPoint (x+23, y+23);
- re.DrawPic (x, y, cl.configstrings[CS_IMAGES+value]);
- }
- continue;
- }
-
- if (!strcmp(token, "client"))
- { // draw a deathmatch client block
- int score, ping, time;
-
- token = COM_Parse (&s);
- x = vid.width/2 - 160 + atoi(token);
- token = COM_Parse (&s);
- y = vid.height/2 - 120 + atoi(token);
- SCR_AddDirtyPoint (x, y);
- SCR_AddDirtyPoint (x+159, y+31);
-
- token = COM_Parse (&s);
- value = atoi(token);
- if (value >= MAX_CLIENTS || value < 0)
- Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
- ci = &cl.clientinfo[value];
-
- token = COM_Parse (&s);
- score = atoi(token);
-
- token = COM_Parse (&s);
- ping = atoi(token);
-
- token = COM_Parse (&s);
- time = atoi(token);
-
- DrawAltString (x+32, y, ci->name);
- DrawString (x+32, y+8, "Score: ");
- DrawAltString (x+32+7*8, y+8, va("%i", score));
- DrawString (x+32, y+16, va("Ping: %i", ping));
- DrawString (x+32, y+24, va("Time: %i", time));
-
- if (!ci->icon)
- ci = &cl.baseclientinfo;
- re.DrawPic (x, y, ci->iconname);
- continue;
- }
-
- if (!strcmp(token, "ctf"))
- { // draw a ctf client block
- int score, ping;
- char block[80];
-
- token = COM_Parse (&s);
- x = vid.width/2 - 160 + atoi(token);
- token = COM_Parse (&s);
- y = vid.height/2 - 120 + atoi(token);
- SCR_AddDirtyPoint (x, y);
- SCR_AddDirtyPoint (x+159, y+31);
-
- token = COM_Parse (&s);
- value = atoi(token);
- if (value >= MAX_CLIENTS || value < 0)
- Com_Error (ERR_DROP, "client >= MAX_CLIENTS");
- ci = &cl.clientinfo[value];
-
- token = COM_Parse (&s);
- score = atoi(token);
-
- token = COM_Parse (&s);
- ping = atoi(token);
- if (ping > 999)
- ping = 999;
-
- sprintf(block, "%3d %3d %-12.12s", score, ping, ci->name);
-
- if (value == cl.playernum)
- DrawAltString (x, y, block);
- else
- DrawString (x, y, block);
- continue;
- }
-
- if (!strcmp(token, "picn"))
- { // draw a pic from a name
- token = COM_Parse (&s);
- SCR_AddDirtyPoint (x, y);
- SCR_AddDirtyPoint (x+23, y+23);
- re.DrawPic (x, y, token);
- continue;
- }
-
- if (!strcmp(token, "num"))
- { // draw a number
- token = COM_Parse (&s);
- width = atoi(token);
- token = COM_Parse (&s);
- value = cl.frame.playerstate.stats[atoi(token)];
- SCR_DrawField (x, y, 0, width, value);
- continue;
- }
-
- if (!strcmp(token, "hnum"))
- { // health number
- int color;
-
- width = 3;
- value = cl.frame.playerstate.stats[STAT_HEALTH];
- if (value > 25)
- color = 0; // green
- else if (value > 0)
- color = (cl.frame.serverframe>>2) & 1; // flash
- else
- color = 1;
-
- if (cl.frame.playerstate.stats[STAT_FLASHES] & 1)
- re.DrawPic (x, y, "field_3");
-
- SCR_DrawField (x, y, color, width, value);
- continue;
- }
-
- if (!strcmp(token, "anum"))
- { // ammo number
- int color;
-
- width = 3;
- value = cl.frame.playerstate.stats[STAT_AMMO];
- if (value > 5)
- color = 0; // green
- else if (value >= 0)
- color = (cl.frame.serverframe>>2) & 1; // flash
- else
- continue; // negative number = don't show
-
- if (cl.frame.playerstate.stats[STAT_FLASHES] & 4)
- re.DrawPic (x, y, "field_3");
-
- SCR_DrawField (x, y, color, width, value);
- continue;
- }
-
- if (!strcmp(token, "rnum"))
- { // armor number
- int color;
-
- width = 3;
- value = cl.frame.playerstate.stats[STAT_ARMOR];
- if (value < 1)
- continue;
-
- color = 0; // green
-
- if (cl.frame.playerstate.stats[STAT_FLASHES] & 2)
- re.DrawPic (x, y, "field_3");
-
- SCR_DrawField (x, y, color, width, value);
- continue;
- }
-
-
- if (!strcmp(token, "stat_string"))
- {
- token = COM_Parse (&s);
- index = atoi(token);
- if (index < 0 || index >= MAX_CONFIGSTRINGS)
- Com_Error (ERR_DROP, "Bad stat_string index");
- index = cl.frame.playerstate.stats[index];
- if (index < 0 || index >= MAX_CONFIGSTRINGS)
- Com_Error (ERR_DROP, "Bad stat_string index");
- DrawString (x, y, cl.configstrings[index]);
- continue;
- }
-
- if (!strcmp(token, "cstring"))
- {
- token = COM_Parse (&s);
- DrawHUDString (token, x, y, 320, 0);
- continue;
- }
-
- if (!strcmp(token, "string"))
- {
- token = COM_Parse (&s);
- DrawString (x, y, token);
- continue;
- }
-
- if (!strcmp(token, "cstring2"))
- {
- token = COM_Parse (&s);
- DrawHUDString (token, x, y, 320,0x80);
- continue;
- }
-
- if (!strcmp(token, "string2"))
- {
- token = COM_Parse (&s);
- DrawAltString (x, y, token);
- continue;
- }
-
- if (!strcmp(token, "if"))
- { // draw a number
- token = COM_Parse (&s);
- value = cl.frame.playerstate.stats[atoi(token)];
- if (!value)
- { // skip to endif
- while (s && strcmp(token, "endif") )
- {
- token = COM_Parse (&s);
- }
- }
-
- continue;
- }
-
-
- }
-}
-
-
-/*
-================
-SCR_DrawStats
-
-The status bar is a small layout program that
-is based on the stats array
-================
-*/
-void SCR_DrawStats (void)
-{
- SCR_ExecuteLayoutString (cl.configstrings[CS_STATUSBAR]);
-}
-
-
-/*
-================
-SCR_DrawLayout
-
-================
-*/
-void SCR_DrawLayout (void)
-{
- if (!cl.frame.playerstate.stats[STAT_LAYOUTS])
- return;
- SCR_ExecuteLayoutString (cl.layout);
-}
-
-//=======================================================
-
-/*
-==================
-SCR_UpdateScreen
-
-This is called every frame, and can also be called explicitly to flush
-text to the screen.
-==================
-*/
-void SCR_UpdateScreen (void)
-{
- int numframes;
- int i;
- float separation[2] = { 0, 0 };
-
- // if the screen is disabled (loading plaque is up, or vid mode changing)
- // do nothing at all
- if (cls.disable_screen)
- {
- if (Sys_Milliseconds() - cls.disable_screen > 120000)
- {
- cls.disable_screen = 0;
- Com_Printf ("Loading plaque timed out.\n");
- }
- return;
- }
-
- if (!scr_initialized || !con.initialized)
- return; // not initialized yet
-
- /*
- ** range check cl_camera_separation so we don't inadvertently fry someone's
- ** brain
- */
- if ( cl_stereo_separation->value > 1.0 )
- Cvar_SetValue( "cl_stereo_separation", 1.0 );
- else if ( cl_stereo_separation->value < 0 )
- Cvar_SetValue( "cl_stereo_separation", 0.0 );
-
- if ( cl_stereo->value )
- {
- numframes = 2;
- separation[0] = -cl_stereo_separation->value / 2;
- separation[1] = cl_stereo_separation->value / 2;
- }
- else
- {
- separation[0] = 0;
- separation[1] = 0;
- numframes = 1;
- }
-
- for ( i = 0; i < numframes; i++ )
- {
- re.BeginFrame( separation[i] );
-
- if (scr_draw_loading == 2)
- { // loading plaque over black screen
- int w, h;
-
- re.CinematicSetPalette(NULL);
- scr_draw_loading = false;
- re.DrawGetPicSize (&w, &h, "loading");
- re.DrawPic ((vid.width-w)/2, (vid.height-h)/2, "loading");
-// re.EndFrame();
-// return;
- }
- // if a cinematic is supposed to be running, handle menus
- // and console specially
- else if (cl.cinematictime > 0)
- {
- if (cls.key_dest == key_menu)
- {
- if (cl.cinematicpalette_active)
- {
- re.CinematicSetPalette(NULL);
- cl.cinematicpalette_active = false;
- }
- M_Draw ();
-// re.EndFrame();
-// return;
- }
- else if (cls.key_dest == key_console)
- {
- if (cl.cinematicpalette_active)
- {
- re.CinematicSetPalette(NULL);
- cl.cinematicpalette_active = false;
- }
- SCR_DrawConsole ();
-// re.EndFrame();
-// return;
- }
- else
- {
- SCR_DrawCinematic();
-// re.EndFrame();
-// return;
- }
- }
- else
- {
-
- // make sure the game palette is active
- if (cl.cinematicpalette_active)
- {
- re.CinematicSetPalette(NULL);
- cl.cinematicpalette_active = false;
- }
-
- // do 3D refresh drawing, and then update the screen
- SCR_CalcVrect ();
-
- // clear any dirty part of the background
- SCR_TileClear ();
-
- V_RenderView ( separation[i] );
-
- SCR_DrawStats ();
- if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 1)
- SCR_DrawLayout ();
- if (cl.frame.playerstate.stats[STAT_LAYOUTS] & 2)
- CL_DrawInventory ();
-
- SCR_DrawNet ();
- SCR_CheckDrawCenterString ();
-
- if (scr_timegraph->value)
- SCR_DebugGraph (cls.frametime*300, 0);
-
- if (scr_debuggraph->value || scr_timegraph->value || scr_netgraph->value)
- SCR_DrawDebugGraph ();
-
- SCR_DrawPause ();
-
- SCR_DrawConsole ();
-
- M_Draw ();
-
- SCR_DrawLoading ();
- }
- }
- re.EndFrame();
-}
--- a/client/cl_tent.c
+++ /dev/null
@@ -1,1729 +1,0 @@
-// cl_tent.c -- client side temporary entities
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-typedef enum
-{
- ex_free, ex_explosion, ex_misc, ex_flash, ex_mflash, ex_poly, ex_poly2
-} exptype_t;
-
-typedef struct
-{
- exptype_t type;
- entity_t ent;
-
- int frames;
- float light;
- vec3_t lightcolor;
- float start;
- int baseframe;
-} explosion_t;
-
-
-
-#define MAX_EXPLOSIONS 32
-explosion_t cl_explosions[MAX_EXPLOSIONS];
-
-
-#define MAX_BEAMS 32
-typedef struct
-{
- int entity;
- int dest_entity;
- struct model_s *model;
- int endtime;
- vec3_t offset;
- vec3_t start, end;
-} beam_t;
-beam_t cl_beams[MAX_BEAMS];
-//PMM - added this for player-linked beams. Currently only used by the plasma beam
-beam_t cl_playerbeams[MAX_BEAMS];
-
-
-#define MAX_LASERS 32
-typedef struct
-{
- entity_t ent;
- int endtime;
-} laser_t;
-laser_t cl_lasers[MAX_LASERS];
-
-//ROGUE
-cl_sustain_t cl_sustains[MAX_SUSTAINS];
-//ROGUE
-
-//PGM
-extern void CL_TeleportParticles (vec3_t org);
-//PGM
-
-void CL_BlasterParticles (vec3_t org, vec3_t dir);
-void CL_ExplosionParticles (vec3_t org);
-void CL_BFGExplosionParticles (vec3_t org);
-// RAFAEL
-void CL_BlueBlasterParticles (vec3_t org, vec3_t dir);
-
-struct sfx_s *cl_sfx_ric1;
-struct sfx_s *cl_sfx_ric2;
-struct sfx_s *cl_sfx_ric3;
-struct sfx_s *cl_sfx_lashit;
-struct sfx_s *cl_sfx_spark5;
-struct sfx_s *cl_sfx_spark6;
-struct sfx_s *cl_sfx_spark7;
-struct sfx_s *cl_sfx_railg;
-struct sfx_s *cl_sfx_rockexp;
-struct sfx_s *cl_sfx_grenexp;
-struct sfx_s *cl_sfx_watrexp;
-// RAFAEL
-struct sfx_s *cl_sfx_plasexp;
-struct sfx_s *cl_sfx_footsteps[4];
-
-struct model_s *cl_mod_explode;
-struct model_s *cl_mod_smoke;
-struct model_s *cl_mod_flash;
-struct model_s *cl_mod_parasite_segment;
-struct model_s *cl_mod_grapple_cable;
-struct model_s *cl_mod_parasite_tip;
-struct model_s *cl_mod_explo4;
-struct model_s *cl_mod_bfg_explo;
-struct model_s *cl_mod_powerscreen;
-// RAFAEL
-struct model_s *cl_mod_plasmaexplo;
-
-//ROGUE
-struct sfx_s *cl_sfx_lightning;
-struct sfx_s *cl_sfx_disrexp;
-struct model_s *cl_mod_lightning;
-struct model_s *cl_mod_heatbeam;
-struct model_s *cl_mod_monster_heatbeam;
-struct model_s *cl_mod_explo4_big;
-
-//ROGUE
-/*
-=================
-CL_RegisterTEntSounds
-=================
-*/
-void CL_RegisterTEntSounds (void)
-{
- int i;
- char name[MAX_QPATH];
-
- // PMM - version stuff
-// Com_Printf ("%s\n", ROGUE_VERSION_STRING);
- // PMM
- cl_sfx_ric1 = S_RegisterSound ("world/ric1.wav");
- cl_sfx_ric2 = S_RegisterSound ("world/ric2.wav");
- cl_sfx_ric3 = S_RegisterSound ("world/ric3.wav");
- cl_sfx_lashit = S_RegisterSound("weapons/lashit.wav");
- cl_sfx_spark5 = S_RegisterSound ("world/spark5.wav");
- cl_sfx_spark6 = S_RegisterSound ("world/spark6.wav");
- cl_sfx_spark7 = S_RegisterSound ("world/spark7.wav");
- cl_sfx_railg = S_RegisterSound ("weapons/railgf1a.wav");
- cl_sfx_rockexp = S_RegisterSound ("weapons/rocklx1a.wav");
- cl_sfx_grenexp = S_RegisterSound ("weapons/grenlx1a.wav");
- cl_sfx_watrexp = S_RegisterSound ("weapons/xpld_wat.wav");
- // RAFAEL
- // cl_sfx_plasexp = S_RegisterSound ("weapons/plasexpl.wav");
- S_RegisterSound ("player/land1.wav");
-
- S_RegisterSound ("player/fall2.wav");
- S_RegisterSound ("player/fall1.wav");
-
- for (i=0 ; i<4 ; i++)
- {
- Com_sprintf (name, sizeof(name), "player/step%i.wav", i+1);
- cl_sfx_footsteps[i] = S_RegisterSound (name);
- }
-
-//PGM
- cl_sfx_lightning = S_RegisterSound ("weapons/tesla.wav");
- cl_sfx_disrexp = S_RegisterSound ("weapons/disrupthit.wav");
- // version stuff
- sprintf (name, "weapons/sound%d.wav", ROGUE_VERSION_ID);
- if (name[0] == 'w')
- name[0] = 'W';
-//PGM
-}
-
-/*
-=================
-CL_RegisterTEntModels
-=================
-*/
-void CL_RegisterTEntModels (void)
-{
- cl_mod_explode = re.RegisterModel ("models/objects/explode/tris.md2");
- cl_mod_smoke = re.RegisterModel ("models/objects/smoke/tris.md2");
- cl_mod_flash = re.RegisterModel ("models/objects/flash/tris.md2");
- cl_mod_parasite_segment = re.RegisterModel ("models/monsters/parasite/segment/tris.md2");
- cl_mod_grapple_cable = re.RegisterModel ("models/ctf/segment/tris.md2");
- cl_mod_parasite_tip = re.RegisterModel ("models/monsters/parasite/tip/tris.md2");
- cl_mod_explo4 = re.RegisterModel ("models/objects/r_explode/tris.md2");
- cl_mod_bfg_explo = re.RegisterModel ("sprites/s_bfg2.sp2");
- cl_mod_powerscreen = re.RegisterModel ("models/items/armor/effect/tris.md2");
-
-re.RegisterModel ("models/objects/laser/tris.md2");
-re.RegisterModel ("models/objects/grenade2/tris.md2");
-re.RegisterModel ("models/weapons/v_machn/tris.md2");
-re.RegisterModel ("models/weapons/v_handgr/tris.md2");
-re.RegisterModel ("models/weapons/v_shotg2/tris.md2");
-re.RegisterModel ("models/objects/gibs/bone/tris.md2");
-re.RegisterModel ("models/objects/gibs/sm_meat/tris.md2");
-re.RegisterModel ("models/objects/gibs/bone2/tris.md2");
-// RAFAEL
-// re.RegisterModel ("models/objects/blaser/tris.md2");
-
-re.RegisterPic ("w_machinegun");
-re.RegisterPic ("a_bullets");
-re.RegisterPic ("i_health");
-re.RegisterPic ("a_grenades");
-
-//ROGUE
- cl_mod_explo4_big = re.RegisterModel ("models/objects/r_explode2/tris.md2");
- cl_mod_lightning = re.RegisterModel ("models/proj/lightning/tris.md2");
- cl_mod_heatbeam = re.RegisterModel ("models/proj/beam/tris.md2");
- cl_mod_monster_heatbeam = re.RegisterModel ("models/proj/widowbeam/tris.md2");
-//ROGUE
-}
-
-/*
-=================
-CL_ClearTEnts
-=================
-*/
-void CL_ClearTEnts (void)
-{
- memset (cl_beams, 0, sizeof(cl_beams));
- memset (cl_explosions, 0, sizeof(cl_explosions));
- memset (cl_lasers, 0, sizeof(cl_lasers));
-
-//ROGUE
- memset (cl_playerbeams, 0, sizeof(cl_playerbeams));
- memset (cl_sustains, 0, sizeof(cl_sustains));
-//ROGUE
-}
-
-/*
-=================
-CL_AllocExplosion
-=================
-*/
-explosion_t *CL_AllocExplosion (void)
-{
- int i;
- int time;
- int index;
-
- for (i=0 ; i<MAX_EXPLOSIONS ; i++)
- {
- if (cl_explosions[i].type == ex_free)
- {
- memset (&cl_explosions[i], 0, sizeof (cl_explosions[i]));
- return &cl_explosions[i];
- }
- }
-// find the oldest explosion
- time = cl.time;
- index = 0;
-
- for (i=0 ; i<MAX_EXPLOSIONS ; i++)
- if (cl_explosions[i].start < time)
- {
- time = cl_explosions[i].start;
- index = i;
- }
- memset (&cl_explosions[index], 0, sizeof (cl_explosions[index]));
- return &cl_explosions[index];
-}
-
-/*
-=================
-CL_SmokeAndFlash
-=================
-*/
-void CL_SmokeAndFlash(vec3_t origin)
-{
- explosion_t *ex;
-
- ex = CL_AllocExplosion ();
- VectorCopy (origin, ex->ent.origin);
- ex->type = ex_misc;
- ex->frames = 4;
- ex->ent.flags = RF_TRANSLUCENT;
- ex->start = cl.frame.servertime - 100;
- ex->ent.model = cl_mod_smoke;
-
- ex = CL_AllocExplosion ();
- VectorCopy (origin, ex->ent.origin);
- ex->type = ex_flash;
- ex->ent.flags = RF_FULLBRIGHT;
- ex->frames = 2;
- ex->start = cl.frame.servertime - 100;
- ex->ent.model = cl_mod_flash;
-}
-
-/*
-=================
-CL_ParseParticles
-=================
-*/
-void CL_ParseParticles (void)
-{
- int color, count;
- vec3_t pos, dir;
-
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
-
- color = MSG_ReadByte (&net_message);
-
- count = MSG_ReadByte (&net_message);
-
- CL_ParticleEffect (pos, dir, color, count);
-}
-
-/*
-=================
-CL_ParseBeam
-=================
-*/
-int CL_ParseBeam (struct model_s *model)
-{
- int ent;
- vec3_t start, end;
- beam_t *b;
- int i;
-
- ent = MSG_ReadShort (&net_message);
-
- MSG_ReadPos (&net_message, start);
- MSG_ReadPos (&net_message, end);
-
-// override any beam with the same entity
- for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
- if (b->entity == ent)
- {
- b->entity = ent;
- b->model = model;
- b->endtime = cl.time + 200;
- VectorCopy (start, b->start);
- VectorCopy (end, b->end);
- VectorClear (b->offset);
- return ent;
- }
-
-// find a free beam
- for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
- {
- if (!b->model || b->endtime < cl.time)
- {
- b->entity = ent;
- b->model = model;
- b->endtime = cl.time + 200;
- VectorCopy (start, b->start);
- VectorCopy (end, b->end);
- VectorClear (b->offset);
- return ent;
- }
- }
- Com_Printf ("beam list overflow!\n");
- return ent;
-}
-
-/*
-=================
-CL_ParseBeam2
-=================
-*/
-int CL_ParseBeam2 (struct model_s *model)
-{
- int ent;
- vec3_t start, end, offset;
- beam_t *b;
- int i;
-
- ent = MSG_ReadShort (&net_message);
-
- MSG_ReadPos (&net_message, start);
- MSG_ReadPos (&net_message, end);
- MSG_ReadPos (&net_message, offset);
-
-// Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
-
-// override any beam with the same entity
-
- for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
- if (b->entity == ent)
- {
- b->entity = ent;
- b->model = model;
- b->endtime = cl.time + 200;
- VectorCopy (start, b->start);
- VectorCopy (end, b->end);
- VectorCopy (offset, b->offset);
- return ent;
- }
-
-// find a free beam
- for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
- {
- if (!b->model || b->endtime < cl.time)
- {
- b->entity = ent;
- b->model = model;
- b->endtime = cl.time + 200;
- VectorCopy (start, b->start);
- VectorCopy (end, b->end);
- VectorCopy (offset, b->offset);
- return ent;
- }
- }
- Com_Printf ("beam list overflow!\n");
- return ent;
-}
-
-// ROGUE
-/*
-=================
-CL_ParsePlayerBeam
- - adds to the cl_playerbeam array instead of the cl_beams array
-=================
-*/
-int CL_ParsePlayerBeam (struct model_s *model)
-{
- int ent;
- vec3_t start, end, offset;
- beam_t *b;
- int i;
-
- ent = MSG_ReadShort (&net_message);
-
- MSG_ReadPos (&net_message, start);
- MSG_ReadPos (&net_message, end);
- // PMM - network optimization
- if (model == cl_mod_heatbeam)
- VectorSet(offset, 2, 7, -3);
- else if (model == cl_mod_monster_heatbeam)
- {
- model = cl_mod_heatbeam;
- VectorSet(offset, 0, 0, 0);
- }
- else
- MSG_ReadPos (&net_message, offset);
-
-// Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
-
-// override any beam with the same entity
-// PMM - For player beams, we only want one per player (entity) so..
- for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
- {
- if (b->entity == ent)
- {
- b->entity = ent;
- b->model = model;
- b->endtime = cl.time + 200;
- VectorCopy (start, b->start);
- VectorCopy (end, b->end);
- VectorCopy (offset, b->offset);
- return ent;
- }
- }
-
-// find a free beam
- for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
- {
- if (!b->model || b->endtime < cl.time)
- {
- b->entity = ent;
- b->model = model;
- b->endtime = cl.time + 100; // PMM - this needs to be 100 to prevent multiple heatbeams
- VectorCopy (start, b->start);
- VectorCopy (end, b->end);
- VectorCopy (offset, b->offset);
- return ent;
- }
- }
- Com_Printf ("beam list overflow!\n");
- return ent;
-}
-//rogue
-
-/*
-=================
-CL_ParseLightning
-=================
-*/
-int CL_ParseLightning (struct model_s *model)
-{
- int srcEnt, destEnt;
- vec3_t start, end;
- beam_t *b;
- int i;
-
- srcEnt = MSG_ReadShort (&net_message);
- destEnt = MSG_ReadShort (&net_message);
-
- MSG_ReadPos (&net_message, start);
- MSG_ReadPos (&net_message, end);
-
-// override any beam with the same source AND destination entities
- for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
- if (b->entity == srcEnt && b->dest_entity == destEnt)
- {
-// Com_Printf("%d: OVERRIDE %d -> %d\n", cl.time, srcEnt, destEnt);
- b->entity = srcEnt;
- b->dest_entity = destEnt;
- b->model = model;
- b->endtime = cl.time + 200;
- VectorCopy (start, b->start);
- VectorCopy (end, b->end);
- VectorClear (b->offset);
- return srcEnt;
- }
-
-// find a free beam
- for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
- {
- if (!b->model || b->endtime < cl.time)
- {
-// Com_Printf("%d: NORMAL %d -> %d\n", cl.time, srcEnt, destEnt);
- b->entity = srcEnt;
- b->dest_entity = destEnt;
- b->model = model;
- b->endtime = cl.time + 200;
- VectorCopy (start, b->start);
- VectorCopy (end, b->end);
- VectorClear (b->offset);
- return srcEnt;
- }
- }
- Com_Printf ("beam list overflow!\n");
- return srcEnt;
-}
-
-/*
-=================
-CL_ParseLaser
-=================
-*/
-void CL_ParseLaser (int colors)
-{
- vec3_t start;
- vec3_t end;
- laser_t *l;
- int i;
-
- MSG_ReadPos (&net_message, start);
- MSG_ReadPos (&net_message, end);
-
- for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
- {
- if (l->endtime < cl.time)
- {
- l->ent.flags = RF_TRANSLUCENT | RF_BEAM;
- VectorCopy (start, l->ent.origin);
- VectorCopy (end, l->ent.oldorigin);
- l->ent.alpha = 0.30;
- l->ent.skinnum = (colors >> ((rand() % 4)*8)) & 0xff;
- l->ent.model = NULL;
- l->ent.frame = 4;
- l->endtime = cl.time + 100;
- return;
- }
- }
-}
-
-//=============
-//ROGUE
-void CL_ParseSteam (void)
-{
- vec3_t pos, dir;
- int id, i;
- int r;
- int cnt;
- int color;
- int magnitude;
- cl_sustain_t *s, *free_sustain;
-
- id = MSG_ReadShort (&net_message); // an id of -1 is an instant effect
- if (id != -1) // sustains
- {
-// Com_Printf ("Sustain effect id %d\n", id);
- free_sustain = NULL;
- for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
- {
- if (s->id == 0)
- {
- free_sustain = s;
- break;
- }
- }
- if (free_sustain)
- {
- s->id = id;
- s->count = MSG_ReadByte (&net_message);
- MSG_ReadPos (&net_message, s->org);
- MSG_ReadDir (&net_message, s->dir);
- r = MSG_ReadByte (&net_message);
- s->color = r & 0xff;
- s->magnitude = MSG_ReadShort (&net_message);
- s->endtime = cl.time + MSG_ReadLong (&net_message);
- s->think = CL_ParticleSteamEffect2;
- s->thinkinterval = 100;
- s->nextthink = cl.time;
- }
- else
- {
-// Com_Printf ("No free sustains!\n");
- // FIXME - read the stuff anyway /* and toss the results */
- MSG_ReadByte (&net_message);
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- MSG_ReadByte (&net_message);
- MSG_ReadShort (&net_message);
- MSG_ReadLong (&net_message); // really interval
- }
- }
- else // instant
- {
- cnt = MSG_ReadByte (&net_message);
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- r = MSG_ReadByte (&net_message);
- magnitude = MSG_ReadShort (&net_message);
- color = r & 0xff;
- CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
-// S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
- }
-}
-
-void CL_ParseWidow (void)
-{
- vec3_t pos;
- int id, i;
- cl_sustain_t *s, *free_sustain;
-
- id = MSG_ReadShort (&net_message);
-
- free_sustain = NULL;
- for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
- {
- if (s->id == 0)
- {
- free_sustain = s;
- break;
- }
- }
- if (free_sustain)
- {
- s->id = id;
- MSG_ReadPos (&net_message, s->org);
- s->endtime = cl.time + 2100;
- s->think = CL_Widowbeamout;
- s->thinkinterval = 1;
- s->nextthink = cl.time;
- }
- else // no free sustains
- {
- // FIXME - read the stuff anyway
- MSG_ReadPos (&net_message, pos);
- }
-}
-
-void CL_ParseNuke (void)
-{
- vec3_t pos;
- int i;
- cl_sustain_t *s, *free_sustain;
-
- free_sustain = NULL;
- for (i=0, s=cl_sustains; i<MAX_SUSTAINS; i++, s++)
- {
- if (s->id == 0)
- {
- free_sustain = s;
- break;
- }
- }
- if (free_sustain)
- {
- s->id = 21000;
- MSG_ReadPos (&net_message, s->org);
- s->endtime = cl.time + 1000;
- s->think = CL_Nukeblast;
- s->thinkinterval = 1;
- s->nextthink = cl.time;
- }
- else // no free sustains
- {
- // FIXME - read the stuff anyway
- MSG_ReadPos (&net_message, pos);
- }
-}
-
-//ROGUE
-//=============
-
-
-/*
-=================
-CL_ParseTEnt
-=================
-*/
-static byte splash_color[] = {0x00, 0xe0, 0xb0, 0x50, 0xd0, 0xe0, 0xe8};
-
-void CL_ParseTEnt (void)
-{
- int type;
- vec3_t pos, pos2, dir;
- explosion_t *ex;
- int cnt;
- int color;
- int r;
- int ent;
- int magnitude;
-
- type = MSG_ReadByte (&net_message);
-
- switch (type)
- {
- case TE_BLOOD: // bullet hitting flesh
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- CL_ParticleEffect (pos, dir, 0xe8, 60);
- break;
-
- case TE_GUNSHOT: // bullet hitting wall
- case TE_SPARKS:
- case TE_BULLET_SPARKS:
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- if (type == TE_GUNSHOT)
- CL_ParticleEffect (pos, dir, 0, 40);
- else
- CL_ParticleEffect (pos, dir, 0xe0, 6);
-
- if (type != TE_SPARKS)
- {
- CL_SmokeAndFlash(pos);
-
- // impact sound
- cnt = rand()&15;
- if (cnt == 1)
- S_StartSound (pos, 0, 0, cl_sfx_ric1, 1, ATTN_NORM, 0);
- else if (cnt == 2)
- S_StartSound (pos, 0, 0, cl_sfx_ric2, 1, ATTN_NORM, 0);
- else if (cnt == 3)
- S_StartSound (pos, 0, 0, cl_sfx_ric3, 1, ATTN_NORM, 0);
- }
-
- break;
-
- case TE_SCREEN_SPARKS:
- case TE_SHIELD_SPARKS:
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- if (type == TE_SCREEN_SPARKS)
- CL_ParticleEffect (pos, dir, 0xd0, 40);
- else
- CL_ParticleEffect (pos, dir, 0xb0, 40);
- //FIXME : replace or remove this sound
- S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
- break;
-
- case TE_SHOTGUN: // bullet hitting wall
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- CL_ParticleEffect (pos, dir, 0, 20);
- CL_SmokeAndFlash(pos);
- break;
-
- case TE_SPLASH: // bullet hitting water
- cnt = MSG_ReadByte (&net_message);
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- r = MSG_ReadByte (&net_message);
- if (r > 6)
- color = 0x00;
- else
- color = splash_color[r];
- CL_ParticleEffect (pos, dir, color, cnt);
-
- if (r == SPLASH_SPARKS)
- {
- r = rand() & 3;
- if (r == 0)
- S_StartSound (pos, 0, 0, cl_sfx_spark5, 1, ATTN_STATIC, 0);
- else if (r == 1)
- S_StartSound (pos, 0, 0, cl_sfx_spark6, 1, ATTN_STATIC, 0);
- else
- S_StartSound (pos, 0, 0, cl_sfx_spark7, 1, ATTN_STATIC, 0);
- }
- break;
-
- case TE_LASER_SPARKS:
- cnt = MSG_ReadByte (&net_message);
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- color = MSG_ReadByte (&net_message);
- CL_ParticleEffect2 (pos, dir, color, cnt);
- break;
-
- // RAFAEL
- case TE_BLUEHYPERBLASTER:
- MSG_ReadPos (&net_message, pos);
- MSG_ReadPos (&net_message, dir);
- CL_BlasterParticles (pos, dir);
- break;
-
- case TE_BLASTER: // blaster hitting wall
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- CL_BlasterParticles (pos, dir);
-
- ex = CL_AllocExplosion ();
- VectorCopy (pos, ex->ent.origin);
- ex->ent.angles[0] = acos(dir[2])/M_PI*180;
- // PMM - fixed to correct for pitch of 0
- if (dir[0])
- ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
- else if (dir[1] > 0)
- ex->ent.angles[1] = 90;
- else if (dir[1] < 0)
- ex->ent.angles[1] = 270;
- else
- ex->ent.angles[1] = 0;
-
- ex->type = ex_misc;
- ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
- ex->start = cl.frame.servertime - 100;
- ex->light = 150;
- ex->lightcolor[0] = 1;
- ex->lightcolor[1] = 1;
- ex->ent.model = cl_mod_explode;
- ex->frames = 4;
- S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
- break;
-
- case TE_RAILTRAIL: // railgun effect
- MSG_ReadPos (&net_message, pos);
- MSG_ReadPos (&net_message, pos2);
- CL_RailTrail (pos, pos2);
- S_StartSound (pos2, 0, 0, cl_sfx_railg, 1, ATTN_NORM, 0);
- break;
-
- case TE_EXPLOSION2:
- case TE_GRENADE_EXPLOSION:
- case TE_GRENADE_EXPLOSION_WATER:
- MSG_ReadPos (&net_message, pos);
-
- ex = CL_AllocExplosion ();
- VectorCopy (pos, ex->ent.origin);
- ex->type = ex_poly;
- ex->ent.flags = RF_FULLBRIGHT;
- ex->start = cl.frame.servertime - 100;
- ex->light = 350;
- ex->lightcolor[0] = 1.0;
- ex->lightcolor[1] = 0.5;
- ex->lightcolor[2] = 0.5;
- ex->ent.model = cl_mod_explo4;
- ex->frames = 19;
- ex->baseframe = 30;
- ex->ent.angles[1] = rand() % 360;
- CL_ExplosionParticles (pos);
- if (type == TE_GRENADE_EXPLOSION_WATER)
- S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
- else
- S_StartSound (pos, 0, 0, cl_sfx_grenexp, 1, ATTN_NORM, 0);
- break;
-
- // RAFAEL
- case TE_PLASMA_EXPLOSION:
- MSG_ReadPos (&net_message, pos);
- ex = CL_AllocExplosion ();
- VectorCopy (pos, ex->ent.origin);
- ex->type = ex_poly;
- ex->ent.flags = RF_FULLBRIGHT;
- ex->start = cl.frame.servertime - 100;
- ex->light = 350;
- ex->lightcolor[0] = 1.0;
- ex->lightcolor[1] = 0.5;
- ex->lightcolor[2] = 0.5;
- ex->ent.angles[1] = rand() % 360;
- ex->ent.model = cl_mod_explo4;
- if (qfrand() < 0.5)
- ex->baseframe = 15;
- ex->frames = 15;
- CL_ExplosionParticles (pos);
- S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
- break;
-
- case TE_EXPLOSION1:
- case TE_EXPLOSION1_BIG: // PMM
- case TE_ROCKET_EXPLOSION:
- case TE_ROCKET_EXPLOSION_WATER:
- case TE_EXPLOSION1_NP: // PMM
- MSG_ReadPos (&net_message, pos);
-
- ex = CL_AllocExplosion ();
- VectorCopy (pos, ex->ent.origin);
- ex->type = ex_poly;
- ex->ent.flags = RF_FULLBRIGHT;
- ex->start = cl.frame.servertime - 100;
- ex->light = 350;
- ex->lightcolor[0] = 1.0;
- ex->lightcolor[1] = 0.5;
- ex->lightcolor[2] = 0.5;
- ex->ent.angles[1] = rand() % 360;
- if (type != TE_EXPLOSION1_BIG) // PMM
- ex->ent.model = cl_mod_explo4; // PMM
- else
- ex->ent.model = cl_mod_explo4_big;
- if (qfrand() < 0.5)
- ex->baseframe = 15;
- ex->frames = 15;
- if ((type != TE_EXPLOSION1_BIG) && (type != TE_EXPLOSION1_NP)) // PMM
- CL_ExplosionParticles (pos); // PMM
- if (type == TE_ROCKET_EXPLOSION_WATER)
- S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
- else
- S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
- break;
-
- case TE_BFG_EXPLOSION:
- MSG_ReadPos (&net_message, pos);
- ex = CL_AllocExplosion ();
- VectorCopy (pos, ex->ent.origin);
- ex->type = ex_poly;
- ex->ent.flags = RF_FULLBRIGHT;
- ex->start = cl.frame.servertime - 100;
- ex->light = 350;
- ex->lightcolor[0] = 0.0;
- ex->lightcolor[1] = 1.0;
- ex->lightcolor[2] = 0.0;
- ex->ent.model = cl_mod_bfg_explo;
- ex->ent.flags |= RF_TRANSLUCENT;
- ex->ent.alpha = 0.30;
- ex->frames = 4;
- break;
-
- case TE_BFG_BIGEXPLOSION:
- MSG_ReadPos (&net_message, pos);
- CL_BFGExplosionParticles (pos);
- break;
-
- case TE_BFG_LASER:
- CL_ParseLaser (0xd0d1d2d3);
- break;
-
- case TE_BUBBLETRAIL:
- MSG_ReadPos (&net_message, pos);
- MSG_ReadPos (&net_message, pos2);
- CL_BubbleTrail (pos, pos2);
- break;
-
- case TE_PARASITE_ATTACK:
- case TE_MEDIC_CABLE_ATTACK:
- CL_ParseBeam (cl_mod_parasite_segment); /* toss result */
- break;
-
- case TE_BOSSTPORT: // boss teleporting to station
- MSG_ReadPos (&net_message, pos);
- CL_BigTeleportParticles (pos);
- S_StartSound (pos, 0, 0, S_RegisterSound ("misc/bigtele.wav"), 1, ATTN_NONE, 0);
- break;
-
- case TE_GRAPPLE_CABLE:
- CL_ParseBeam2 (cl_mod_grapple_cable); /* toss result */
- break;
-
- // RAFAEL
- case TE_WELDING_SPARKS:
- cnt = MSG_ReadByte (&net_message);
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- color = MSG_ReadByte (&net_message);
- CL_ParticleEffect2 (pos, dir, color, cnt);
-
- ex = CL_AllocExplosion ();
- VectorCopy (pos, ex->ent.origin);
- ex->type = ex_flash;
- // note to self
- // we need a better no draw flag
- ex->ent.flags = RF_BEAM;
- ex->start = cl.frame.servertime - 0.1;
- ex->light = 100 + (rand()%75);
- ex->lightcolor[0] = 1.0;
- ex->lightcolor[1] = 1.0;
- ex->lightcolor[2] = 0.3;
- ex->ent.model = cl_mod_flash;
- ex->frames = 2;
- break;
-
- case TE_GREENBLOOD:
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- CL_ParticleEffect2 (pos, dir, 0xdf, 30);
- break;
-
- // RAFAEL
- case TE_TUNNEL_SPARKS:
- cnt = MSG_ReadByte (&net_message);
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- color = MSG_ReadByte (&net_message);
- CL_ParticleEffect3 (pos, dir, color, cnt);
- break;
-
-//=============
-//PGM
- // PMM -following code integrated for flechette (different color)
- case TE_BLASTER2: // green blaster hitting wall
- case TE_FLECHETTE: // flechette
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
-
- // PMM
- if (type == TE_BLASTER2)
- CL_BlasterParticles2 (pos, dir, 0xd0);
- else
- CL_BlasterParticles2 (pos, dir, 0x6f); // 75
-
- ex = CL_AllocExplosion ();
- VectorCopy (pos, ex->ent.origin);
- ex->ent.angles[0] = acos(dir[2])/M_PI*180;
- // PMM - fixed to correct for pitch of 0
- if (dir[0])
- ex->ent.angles[1] = atan2(dir[1], dir[0])/M_PI*180;
- else if (dir[1] > 0)
- ex->ent.angles[1] = 90;
- else if (dir[1] < 0)
- ex->ent.angles[1] = 270;
- else
- ex->ent.angles[1] = 0;
-
- ex->type = ex_misc;
- ex->ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
-
- // PMM
- if (type == TE_BLASTER2)
- ex->ent.skinnum = 1;
- else // flechette
- ex->ent.skinnum = 2;
-
- ex->start = cl.frame.servertime - 100;
- ex->light = 150;
- // PMM
- if (type == TE_BLASTER2)
- ex->lightcolor[1] = 1;
- else // flechette
- {
- ex->lightcolor[0] = 0.19;
- ex->lightcolor[1] = 0.41;
- ex->lightcolor[2] = 0.75;
- }
- ex->ent.model = cl_mod_explode;
- ex->frames = 4;
- S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
- break;
-
-
- case TE_LIGHTNING:
- ent = CL_ParseLightning (cl_mod_lightning);
- S_StartSound (NULL, ent, CHAN_WEAPON, cl_sfx_lightning, 1, ATTN_NORM, 0);
- break;
-
- case TE_DEBUGTRAIL:
- MSG_ReadPos (&net_message, pos);
- MSG_ReadPos (&net_message, pos2);
- CL_DebugTrail (pos, pos2);
- break;
-
- case TE_PLAIN_EXPLOSION:
- MSG_ReadPos (&net_message, pos);
-
- ex = CL_AllocExplosion ();
- VectorCopy (pos, ex->ent.origin);
- ex->type = ex_poly;
- ex->ent.flags = RF_FULLBRIGHT;
- ex->start = cl.frame.servertime - 100;
- ex->light = 350;
- ex->lightcolor[0] = 1.0;
- ex->lightcolor[1] = 0.5;
- ex->lightcolor[2] = 0.5;
- ex->ent.angles[1] = rand() % 360;
- ex->ent.model = cl_mod_explo4;
- if (qfrand() < 0.5)
- ex->baseframe = 15;
- ex->frames = 15;
- if (type == TE_ROCKET_EXPLOSION_WATER)
- S_StartSound (pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
- else
- S_StartSound (pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
- break;
-
- case TE_FLASHLIGHT:
- MSG_ReadPos(&net_message, pos);
- ent = MSG_ReadShort(&net_message);
- CL_Flashlight(ent, pos);
- break;
-
- case TE_FORCEWALL:
- MSG_ReadPos(&net_message, pos);
- MSG_ReadPos(&net_message, pos2);
- color = MSG_ReadByte (&net_message);
- CL_ForceWall(pos, pos2, color);
- break;
-
- case TE_HEATBEAM:
- CL_ParsePlayerBeam (cl_mod_heatbeam); /* toss result */
- break;
-
- case TE_MONSTER_HEATBEAM:
- CL_ParsePlayerBeam (cl_mod_monster_heatbeam); /* toss result */
- break;
-
- case TE_HEATBEAM_SPARKS:
-// cnt = MSG_ReadByte (&net_message);
- cnt = 50;
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
-// r = MSG_ReadByte (&net_message);
-// magnitude = MSG_ReadShort (&net_message);
- r = 8;
- magnitude = 60;
- color = r & 0xff;
- CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
- S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
- break;
-
- case TE_HEATBEAM_STEAM:
-// cnt = MSG_ReadByte (&net_message);
- cnt = 20;
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
-// r = MSG_ReadByte (&net_message);
-// magnitude = MSG_ReadShort (&net_message);
-// color = r & 0xff;
- color = 0xe0;
- magnitude = 60;
- CL_ParticleSteamEffect (pos, dir, color, cnt, magnitude);
- S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
- break;
-
- case TE_STEAM:
- CL_ParseSteam();
- break;
-
- case TE_BUBBLETRAIL2:
-// cnt = MSG_ReadByte (&net_message);
- cnt = 8;
- MSG_ReadPos (&net_message, pos);
- MSG_ReadPos (&net_message, pos2);
- CL_BubbleTrail2 (pos, pos2, cnt);
- S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
- break;
-
- case TE_MOREBLOOD:
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
- CL_ParticleEffect (pos, dir, 0xe8, 250);
- break;
-
- case TE_CHAINFIST_SMOKE:
- dir[0]=0; dir[1]=0; dir[2]=1;
- MSG_ReadPos(&net_message, pos);
- CL_ParticleSmokeEffect (pos, dir, 0, 20, 20);
- break;
-
- case TE_ELECTRIC_SPARKS:
- MSG_ReadPos (&net_message, pos);
- MSG_ReadDir (&net_message, dir);
-// CL_ParticleEffect (pos, dir, 109, 40);
- CL_ParticleEffect (pos, dir, 0x75, 40);
- //FIXME : replace or remove this sound
- S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
- break;
-
- case TE_TRACKER_EXPLOSION:
- MSG_ReadPos (&net_message, pos);
- CL_ColorFlash (pos, 0, 150, -1, -1, -1);
- CL_ColorExplosionParticles (pos, 0, 1);
-// CL_Tracker_Explode (pos);
- S_StartSound (pos, 0, 0, cl_sfx_disrexp, 1, ATTN_NORM, 0);
- break;
-
- case TE_TELEPORT_EFFECT:
- case TE_DBALL_GOAL:
- MSG_ReadPos (&net_message, pos);
- CL_TeleportParticles (pos);
- break;
-
- case TE_WIDOWBEAMOUT:
- CL_ParseWidow ();
- break;
-
- case TE_NUKEBLAST:
- CL_ParseNuke ();
- break;
-
- case TE_WIDOWSPLASH:
- MSG_ReadPos (&net_message, pos);
- CL_WidowSplash (pos);
- break;
-//PGM
-//==============
-
- default:
- Com_Error (ERR_DROP, "CL_ParseTEnt: bad type");
- }
-}
-
-/*
-=================
-CL_AddBeams
-=================
-*/
-void CL_AddBeams (void)
-{
- int i,j;
- beam_t *b;
- vec3_t dist, org;
- float d;
- entity_t ent;
- float yaw, pitch;
- float forward;
- float len, steps;
- float model_length;
-
-// update beams
- for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
- {
- if (!b->model || b->endtime < cl.time)
- continue;
-
- // if coming from the player, update the start position
- if (b->entity == cl.playernum+1) // entity 0 is the world
- {
- VectorCopy (cl.refdef.vieworg, b->start);
- b->start[2] -= 22; // adjust for view height
- }
- VectorAdd (b->start, b->offset, org);
-
- // calculate pitch and yaw
- VectorSubtract (b->end, org, dist);
-
- if (dist[1] == 0 && dist[0] == 0)
- {
- yaw = 0;
- if (dist[2] > 0)
- pitch = 90;
- else
- pitch = 270;
- }
- else
- {
- // PMM - fixed to correct for pitch of 0
- if (dist[0])
- yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
- else if (dist[1] > 0)
- yaw = 90;
- else
- yaw = 270;
- if (yaw < 0)
- yaw += 360;
-
- forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
- pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
- if (pitch < 0)
- pitch += 360.0;
- }
-
- // add new entities for the beams
- d = VectorNormalize(dist);
-
- memset (&ent, 0, sizeof(ent));
- if (b->model == cl_mod_lightning)
- {
- model_length = 35.0;
- d-= 20.0; // correction so it doesn't end in middle of tesla
- }
- else
- {
- model_length = 30.0;
- }
- steps = ceil(d/model_length);
- len = (d-model_length)/(steps-1);
-
- // PMM - special case for lightning model .. if the real length is shorter than the model,
- // flip it around & draw it from the end to the start. This prevents the model from going
- // through the tesla mine (instead it goes through the target)
- if ((b->model == cl_mod_lightning) && (d <= model_length))
- {
-// Com_Printf ("special case\n");
- VectorCopy (b->end, ent.origin);
- // offset to push beam outside of tesla model (negative because dist is from end to start
- // for this beam)
-// for (j=0 ; j<3 ; j++)
-// ent.origin[j] -= dist[j]*10.0;
- ent.model = b->model;
- ent.flags = RF_FULLBRIGHT;
- ent.angles[0] = pitch;
- ent.angles[1] = yaw;
- ent.angles[2] = rand()%360;
- V_AddEntity (&ent);
- return;
- }
- while (d > 0)
- {
- VectorCopy (org, ent.origin);
- ent.model = b->model;
- if (b->model == cl_mod_lightning)
- {
- ent.flags = RF_FULLBRIGHT;
- ent.angles[0] = -pitch;
- ent.angles[1] = yaw + 180.0;
- ent.angles[2] = rand()%360;
- }
- else
- {
- ent.angles[0] = pitch;
- ent.angles[1] = yaw;
- ent.angles[2] = rand()%360;
- }
-
-// Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity);
- V_AddEntity (&ent);
-
- for (j=0 ; j<3 ; j++)
- org[j] += dist[j]*len;
- d -= model_length;
- }
- }
-}
-
-
-/*
-// Com_Printf ("Endpoint: %f %f %f\n", b->end[0], b->end[1], b->end[2]);
-// Com_Printf ("Pred View Angles: %f %f %f\n", cl.predicted_angles[0], cl.predicted_angles[1], cl.predicted_angles[2]);
-// Com_Printf ("Act View Angles: %f %f %f\n", cl.refdef.viewangles[0], cl.refdef.viewangles[1], cl.refdef.viewangles[2]);
-// VectorCopy (cl.predicted_origin, b->start);
-// b->start[2] += 22; // adjust for view height
-// if (fabs(cl.refdef.vieworg[2] - b->start[2]) >= 10) {
-// b->start[2] = cl.refdef.vieworg[2];
-// }
-
-// Com_Printf ("Time: %d %d %f\n", cl.time, cls.realtime, cls.frametime);
-*/
-
-extern cvar_t *hand;
-
-/*
-=================
-ROGUE - draw player locked beams
-CL_AddPlayerBeams
-=================
-*/
-void CL_AddPlayerBeams (void)
-{
- int i,j;
- beam_t *b;
- vec3_t dist, org;
- float d;
- entity_t ent;
- float yaw, pitch;
- float forward;
- float len, steps;
- int framenum = 0;
- float model_length;
-
- float hand_multiplier;
- frame_t *oldframe;
- player_state_t *ps, *ops;
-
-//PMM
- if (hand)
- {
- if (hand->value == 2)
- hand_multiplier = 0;
- else if (hand->value == 1)
- hand_multiplier = -1;
- else
- hand_multiplier = 1;
- }
- else
- {
- hand_multiplier = 1;
- }
-//PMM
-
-// update beams
- for (i=0, b=cl_playerbeams ; i< MAX_BEAMS ; i++, b++)
- {
- vec3_t f,r,u;
- if (!b->model || b->endtime < cl.time)
- continue;
-
- if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
- {
-
- // if coming from the player, update the start position
- if (b->entity == cl.playernum+1) // entity 0 is the world
- {
- // set up gun position
- // code straight out of CL_AddViewWeapon
- ps = &cl.frame.playerstate;
- j = (cl.frame.serverframe - 1) & UPDATE_MASK;
- oldframe = &cl.frames[j];
- if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid)
- oldframe = &cl.frame; // previous frame was dropped or involid
- ops = &oldframe->playerstate;
- for (j=0 ; j<3 ; j++)
- {
- b->start[j] = cl.refdef.vieworg[j] + ops->gunoffset[j]
- + cl.lerpfrac * (ps->gunoffset[j] - ops->gunoffset[j]);
- }
- VectorMA (b->start, (hand_multiplier * b->offset[0]), cl.v_right, org);
- VectorMA ( org, b->offset[1], cl.v_forward, org);
- VectorMA ( org, b->offset[2], cl.v_up, org);
- if ((hand) && (hand->value == 2)) {
- VectorMA (org, -1, cl.v_up, org);
- }
- // FIXME - take these out when final
- VectorCopy (cl.v_right, r);
- VectorCopy (cl.v_forward, f);
- VectorCopy (cl.v_up, u);
-
- }
- else
- VectorCopy (b->start, org);
- }
- else
- {
- // if coming from the player, update the start position
- if (b->entity == cl.playernum+1) // entity 0 is the world
- {
- VectorCopy (cl.refdef.vieworg, b->start);
- b->start[2] -= 22; // adjust for view height
- }
- VectorAdd (b->start, b->offset, org);
- }
-
- // calculate pitch and yaw
- VectorSubtract (b->end, org, dist);
-
-//PMM
- if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.playernum+1))
- {
- vec_t len;
-
- len = VectorLength (dist);
- VectorScale (f, len, dist);
- VectorMA (dist, (hand_multiplier * b->offset[0]), r, dist);
- VectorMA (dist, b->offset[1], f, dist);
- VectorMA (dist, b->offset[2], u, dist);
- if ((hand) && (hand->value == 2)) {
- VectorMA (org, -1, cl.v_up, org);
- }
- }
-//PMM
-
- if (dist[1] == 0 && dist[0] == 0)
- {
- yaw = 0;
- if (dist[2] > 0)
- pitch = 90;
- else
- pitch = 270;
- }
- else
- {
- // PMM - fixed to correct for pitch of 0
- if (dist[0])
- yaw = (atan2(dist[1], dist[0]) * 180 / M_PI);
- else if (dist[1] > 0)
- yaw = 90;
- else
- yaw = 270;
- if (yaw < 0)
- yaw += 360;
-
- forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
- pitch = (atan2(dist[2], forward) * -180.0 / M_PI);
- if (pitch < 0)
- pitch += 360.0;
- }
-
- if (cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
- {
- if (b->entity != cl.playernum+1)
- {
- framenum = 2;
-// Com_Printf ("Third person\n");
- ent.angles[0] = -pitch;
- ent.angles[1] = yaw + 180.0;
- ent.angles[2] = 0;
-// Com_Printf ("%f %f - %f %f %f\n", -pitch, yaw+180.0, b->offset[0], b->offset[1], b->offset[2]);
- AngleVectors(ent.angles, f, r, u);
-
- // if it's a non-origin offset, it's a player, so use the hardcoded player offset
- if (!VectorCompare (b->offset, vec3_origin))
- {
- VectorMA (org, -(b->offset[0])+1, r, org);
- VectorMA (org, -(b->offset[1]), f, org);
- VectorMA (org, -(b->offset[2])-10, u, org);
- }
- else
- {
- // if it's a monster, do the particle effect
- CL_MonsterPlasma_Shell(b->start);
- }
- }
- else
- {
- framenum = 1;
- }
- }
-
- // if it's the heatbeam, draw the particle effect
- if ((cl_mod_heatbeam && (b->model == cl_mod_heatbeam) && (b->entity == cl.playernum+1)))
- {
- CL_Heatbeam (org, dist);
- }
-
- // add new entities for the beams
- d = VectorNormalize(dist);
-
- memset (&ent, 0, sizeof(ent));
- if (b->model == cl_mod_heatbeam)
- {
- model_length = 32.0;
- }
- else if (b->model == cl_mod_lightning)
- {
- model_length = 35.0;
- d-= 20.0; // correction so it doesn't end in middle of tesla
- }
- else
- {
- model_length = 30.0;
- }
- steps = ceil(d/model_length);
- len = (d-model_length)/(steps-1);
-
- // PMM - special case for lightning model .. if the real length is shorter than the model,
- // flip it around & draw it from the end to the start. This prevents the model from going
- // through the tesla mine (instead it goes through the target)
- if ((b->model == cl_mod_lightning) && (d <= model_length))
- {
-// Com_Printf ("special case\n");
- VectorCopy (b->end, ent.origin);
- // offset to push beam outside of tesla model (negative because dist is from end to start
- // for this beam)
-// for (j=0 ; j<3 ; j++)
-// ent.origin[j] -= dist[j]*10.0;
- ent.model = b->model;
- ent.flags = RF_FULLBRIGHT;
- ent.angles[0] = pitch;
- ent.angles[1] = yaw;
- ent.angles[2] = rand()%360;
- V_AddEntity (&ent);
- return;
- }
- while (d > 0)
- {
- VectorCopy (org, ent.origin);
- ent.model = b->model;
- if(cl_mod_heatbeam && (b->model == cl_mod_heatbeam))
- {
-// ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
-// ent.alpha = 0.3;
- ent.flags = RF_FULLBRIGHT;
- ent.angles[0] = -pitch;
- ent.angles[1] = yaw + 180.0;
- ent.angles[2] = (cl.time) % 360;
-// ent.angles[2] = rand()%360;
- ent.frame = framenum;
- }
- else if (b->model == cl_mod_lightning)
- {
- ent.flags = RF_FULLBRIGHT;
- ent.angles[0] = -pitch;
- ent.angles[1] = yaw + 180.0;
- ent.angles[2] = rand()%360;
- }
- else
- {
- ent.angles[0] = pitch;
- ent.angles[1] = yaw;
- ent.angles[2] = rand()%360;
- }
-
-// Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity);
- V_AddEntity (&ent);
-
- for (j=0 ; j<3 ; j++)
- org[j] += dist[j]*len;
- d -= model_length;
- }
- }
-}
-
-/*
-=================
-CL_AddExplosions
-=================
-*/
-void CL_AddExplosions (void)
-{
- entity_t *ent;
- int i;
- explosion_t *ex;
- float frac;
- int f;
-
- memset (&ent, 0, sizeof(ent));
-
- for (i=0, ex=cl_explosions ; i< MAX_EXPLOSIONS ; i++, ex++)
- {
- if (ex->type == ex_free)
- continue;
- frac = (cl.time - ex->start)/100.0;
- f = floor(frac);
-
- ent = &ex->ent;
-
- switch (ex->type)
- {
- case ex_mflash:
- if (f >= ex->frames-1)
- ex->type = ex_free;
- break;
- case ex_misc:
- if (f >= ex->frames-1)
- {
- ex->type = ex_free;
- break;
- }
- ent->alpha = 1.0 - frac/(ex->frames-1);
- break;
- case ex_flash:
- if (f >= 1)
- {
- ex->type = ex_free;
- break;
- }
- ent->alpha = 1.0;
- break;
- case ex_poly:
- if (f >= ex->frames-1)
- {
- ex->type = ex_free;
- break;
- }
-
- ent->alpha = (16.0 - (float)f)/16.0;
-
- if (f < 10)
- {
- ent->skinnum = (f>>1);
- if (ent->skinnum < 0)
- ent->skinnum = 0;
- }
- else
- {
- ent->flags |= RF_TRANSLUCENT;
- if (f < 13)
- ent->skinnum = 5;
- else
- ent->skinnum = 6;
- }
- break;
- case ex_poly2:
- if (f >= ex->frames-1)
- {
- ex->type = ex_free;
- break;
- }
-
- ent->alpha = (5.0 - (float)f)/5.0;
- ent->skinnum = 0;
- ent->flags |= RF_TRANSLUCENT;
- break;
- }
-
- if (ex->type == ex_free)
- continue;
- if (ex->light)
- {
- V_AddLight (ent->origin, ex->light*ent->alpha,
- ex->lightcolor[0], ex->lightcolor[1], ex->lightcolor[2]);
- }
-
- VectorCopy (ent->origin, ent->oldorigin);
-
- if (f < 0)
- f = 0;
- ent->frame = ex->baseframe + f + 1;
- ent->oldframe = ex->baseframe + f;
- ent->backlerp = 1.0 - cl.lerpfrac;
-
- V_AddEntity (ent);
- }
-}
-
-
-/*
-=================
-CL_AddLasers
-=================
-*/
-void CL_AddLasers (void)
-{
- laser_t *l;
- int i;
-
- for (i=0, l=cl_lasers ; i< MAX_LASERS ; i++, l++)
- {
- if (l->endtime >= cl.time)
- V_AddEntity (&l->ent);
- }
-}
-
-/* PMM - CL_Sustains */
-void CL_ProcessSustain (void)
-{
- cl_sustain_t *s;
- int i;
-
- for (i=0, s=cl_sustains; i< MAX_SUSTAINS; i++, s++)
- {
- if (s->id)
- if ((s->endtime >= cl.time) && (cl.time >= s->nextthink))
- {
-// Com_Printf ("think %d %d %d\n", cl.time, s->nextthink, s->thinkinterval);
- s->think (s);
- }
- else if (s->endtime < cl.time)
- s->id = 0;
- }
-}
-
-/*
-=================
-CL_AddTEnts
-=================
-*/
-void CL_AddTEnts (void)
-{
- CL_AddBeams ();
- // PMM - draw plasma beams
- CL_AddPlayerBeams ();
- CL_AddExplosions ();
- CL_AddLasers ();
- // PMM - set up sustain
- CL_ProcessSustain();
-}
--- a/client/cl_view.c
+++ /dev/null
@@ -1,568 +1,0 @@
-// cl_view.c -- player rendering positioning
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-//=============
-//
-// development tools for weapons
-//
-int gun_frame;
-struct model_s *gun_model;
-
-//=============
-
-cvar_t *crosshair;
-cvar_t *cl_testparticles;
-cvar_t *cl_testentities;
-cvar_t *cl_testlights;
-cvar_t *cl_testblend;
-
-cvar_t *cl_stats;
-
-
-int r_numdlights;
-dlight_t r_dlights[MAX_DLIGHTS];
-
-int r_numentities;
-entity_t r_entities[MAX_ENTITIES];
-
-int r_numparticles;
-particle_t r_particles[MAX_PARTICLES];
-
-lightstyle_t r_lightstyles[MAX_LIGHTSTYLES];
-
-char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
-int num_cl_weaponmodels;
-
-/*
-====================
-V_ClearScene
-
-Specifies the model that will be used as the world
-====================
-*/
-void V_ClearScene (void)
-{
- r_numdlights = 0;
- r_numentities = 0;
- r_numparticles = 0;
-}
-
-
-/*
-=====================
-V_AddEntity
-
-=====================
-*/
-void V_AddEntity (entity_t *ent)
-{
- if (r_numentities >= MAX_ENTITIES)
- return;
- r_entities[r_numentities++] = *ent;
-}
-
-
-/*
-=====================
-V_AddParticle
-
-=====================
-*/
-void V_AddParticle (vec3_t org, int color, float alpha)
-{
- particle_t *p;
-
- if (r_numparticles >= MAX_PARTICLES)
- return;
- p = &r_particles[r_numparticles++];
- VectorCopy (org, p->origin);
- p->color = color;
- p->alpha = alpha;
-}
-
-/*
-=====================
-V_AddLight
-
-=====================
-*/
-void V_AddLight (vec3_t org, float intensity, float r, float g, float b)
-{
- dlight_t *dl;
-
- if (r_numdlights >= MAX_DLIGHTS)
- return;
- dl = &r_dlights[r_numdlights++];
- VectorCopy (org, dl->origin);
- dl->intensity = intensity;
- dl->color[0] = r;
- dl->color[1] = g;
- dl->color[2] = b;
-}
-
-
-/*
-=====================
-V_AddLightStyle
-
-=====================
-*/
-void V_AddLightStyle (int style, float r, float g, float b)
-{
- lightstyle_t *ls;
-
- if (style < 0 || style > MAX_LIGHTSTYLES)
- Com_Error (ERR_DROP, "Bad light style %i", style);
- ls = &r_lightstyles[style];
-
- ls->white = r+g+b;
- ls->rgb[0] = r;
- ls->rgb[1] = g;
- ls->rgb[2] = b;
-}
-
-/*
-================
-V_TestParticles
-
-If cl_testparticles is set, create 4096 particles in the view
-================
-*/
-void V_TestParticles (void)
-{
- particle_t *p;
- int i, j;
- float d, r, u;
-
- r_numparticles = MAX_PARTICLES;
- for (i=0 ; i<r_numparticles ; i++)
- {
- d = i*0.25;
- r = 4*((i&7)-3.5);
- u = 4*(((i>>3)&7)-3.5);
- p = &r_particles[i];
-
- for (j=0 ; j<3 ; j++)
- p->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*d +
- cl.v_right[j]*r + cl.v_up[j]*u;
-
- p->color = 8;
- p->alpha = cl_testparticles->value;
- }
-}
-
-/*
-================
-V_TestEntities
-
-If cl_testentities is set, create 32 player models
-================
-*/
-void V_TestEntities (void)
-{
- int i, j;
- float f, r;
- entity_t *ent;
-
- r_numentities = 32;
- memset (r_entities, 0, sizeof(r_entities));
-
- for (i=0 ; i<r_numentities ; i++)
- {
- ent = &r_entities[i];
-
- r = 64 * ( (i%4) - 1.5 );
- f = 64 * (i/4) + 128;
-
- for (j=0 ; j<3 ; j++)
- ent->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
- cl.v_right[j]*r;
-
- ent->model = cl.baseclientinfo.model;
- ent->skin = cl.baseclientinfo.skin;
- }
-}
-
-/*
-================
-V_TestLights
-
-If cl_testlights is set, create 32 lights models
-================
-*/
-void V_TestLights (void)
-{
- int i, j;
- float f, r;
- dlight_t *dl;
-
- r_numdlights = 32;
- memset (r_dlights, 0, sizeof(r_dlights));
-
- for (i=0 ; i<r_numdlights ; i++)
- {
- dl = &r_dlights[i];
-
- r = 64 * ( (i%4) - 1.5 );
- f = 64 * (i/4) + 128;
-
- for (j=0 ; j<3 ; j++)
- dl->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
- cl.v_right[j]*r;
- dl->color[0] = ((i%6)+1) & 1;
- dl->color[1] = (((i%6)+1) & 2)>>1;
- dl->color[2] = (((i%6)+1) & 4)>>2;
- dl->intensity = 200;
- }
-}
-
-//===================================================================
-
-/*
-=================
-CL_PrepRefresh
-
-Call before entering a new level, or after changing dlls
-=================
-*/
-void CL_PrepRefresh (void)
-{
- char mapname[32];
- int i;
- char name[MAX_QPATH];
- float rotate;
- vec3_t axis;
-
- if (!cl.configstrings[CS_MODELS+1][0])
- return; // no map loaded
-
- SCR_AddDirtyPoint (0, 0);
- SCR_AddDirtyPoint (vid.width-1, vid.height-1);
-
- // let the render dll load the map
- strcpy (mapname, cl.configstrings[CS_MODELS+1] + 5); // skip "maps/"
- mapname[strlen(mapname)-4] = 0; // cut off ".bsp"
-
- // register models, pics, and skins
- Com_Printf ("Map: %s\r", mapname);
- SCR_UpdateScreen ();
- re.BeginRegistration (mapname);
- Com_Printf (" \r");
-
- // precache status bar pics
- Com_Printf ("pics\r");
- SCR_UpdateScreen ();
- SCR_TouchPics ();
- Com_Printf (" \r");
-
- CL_RegisterTEntModels ();
-
- num_cl_weaponmodels = 1;
- strcpy(cl_weaponmodels[0], "weapon.md2");
-
- for (i=1 ; i<MAX_MODELS && cl.configstrings[CS_MODELS+i][0] ; i++)
- {
- strcpy (name, cl.configstrings[CS_MODELS+i]);
- name[37] = 0; // never go beyond one line
- if (name[0] != '*')
- Com_Printf ("%s\r", name);
- SCR_UpdateScreen ();
- Sys_SendKeyEvents (); // pump message loop
- if (name[0] == '#')
- {
- // special player weapon model
- if (num_cl_weaponmodels < MAX_CLIENTWEAPONMODELS)
- {
- strncpy(cl_weaponmodels[num_cl_weaponmodels], cl.configstrings[CS_MODELS+i]+1,
- sizeof(cl_weaponmodels[num_cl_weaponmodels]) - 1);
- num_cl_weaponmodels++;
- }
- }
- else
- {
- cl.model_draw[i] = re.RegisterModel (cl.configstrings[CS_MODELS+i]);
- if (name[0] == '*')
- cl.model_clip[i] = CM_InlineModel (cl.configstrings[CS_MODELS+i]);
- else
- cl.model_clip[i] = NULL;
- }
- if (name[0] != '*')
- Com_Printf (" \r");
- }
-
- Com_Printf ("images\r", i);
- SCR_UpdateScreen ();
- for (i=1 ; i<MAX_IMAGES && cl.configstrings[CS_IMAGES+i][0] ; i++)
- {
- cl.image_precache[i] = re.RegisterPic (cl.configstrings[CS_IMAGES+i]);
- Sys_SendKeyEvents (); // pump message loop
- }
-
- Com_Printf (" \r");
- for (i=0 ; i<MAX_CLIENTS ; i++)
- {
- if (!cl.configstrings[CS_PLAYERSKINS+i][0])
- continue;
- Com_Printf ("client %i\r", i);
- SCR_UpdateScreen ();
- Sys_SendKeyEvents (); // pump message loop
- CL_ParseClientinfo (i);
- Com_Printf (" \r");
- }
-
- CL_LoadClientinfo (&cl.baseclientinfo, "unnamed\\male/grunt");
-
- // set sky textures and speed
- Com_Printf ("sky\r", i);
- SCR_UpdateScreen ();
- rotate = atof (cl.configstrings[CS_SKYROTATE]);
- sscanf (cl.configstrings[CS_SKYAXIS], "%f %f %f",
- &axis[0], &axis[1], &axis[2]);
- re.SetSky (cl.configstrings[CS_SKY], rotate, axis);
- Com_Printf (" \r");
-
- // the renderer can now free unneeded stuff
- re.EndRegistration ();
-
- // clear any lines of console text
- Con_ClearNotify ();
-
- SCR_UpdateScreen ();
- cl.refresh_prepped = true;
- cl.force_refdef = true; // make sure we have a valid refdef
-
- // start the cd track
- CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
-}
-
-/*
-====================
-CalcFov
-====================
-*/
-float CalcFov (float fov_x, float width, float height)
-{
- float a;
- float x;
-
- if (fov_x < 1 || fov_x > 179)
- Com_Error (ERR_DROP, "Bad fov: %f", fov_x);
-
- x = width/tan(fov_x/360*M_PI);
-
- a = atan (height/x);
-
- a = a*360/M_PI;
-
- return a;
-}
-
-//============================================================================
-
-// gun frame debugging functions
-void V_Gun_Next_f (void)
-{
- gun_frame++;
- Com_Printf ("frame %i\n", gun_frame);
-}
-
-void V_Gun_Prev_f (void)
-{
- gun_frame--;
- if (gun_frame < 0)
- gun_frame = 0;
- Com_Printf ("frame %i\n", gun_frame);
-}
-
-void V_Gun_Model_f (void)
-{
- char name[MAX_QPATH];
-
- if (Cmd_Argc() != 2)
- {
- gun_model = NULL;
- return;
- }
- Com_sprintf (name, sizeof(name), "models/%s/tris.md2", Cmd_Argv(1));
- gun_model = re.RegisterModel (name);
-}
-
-//============================================================================
-
-
-/*
-=================
-SCR_DrawCrosshair
-=================
-*/
-void SCR_DrawCrosshair (void)
-{
- if (!crosshair->value)
- return;
-
- if (crosshair->modified)
- {
- crosshair->modified = false;
- SCR_TouchPics ();
- }
-
- if (!crosshair_pic[0])
- return;
-
- re.DrawPic (scr_vrect.x + ((scr_vrect.width - crosshair_width)>>1)
- , scr_vrect.y + ((scr_vrect.height - crosshair_height)>>1), crosshair_pic);
-}
-
-/*
-==================
-V_RenderView
-
-==================
-*/
-void V_RenderView( float stereo_separation )
-{
- extern int entitycmpfnc( const entity_t *, const entity_t * );
-
- if (cls.state != ca_active)
- return;
-
- if (!cl.refresh_prepped)
- return; // still loading
-
- if (cl_timedemo->value)
- {
- if (!cl.timedemo_start)
- cl.timedemo_start = Sys_Milliseconds ();
- cl.timedemo_frames++;
- }
-
- // an invalid frame will just use the exact previous refdef
- // we can't use the old frame if the video mode has changed, though...
- if ( cl.frame.valid && (cl.force_refdef || !cl_paused->value) )
- {
- cl.force_refdef = false;
-
- V_ClearScene ();
-
- // build a refresh entity list and calc cl.sim*
- // this also calls CL_CalcViewValues which loads
- // v_forward, etc.
- CL_AddEntities ();
-
- if (cl_testparticles->value)
- V_TestParticles ();
- if (cl_testentities->value)
- V_TestEntities ();
- if (cl_testlights->value)
- V_TestLights ();
- if (cl_testblend->value)
- {
- cl.refdef.blend[0] = 1;
- cl.refdef.blend[1] = 0.5;
- cl.refdef.blend[2] = 0.25;
- cl.refdef.blend[3] = 0.5;
- }
-
- // offset vieworg appropriately if we're doing stereo separation
- if ( stereo_separation != 0 )
- {
- vec3_t tmp;
-
- VectorScale( cl.v_right, stereo_separation, tmp );
- VectorAdd( cl.refdef.vieworg, tmp, cl.refdef.vieworg );
- }
-
- // never let it sit exactly on a node line, because a water plane can
- // dissapear when viewed with the eye exactly on it.
- // the server protocol only specifies to 1/8 pixel, so add 1/16 in each axis
- cl.refdef.vieworg[0] += 1.0/16;
- cl.refdef.vieworg[1] += 1.0/16;
- cl.refdef.vieworg[2] += 1.0/16;
-
- cl.refdef.x = scr_vrect.x;
- cl.refdef.y = scr_vrect.y;
- cl.refdef.width = scr_vrect.width;
- cl.refdef.height = scr_vrect.height;
- cl.refdef.fov_y = CalcFov (cl.refdef.fov_x, cl.refdef.width, cl.refdef.height);
- cl.refdef.time = cl.time*0.001;
-
- cl.refdef.areabits = cl.frame.areabits;
-
- if (!cl_add_entities->value)
- r_numentities = 0;
- if (!cl_add_particles->value)
- r_numparticles = 0;
- if (!cl_add_lights->value)
- r_numdlights = 0;
- if (!cl_add_blend->value)
- {
- VectorClear (cl.refdef.blend);
- }
-
- cl.refdef.num_entities = r_numentities;
- cl.refdef.entities = r_entities;
- cl.refdef.num_particles = r_numparticles;
- cl.refdef.particles = r_particles;
- cl.refdef.num_dlights = r_numdlights;
- cl.refdef.dlights = r_dlights;
- cl.refdef.lightstyles = r_lightstyles;
-
- cl.refdef.rdflags = cl.frame.playerstate.rdflags;
-
- // sort entities for better cache locality
- qsort( cl.refdef.entities, cl.refdef.num_entities, sizeof( cl.refdef.entities[0] ), (int (*)(const void *, const void *))entitycmpfnc );
- }
-
- re.RenderFrame (&cl.refdef);
- if (cl_stats->value)
- Com_Printf ("ent:%i lt:%i part:%i\n", r_numentities, r_numdlights, r_numparticles);
- if ( log_stats->value && ( log_stats_file != 0 ) )
- fprintf( log_stats_file, "%i,%i,%i,",r_numentities, r_numdlights, r_numparticles);
-
-
- SCR_AddDirtyPoint (scr_vrect.x, scr_vrect.y);
- SCR_AddDirtyPoint (scr_vrect.x+scr_vrect.width-1,
- scr_vrect.y+scr_vrect.height-1);
-
- SCR_DrawCrosshair ();
-}
-
-
-/*
-=============
-V_Viewpos_f
-=============
-*/
-void V_Viewpos_f (void)
-{
- Com_Printf ("(%i %i %i) : %i\n", (int)cl.refdef.vieworg[0],
- (int)cl.refdef.vieworg[1], (int)cl.refdef.vieworg[2],
- (int)cl.refdef.viewangles[YAW]);
-}
-
-/*
-=============
-V_Init
-=============
-*/
-void V_Init (void)
-{
- Cmd_AddCommand ("gun_next", V_Gun_Next_f);
- Cmd_AddCommand ("gun_prev", V_Gun_Prev_f);
- Cmd_AddCommand ("gun_model", V_Gun_Model_f);
-
- Cmd_AddCommand ("viewpos", V_Viewpos_f);
-
- crosshair = Cvar_Get ("crosshair", "0", CVAR_ARCHIVE);
-
- cl_testblend = Cvar_Get ("cl_testblend", "0", 0);
- cl_testparticles = Cvar_Get ("cl_testparticles", "0", 0);
- cl_testentities = Cvar_Get ("cl_testentities", "0", 0);
- cl_testlights = Cvar_Get ("cl_testlights", "0", 0);
-
- cl_stats = Cvar_Get ("cl_stats", "0", 0);
-}
--- a/client/client.h
+++ /dev/null
@@ -1,536 +1,0 @@
-// client.h -- primary header for client
-
-//#define PARANOID // speed sapping error checking
-
-//=============================================================================
-typedef struct
-{
- qboolean valid; // cleared if delta parsing was invalid
- int serverframe;
- int servertime; // server time the message is valid for (in msec)
- int deltaframe;
- byte areabits[MAX_MAP_AREAS/8]; // portalarea visibility bits
- player_state_t playerstate;
- int num_entities;
- int parse_entities; // non-masked index into cl_parse_entities array
-} frame_t;
-
-typedef struct
-{
- entity_state_t baseline; // delta from this if not from a previous frame
- entity_state_t current;
- entity_state_t prev; // will always be valid, but might just be a copy of current
-
- int serverframe; // if not current, this ent isn't in the frame
-
- int trailcount; // for diminishing grenade trails
- vec3_t lerp_origin; // for trails (variable hz)
-
- int fly_stoptime;
-} centity_t;
-
-#define MAX_CLIENTWEAPONMODELS 20 // PGM -- upped from 16 to fit the chainfist vwep
-
-typedef struct
-{
- char name[MAX_QPATH];
- char cinfo[MAX_QPATH];
- struct image_s *skin;
- struct image_s *icon;
- char iconname[MAX_QPATH];
- struct model_s *model;
- struct model_s *weaponmodel[MAX_CLIENTWEAPONMODELS];
-} clientinfo_t;
-
-extern char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
-extern int num_cl_weaponmodels;
-
-#define CMD_BACKUP 64 // allow a lot of command backups for very fast systems
-
-//
-// the client_state_t structure is wiped completely at every
-// server map change
-//
-typedef struct
-{
- int timeoutcount;
-
- int timedemo_frames;
- int timedemo_start;
-
- qboolean refresh_prepped; // false if on new level or new ref dll
- qboolean sound_prepped; // ambient sounds can start
- qboolean force_refdef; // vid has changed, so we can't use a paused refdef
-
- int parse_entities; // index (not anded off) into cl_parse_entities[]
-
- usercmd_t cmd;
- usercmd_t cmds[CMD_BACKUP]; // each mesage will send several old cmds
- int cmd_time[CMD_BACKUP]; // time sent, for calculating pings
- short predicted_origins[CMD_BACKUP][3]; // for debug comparing against server
-
- float predicted_step; // for stair up smoothing
- unsigned predicted_step_time;
-
- vec3_t predicted_origin; // generated by CL_PredictMovement
- vec3_t predicted_angles;
- vec3_t prediction_error;
-
- frame_t frame; // received from server
- int surpressCount; // number of messages rate supressed
- frame_t frames[UPDATE_BACKUP];
-
- // the client maintains its own idea of view angles, which are
- // sent to the server each frame. It is cleared to 0 upon entering each level.
- // the server sends a delta each frame which is added to the locally
- // tracked view angles to account for standing on rotating objects,
- // and teleport direction changes
- vec3_t viewangles;
-
- int time; // this is the time value that the client
- // is rendering at. always <= cls.realtime
- float lerpfrac; // between oldframe and frame
-
- refdef_t refdef;
-
- vec3_t v_forward, v_right, v_up; // set when refdef.angles is set
-
- //
- // transient data from server
- //
- char layout[1024]; // general 2D overlay
- int inventory[MAX_ITEMS];
-
- //
- // non-gameserver infornamtion
- // FIXME: move this cinematic stuff into the cin_t structure
- FILE *cinematic_file;
- int cinematictime; // cls.realtime for first cinematic frame
- int cinematicframe;
- char cinematicpalette[768];
- qboolean cinematicpalette_active;
-
- //
- // server state information
- //
- qboolean attractloop; // running the attract loop, any key will menu
- int servercount; // server identification for prespawns
- char gamedir[MAX_QPATH];
- int playernum;
-
- char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH];
-
- //
- // locally derived information from server state
- //
- struct model_s *model_draw[MAX_MODELS];
- struct cmodel_s *model_clip[MAX_MODELS];
-
- struct sfx_s *sound_precache[MAX_SOUNDS];
- struct image_s *image_precache[MAX_IMAGES];
-
- clientinfo_t clientinfo[MAX_CLIENTS];
- clientinfo_t baseclientinfo;
-} client_state_t;
-
-extern client_state_t cl;
-/*
-==================================================================
-
-the client_static_t structure is persistant through an arbitrary number
-of server connections
-
-==================================================================
-*/
-
-typedef enum {
- ca_uninitialized,
- ca_disconnected, // not talking to a server
- ca_connecting, // sending request packets to the server
- ca_connected, // netchan_t established, waiting for svc_serverdata
- ca_active // game views should be displayed
-} connstate_t;
-
-typedef enum {
- dl_none,
- dl_model,
- dl_sound,
- dl_skin,
- dl_single
-} dltype_t; // download type
-
-typedef enum {key_game, key_console, key_message, key_menu} keydest_t;
-
-typedef struct
-{
- connstate_t state;
- keydest_t key_dest;
-
- int framecount;
- int realtime; // always increasing, no clamping, etc
- float frametime; // seconds since last frame
-
-// screen rendering information
- float disable_screen; // showing loading plaque between levels
- // or changing rendering dlls
- // if time gets > 30 seconds ahead, break it
- int disable_servercount; // when we receive a frame and cl.servercount
- // > cls.disable_servercount, clear disable_screen
-
-// connection information
- char servername[MAX_OSPATH]; // name of server from original connect
- float connect_time; // for connection retransmits
-
- int quakePort; // a 16 bit value that allows quake servers
- // to work around address translating routers
- netchan_t netchan;
- int serverProtocol; // in case we are doing some kind of version hack
-
- int challenge; // from the server to use for connecting
-
- FILE *download; // file transfer from server
- char downloadtempname[MAX_OSPATH];
- char downloadname[MAX_OSPATH];
- int downloadnumber;
- dltype_t downloadtype;
- int downloadpercent;
-
-// demo recording info must be here, so it isn't cleared on level change
- qboolean demorecording;
- qboolean demowaiting; // don't record until a non-delta message is received
- FILE *demofile;
-} client_static_t;
-
-extern client_static_t cls;
-
-//=============================================================================
-
-//
-// cvars
-//
-extern cvar_t *cl_stereo_separation;
-extern cvar_t *cl_stereo;
-
-extern cvar_t *cl_gun;
-extern cvar_t *cl_add_blend;
-extern cvar_t *cl_add_lights;
-extern cvar_t *cl_add_particles;
-extern cvar_t *cl_add_entities;
-extern cvar_t *cl_predict;
-extern cvar_t *cl_footsteps;
-extern cvar_t *cl_noskins;
-extern cvar_t *cl_autoskins;
-
-extern cvar_t *cl_upspeed;
-extern cvar_t *cl_forwardspeed;
-extern cvar_t *cl_sidespeed;
-
-extern cvar_t *cl_yawspeed;
-extern cvar_t *cl_pitchspeed;
-
-extern cvar_t *cl_run;
-
-extern cvar_t *cl_anglespeedkey;
-
-extern cvar_t *cl_shownet;
-extern cvar_t *cl_showmiss;
-extern cvar_t *cl_showclamp;
-
-extern cvar_t *cl_lightlevel; // FIXME HACK
-
-extern cvar_t *cl_paused;
-extern cvar_t *cl_timedemo;
-
-extern cvar_t *cl_vwep;
-
-typedef struct
-{
- int key; // so entities can reuse same entry
- vec3_t color;
- vec3_t origin;
- float radius;
- float die; // stop lighting after this time
- float decay; // drop this each second
- float minlight; // don't add when contributing less
-} cdlight_t;
-
-extern centity_t cl_entities[MAX_EDICTS];
-extern cdlight_t cl_dlights[MAX_DLIGHTS];
-
-// the cl_parse_entities must be large enough to hold UPDATE_BACKUP frames of
-// entities, so that when a delta compressed message arives from the server
-// it can be un-deltad from the original
-#define MAX_PARSE_ENTITIES 1024
-extern entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES];
-
-//=============================================================================
-
-extern netadr_t net_from;
-extern sizebuf_t net_message;
-
-void DrawString (int x, int y, char *s);
-void DrawAltString (int x, int y, char *s); // toggle high bit
-qboolean CL_CheckOrDownloadFile (char *filename);
-
-void CL_AddNetgraph (void);
-
-//ROGUE
-typedef struct cl_sustain
-{
- int id;
- int type;
- int endtime;
- int nextthink;
- int thinkinterval;
- vec3_t org;
- vec3_t dir;
- int color;
- int count;
- int magnitude;
- void (*think)(struct cl_sustain *self);
-} cl_sustain_t;
-
-#define MAX_SUSTAINS 32
-void CL_ParticleSteamEffect2(cl_sustain_t *self);
-
-void CL_TeleporterParticles (entity_state_t *ent);
-void CL_ParticleEffect (vec3_t org, vec3_t dir, int color, int count);
-void CL_ParticleEffect2 (vec3_t org, vec3_t dir, int color, int count);
-
-// RAFAEL
-void CL_ParticleEffect3 (vec3_t org, vec3_t dir, int color, int count);
-
-
-//=================================================
-
-// ========
-// PGM
-typedef struct particle_s
-{
- struct particle_s *next;
-
- float time;
-
- vec3_t org;
- vec3_t vel;
- vec3_t accel;
- float color;
- float colorvel;
- float alpha;
- float alphavel;
-} cparticle_t;
-
-
-#define PARTICLE_GRAVITY 40
-#define BLASTER_PARTICLE_COLOR 0xe0
-// PMM
-#define INSTANT_PARTICLE -10000.0
-// PGM
-// ========
-
-void CL_ClearEffects (void);
-void CL_ClearTEnts (void);
-void CL_BlasterTrail (vec3_t start, vec3_t end);
-void CL_QuadTrail (vec3_t start, vec3_t end);
-void CL_RailTrail (vec3_t start, vec3_t end);
-void CL_BubbleTrail (vec3_t start, vec3_t end);
-void CL_FlagTrail (vec3_t start, vec3_t end, float color);
-
-// RAFAEL
-void CL_IonripperTrail (vec3_t start, vec3_t end);
-
-// ========
-// PGM
-void CL_BlasterParticles2 (vec3_t org, vec3_t dir, unsigned int color);
-void CL_BlasterTrail2 (vec3_t start, vec3_t end);
-void CL_DebugTrail (vec3_t start, vec3_t end);
-void CL_SmokeTrail (vec3_t start, vec3_t end, int colorStart, int colorRun, int spacing);
-void CL_Flashlight (int ent, vec3_t pos);
-void CL_ForceWall (vec3_t start, vec3_t end, int color);
-void CL_FlameEffects (centity_t *ent, vec3_t origin);
-void CL_GenericParticleEffect (vec3_t org, vec3_t dir, int color, int count, int numcolors, int dirspread, float alphavel);
-void CL_BubbleTrail2 (vec3_t start, vec3_t end, int dist);
-void CL_Heatbeam (vec3_t start, vec3_t end);
-void CL_ParticleSteamEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude);
-void CL_TrackerTrail (vec3_t start, vec3_t end, int particleColor);
-void CL_Tracker_Explode(vec3_t origin);
-void CL_TagTrail (vec3_t start, vec3_t end, float color);
-void CL_ColorFlash (vec3_t pos, int ent, int intensity, float r, float g, float b);
-void CL_Tracker_Shell(vec3_t origin);
-void CL_MonsterPlasma_Shell(vec3_t origin);
-void CL_ColorExplosionParticles (vec3_t org, int color, int run);
-void CL_ParticleSmokeEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude);
-void CL_Widowbeamout (cl_sustain_t *self);
-void CL_Nukeblast (cl_sustain_t *self);
-void CL_WidowSplash (vec3_t org);
-// PGM
-// ========
-
-int CL_ParseEntityBits (int *bits);
-void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int number, int bits);
-void CL_ParseFrame (void);
-
-void CL_ParseTEnt (void);
-void CL_ParseConfigString (void);
-void CL_ParseMuzzleFlash (void);
-void CL_ParseMuzzleFlash2 (void);
-void SmokeAndFlash(vec3_t origin);
-
-void CL_SetLightstyle (int i);
-
-void CL_RunParticles (void);
-void CL_RunDLights (void);
-void CL_RunLightStyles (void);
-
-void CL_AddEntities (void);
-void CL_AddDLights (void);
-void CL_AddTEnts (void);
-void CL_AddLightStyles (void);
-
-//=================================================
-
-void CL_PrepRefresh (void);
-void CL_RegisterSounds (void);
-
-void CL_Quit_f (void);
-
-void IN_Accumulate (void);
-
-void CL_ParseLayout (void);
-
-
-//
-// cl_main
-//
-extern refexport_t re; // interface to refresh .dll
-
-void CL_Init (void);
-
-void CL_FixUpGender(void);
-void CL_Disconnect (void);
-void CL_Disconnect_f (void);
-void CL_GetChallengePacket (void);
-void CL_PingServers_f (void);
-void CL_Snd_Restart_f (void);
-void CL_RequestNextDownload (void);
-
-//
-// cl_input
-//
-typedef struct
-{
- int down[2]; // key nums holding it down
- unsigned downtime; // msec timestamp
- unsigned msec; // msec down this frame
- int state;
-} kbutton_t;
-
-extern kbutton_t in_mlook, in_klook;
-extern kbutton_t in_strafe;
-extern kbutton_t in_speed;
-
-void CL_InitInput (void);
-void CL_SendCmd (void);
-void CL_SendMove (usercmd_t *cmd);
-
-void CL_ClearState (void);
-
-void CL_ReadPackets (void);
-
-int CL_ReadFromServer (void);
-void CL_WriteToServer (usercmd_t *cmd);
-void CL_BaseMove (usercmd_t *cmd);
-
-void IN_CenterView (void);
-
-float CL_KeyState (kbutton_t *key);
-char *Key_KeynumToString (int keynum);
-
-//
-// cl_demo.c
-//
-void CL_WriteDemoMessage (void);
-void CL_Stop_f (void);
-void CL_Record_f (void);
-
-//
-// cl_parse.c
-//
-extern char *svc_strings[256];
-
-void CL_ParseServerMessage (void);
-void CL_LoadClientinfo (clientinfo_t *ci, char *s);
-void SHOWNET(char *s);
-void CL_ParseClientinfo (int player);
-void CL_Download_f (void);
-
-//
-// cl_view.c
-//
-extern int gun_frame;
-extern struct model_s *gun_model;
-
-void V_Init (void);
-void V_RenderView( float stereo_separation );
-void V_AddEntity (entity_t *ent);
-void V_AddParticle (vec3_t org, int color, float alpha);
-void V_AddLight (vec3_t org, float intensity, float r, float g, float b);
-void V_AddLightStyle (int style, float r, float g, float b);
-
-//
-// cl_tent.c
-//
-void CL_RegisterTEntSounds (void);
-void CL_RegisterTEntModels (void);
-void CL_SmokeAndFlash(vec3_t origin);
-
-
-//
-// cl_pred.c
-//
-void CL_InitPrediction (void);
-void CL_PredictMove (void);
-void CL_CheckPredictionError (void);
-
-//
-// cl_fx.c
-//
-cdlight_t *CL_AllocDlight (int key);
-void CL_BigTeleportParticles (vec3_t org);
-void CL_RocketTrail (vec3_t start, vec3_t end, centity_t *old);
-void CL_DiminishingTrail (vec3_t start, vec3_t end, centity_t *old, int flags);
-void CL_FlyEffect (centity_t *ent, vec3_t origin);
-void CL_BfgParticles (entity_t *ent);
-void CL_AddParticles (void);
-void CL_EntityEvent (entity_state_t *ent);
-// RAFAEL
-void CL_TrapParticles (entity_t *ent);
-
-//
-// menus
-//
-void M_Init (void);
-void M_Keydown (int key);
-void M_Draw (void);
-void M_Menu_Main_f (void);
-void M_ForceMenuOff (void);
-void M_AddToServerList (netadr_t adr, char *info);
-
-//
-// cl_inv.c
-//
-void CL_ParseInventory (void);
-void CL_KeyInventory (int key);
-void CL_DrawInventory (void);
-
-//
-// cl_pred.c
-//
-void CL_PredictMovement (void);
-
-#ifdef id386
-void x86_TimerStart( void );
-void x86_TimerStop( void );
-void x86_TimerInit( unsigned long smallest, unsigned longest );
-unsigned long *x86_TimerGetHistogram( void );
-#endif
--- a/client/console.c
+++ /dev/null
@@ -1,660 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-console_t con;
-
-cvar_t *con_notifytime;
-
-
-#define MAXCMDLINE 256
-extern char key_lines[32][MAXCMDLINE];
-extern int edit_line;
-extern int key_linepos;
-
-
-void DrawString (int x, int y, char *s)
-{
- while (*s)
- {
- re.DrawChar (x, y, *s);
- x+=8;
- s++;
- }
-}
-
-void DrawAltString (int x, int y, char *s)
-{
- while (*s)
- {
- re.DrawChar (x, y, *s ^ 0x80);
- x+=8;
- s++;
- }
-}
-
-
-void Key_ClearTyping (void)
-{
- key_lines[edit_line][1] = 0; // clear any typing
- key_linepos = 1;
-}
-
-/*
-================
-Con_ToggleConsole_f
-================
-*/
-void Con_ToggleConsole_f (void)
-{
- SCR_EndLoadingPlaque (); // get rid of loading plaque
-
- if (cl.attractloop)
- {
- Cbuf_AddText ("killserver\n");
- return;
- }
-
- if (cls.state == ca_disconnected)
- { // start the demo loop again
- Cbuf_AddText ("d1\n");
- return;
- }
-
- Key_ClearTyping ();
- Con_ClearNotify ();
-
- if (cls.key_dest == key_console)
- {
- M_ForceMenuOff ();
- Cvar_Set ("paused", "0");
- IN_Grabm (1);
- }
- else
- {
- M_ForceMenuOff ();
- cls.key_dest = key_console;
-
- if (Cvar_VariableValue ("maxclients") == 1
- && Com_ServerState ())
- Cvar_Set ("paused", "1");
- IN_Grabm (0);
- }
-}
-
-/*
-================
-Con_ToggleChat_f
-================
-*/
-void Con_ToggleChat_f (void)
-{
- Key_ClearTyping ();
-
- if (cls.key_dest == key_console)
- {
- if (cls.state == ca_active)
- {
- M_ForceMenuOff ();
- cls.key_dest = key_game;
- }
- }
- else
- cls.key_dest = key_console;
-
- Con_ClearNotify ();
-}
-
-/*
-================
-Con_Clear_f
-================
-*/
-void Con_Clear_f (void)
-{
- memset (con.text, ' ', CON_TEXTSIZE);
-}
-
-
-/*
-================
-Con_Dump_f
-
-Save the console contents out to a file
-================
-*/
-void Con_Dump_f (void)
-{
- int l, x;
- char *line;
- FILE *f;
- char buffer[1024];
- char name[MAX_OSPATH];
-
- if (Cmd_Argc() != 2)
- {
- Com_Printf ("usage: condump <filename>\n");
- return;
- }
-
- Com_sprintf (name, sizeof(name), "%s/%s.txt", FS_Gamedir(), Cmd_Argv(1));
-
- Com_Printf ("Dumped console text to %s.\n", name);
- FS_CreatePath (name);
- f = fopen (name, "w");
- if (!f)
- {
- Com_Printf ("ERROR: couldn't open.\n");
- return;
- }
-
- // skip empty lines
- for (l = con.current - con.totallines + 1 ; l <= con.current ; l++)
- {
- line = con.text + (l%con.totallines)*con.linewidth;
- for (x=0 ; x<con.linewidth ; x++)
- if (line[x] != ' ')
- break;
- if (x != con.linewidth)
- break;
- }
-
- // write the remaining lines
- buffer[con.linewidth] = 0;
- for ( ; l <= con.current ; l++)
- {
- line = con.text + (l%con.totallines)*con.linewidth;
- strncpy (buffer, line, con.linewidth);
- for (x=con.linewidth-1 ; x>=0 ; x--)
- {
- if (buffer[x] == ' ')
- buffer[x] = 0;
- else
- break;
- }
- for (x=0; buffer[x]; x++)
- buffer[x] &= 0x7f;
-
- fprintf (f, "%s\n", buffer);
- }
-
- fclose (f);
-}
-
-
-/*
-================
-Con_ClearNotify
-================
-*/
-void Con_ClearNotify (void)
-{
- int i;
-
- for (i=0 ; i<NUM_CON_TIMES ; i++)
- con.times[i] = 0;
-}
-
-
-/*
-================
-Con_MessageMode_f
-================
-*/
-void Con_MessageMode_f (void)
-{
- chat_team = false;
- cls.key_dest = key_message;
-}
-
-/*
-================
-Con_MessageMode2_f
-================
-*/
-void Con_MessageMode2_f (void)
-{
- chat_team = true;
- cls.key_dest = key_message;
-}
-
-/*
-================
-Con_CheckResize
-
-If the line width has changed, reformat the buffer.
-================
-*/
-void Con_CheckResize (void)
-{
- int i, j, width, oldwidth, oldtotallines, numlines, numchars;
- char tbuf[CON_TEXTSIZE];
-
- width = (vid.width >> 3) - 2;
-
- if (width == con.linewidth)
- return;
-
- if (width < 1) // video hasn't been initialized yet
- {
- width = 38;
- con.linewidth = width;
- con.totallines = CON_TEXTSIZE / con.linewidth;
- memset (con.text, ' ', CON_TEXTSIZE);
- }
- else
- {
- oldwidth = con.linewidth;
- con.linewidth = width;
- oldtotallines = con.totallines;
- con.totallines = CON_TEXTSIZE / con.linewidth;
- numlines = oldtotallines;
-
- if (con.totallines < numlines)
- numlines = con.totallines;
-
- numchars = oldwidth;
-
- if (con.linewidth < numchars)
- numchars = con.linewidth;
-
- memcpy (tbuf, con.text, CON_TEXTSIZE);
- memset (con.text, ' ', CON_TEXTSIZE);
-
- for (i=0 ; i<numlines ; i++)
- {
- for (j=0 ; j<numchars ; j++)
- {
- con.text[(con.totallines - 1 - i) * con.linewidth + j] =
- tbuf[((con.current - i + oldtotallines) %
- oldtotallines) * oldwidth + j];
- }
- }
-
- Con_ClearNotify ();
- }
-
- con.current = con.totallines - 1;
- con.display = con.current;
-}
-
-
-/*
-================
-Con_Init
-================
-*/
-void Con_Init (void)
-{
- con.linewidth = -1;
-
- Con_CheckResize ();
-
- Com_Printf ("Console initialized.\n");
-
-//
-// register our commands
-//
- con_notifytime = Cvar_Get ("con_notifytime", "3", 0);
-
- Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
- Cmd_AddCommand ("togglechat", Con_ToggleChat_f);
- Cmd_AddCommand ("messagemode", Con_MessageMode_f);
- Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
- Cmd_AddCommand ("clear", Con_Clear_f);
- Cmd_AddCommand ("condump", Con_Dump_f);
- con.initialized = true;
-}
-
-
-/*
-===============
-Con_Linefeed
-===============
-*/
-void Con_Linefeed (void)
-{
- con.x = 0;
- if (con.display == con.current)
- con.display++;
- con.current++;
- memset (&con.text[(con.current%con.totallines)*con.linewidth]
- , ' ', con.linewidth);
-}
-
-/*
-================
-Con_Print
-
-Handles cursor positioning, line wrapping, etc
-All console printing must go through this in order to be logged to disk
-If no console is visible, the text will appear at the top of the game window
-================
-*/
-void Con_Print (char *txt)
-{
- int y;
- int c, l;
- static int cr;
- int mask;
-
- if (!con.initialized)
- return;
-
- if (txt[0] == 1 || txt[0] == 2)
- {
- mask = 128; // go to colored text
- txt++;
- }
- else
- mask = 0;
-
-
- while ( (c = *txt) )
- {
- // count word length
- for (l=0 ; l< con.linewidth ; l++)
- if ( txt[l] <= ' ')
- break;
-
- // word wrap
- if (l != con.linewidth && (con.x + l > con.linewidth) )
- con.x = 0;
-
- txt++;
-
- if (cr)
- {
- con.current--;
- cr = false;
- }
-
-
- if (!con.x)
- {
- Con_Linefeed ();
- // mark time for transparent overlay
- if (con.current >= 0)
- con.times[con.current % NUM_CON_TIMES] = cls.realtime;
- }
-
- switch (c)
- {
- case '\n':
- con.x = 0;
- break;
-
- case '\r':
- con.x = 0;
- cr = 1;
- break;
-
- default: // display character and advance
- y = con.current % con.totallines;
- con.text[y*con.linewidth+con.x] = c | mask | con.ormask;
- con.x++;
- if (con.x >= con.linewidth)
- con.x = 0;
- break;
- }
-
- }
-}
-
-
-/*
-==============
-Con_CenteredPrint
-==============
-*/
-void Con_CenteredPrint (char *text)
-{
- int l;
- char buffer[1024];
-
- l = strlen(text);
- l = (con.linewidth-l)/2;
- if (l < 0)
- l = 0;
- memset (buffer, ' ', l);
- strcpy (buffer+l, text);
- strcat (buffer, "\n");
- Con_Print (buffer);
-}
-
-/*
-==============================================================================
-
-DRAWING
-
-==============================================================================
-*/
-
-
-/*
-================
-Con_DrawInput
-
-The input line scrolls horizontally if typing goes beyond the right edge
-================
-*/
-void Con_DrawInput (void)
-{
- int i;
- char *text;
-
- if (cls.key_dest == key_menu)
- return;
- if (cls.key_dest != key_console && cls.state == ca_active)
- return; // don't draw anything (always draw if not active)
-
- text = key_lines[edit_line];
-
-// add the cursor frame
- text[key_linepos] = 10+((int)(cls.realtime>>8)&1);
-
-// fill out remainder with spaces
- for (i=key_linepos+1 ; i< con.linewidth ; i++)
- text[i] = ' ';
-
-// prestep if horizontally scrolling
- if (key_linepos >= con.linewidth)
- text += 1 + key_linepos - con.linewidth;
-
-// draw it
- for (i=0 ; i<con.linewidth ; i++)
- re.DrawChar ( (i+1)<<3, con.vislines - 22, text[i]);
-
-// remove cursor
- key_lines[edit_line][key_linepos] = 0;
-}
-
-
-/*
-================
-Con_DrawNotify
-
-Draws the last few lines of output transparently over the game top
-================
-*/
-void Con_DrawNotify (void)
-{
- int x, v;
- char *text;
- int i;
- int time;
- char *s;
- int skip;
-
- v = 0;
- for (i= con.current-NUM_CON_TIMES+1 ; i<=con.current ; i++)
- {
- if (i < 0)
- continue;
- time = con.times[i % NUM_CON_TIMES];
- if (time == 0)
- continue;
- time = cls.realtime - time;
- if (time > con_notifytime->value*1000)
- continue;
- text = con.text + (i % con.totallines)*con.linewidth;
-
- for (x = 0 ; x < con.linewidth ; x++)
- re.DrawChar ( (x+1)<<3, v, text[x]);
-
- v += 8;
- }
-
-
- if (cls.key_dest == key_message)
- {
- if (chat_team)
- {
- DrawString (8, v, "say_team:");
- skip = 11;
- }
- else
- {
- DrawString (8, v, "say:");
- skip = 5;
- }
-
- s = chat_buffer;
- if (chat_bufferlen > (vid.width>>3)-(skip+1))
- s += chat_bufferlen - ((vid.width>>3)-(skip+1));
- x = 0;
- while(s[x])
- {
- re.DrawChar ( (x+skip)<<3, v, s[x]);
- x++;
- }
- re.DrawChar ( (x+skip)<<3, v, 10+((cls.realtime>>8)&1));
- v += 8;
- }
-
- if (v)
- {
- SCR_AddDirtyPoint (0,0);
- SCR_AddDirtyPoint (vid.width-1, v);
- }
-}
-
-/*
-================
-Con_DrawConsole
-
-Draws the console with the solid background
-================
-*/
-void Con_DrawConsole (float frac)
-{
- int i, j, x, y, n;
- int rows;
- char *text;
- int row;
- int lines;
- char version[64];
- char dlbar[1024];
-
- lines = vid.height * frac;
- if (lines <= 0)
- return;
-
- if (lines > vid.height)
- lines = vid.height;
-
-// draw the background
- re.DrawStretchPic (0, -vid.height+lines, vid.width, vid.height, "conback");
- SCR_AddDirtyPoint (0,0);
- SCR_AddDirtyPoint (vid.width-1,lines-1);
-
- Com_sprintf (version, sizeof(version), "v%4.2f", VERSION);
- for (x=0 ; x<5 ; x++)
- re.DrawChar (vid.width-44+x*8, lines-12, 128 + version[x] );
-
-// draw the text
- con.vislines = lines;
-
-/*
- rows = (lines-8)>>3; // rows of text to draw
-
- y = lines - 24;
-*/
- rows = (lines-22)>>3; // rows of text to draw
-
- y = lines - 30;
-
-// draw from the bottom up
- if (con.display != con.current)
- {
- // draw arrows to show the buffer is backscrolled
- for (x=0 ; x<con.linewidth ; x+=4)
- re.DrawChar ( (x+1)<<3, y, '^');
-
- y -= 8;
- rows--;
- }
-
- row = con.display;
- for (i=0 ; i<rows ; i++, y-=8, row--)
- {
- if (row < 0)
- break;
- if (con.current - row >= con.totallines)
- break; // past scrollback wrap point
-
- text = con.text + (row % con.totallines)*con.linewidth;
-
- for (x=0 ; x<con.linewidth ; x++)
- re.DrawChar ( (x+1)<<3, y, text[x]);
- }
-
-//ZOID
- // draw the download bar
- // figure out width
- if (cls.download) {
- if ((text = strrchr(cls.downloadname, '/')) != NULL)
- text++;
- else
- text = cls.downloadname;
-
- x = con.linewidth - ((con.linewidth * 7) / 40);
- y = x - strlen(text) - 8;
- i = con.linewidth/3;
- if (strlen(text) > i) {
- y = x - i - 11;
- strncpy(dlbar, text, i);
- dlbar[i] = 0;
- strcat(dlbar, "...");
- } else
- strcpy(dlbar, text);
- strcat(dlbar, ": ");
- i = strlen(dlbar);
- dlbar[i++] = 0x80;
- // where's the dot go?
- if (cls.downloadpercent == 0)
- n = 0;
- else
- n = y * cls.downloadpercent / 100;
-
- for (j = 0; j < y; j++)
- if (j == n)
- dlbar[i++] = 0x83;
- else
- dlbar[i++] = 0x81;
- dlbar[i++] = 0x82;
- dlbar[i] = 0;
-
- sprintf(dlbar + strlen(dlbar), " %02d%%", cls.downloadpercent);
-
- // draw it
- y = con.vislines-12;
- for (i = 0; i < strlen(dlbar); i++)
- re.DrawChar ( (i+1)<<3, y, dlbar[i]);
- }
-//ZOID
-
-// draw the input prompt, user text, and cursor if desired
- Con_DrawInput ();
-}
--- a/client/console.h
+++ /dev/null
@@ -1,38 +1,0 @@
-#define NUM_CON_TIMES 4
-
-#define CON_TEXTSIZE 32768
-typedef struct
-{
- qboolean initialized;
-
- char text[CON_TEXTSIZE];
- int current; // line where next message will be printed
- int x; // offset in current line for next print
- int display; // bottom of console displays this line
-
- int ormask; // high bit mask for colored characters
-
- int linewidth; // characters across screen
- int totallines; // total lines in console scrollback
-
- float cursorspeed;
-
- int vislines;
-
- float times[NUM_CON_TIMES]; // cls.realtime time the line was generated
- // for transparent notify lines
-} console_t;
-
-extern console_t con;
-
-void Con_DrawCharacter (int cx, int line, int num);
-
-void Con_CheckResize (void);
-void Con_Init (void);
-void Con_DrawConsole (float frac);
-void Con_Print (char *txt);
-void Con_CenteredPrint (char *text);
-void Con_Clear_f (void);
-void Con_DrawNotify (void);
-void Con_ClearNotify (void);
-void Con_ToggleConsole_f (void);
--- a/client/input.h
+++ /dev/null
@@ -1,24 +1,0 @@
-// input.h -- external (non-keyboard) input devices
-
-extern cvar_t *in_joystick;
-extern cvar_t *lookspring;
-extern cvar_t *lookstrafe;
-extern cvar_t *sensitivity;
-extern cvar_t *freelook;
-extern cvar_t *m_pitch;
-
-void IN_Init (void);
-
-void IN_Shutdown (void);
-
-void IN_Commands (void);
-// oportunity for devices to stick commands on the script buffer
-
-void IN_Frame (void);
-
-void IN_Move (usercmd_t *cmd);
-// add additional movement on top of the keyboard move cmd
-
-void IN_Activate (qboolean active);
-
-void IN_Grabm(int on);
--- a/client/keys.c
+++ /dev/null
@@ -1,927 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-/*
-
-key up events are sent even if in console mode
-
-*/
-
-
-#define MAXCMDLINE 256
-char key_lines[32][MAXCMDLINE];
-int key_linepos;
-int shift_down=false;
-int anykeydown;
-
-int edit_line=0;
-int history_line=0;
-
-int key_waiting;
-char *keybindings[256];
-qboolean consolekeys[256]; // if true, can't be rebound while in console
-qboolean menubound[256]; // if true, can't be rebound while in menu
-int keyshift[256]; // key to map to if shift held down in console
-int key_repeats[256]; // if > 1, it is autorepeating
-qboolean keydown[256];
-
-typedef struct
-{
- char *name;
- int keynum;
-} keyname_t;
-
-keyname_t keynames[] =
-{
- {"TAB", K_TAB},
- {"ENTER", K_ENTER},
- {"ESCAPE", K_ESCAPE},
- {"SPACE", K_SPACE},
- {"BACKSPACE", K_BACKSPACE},
- {"UPARROW", K_UPARROW},
- {"DOWNARROW", K_DOWNARROW},
- {"LEFTARROW", K_LEFTARROW},
- {"RIGHTARROW", K_RIGHTARROW},
-
- {"ALT", K_ALT},
- {"CTRL", K_CTRL},
- {"SHIFT", K_SHIFT},
-
- {"F1", K_F1},
- {"F2", K_F2},
- {"F3", K_F3},
- {"F4", K_F4},
- {"F5", K_F5},
- {"F6", K_F6},
- {"F7", K_F7},
- {"F8", K_F8},
- {"F9", K_F9},
- {"F10", K_F10},
- {"F11", K_F11},
- {"F12", K_F12},
-
- {"INS", K_INS},
- {"DEL", K_DEL},
- {"PGDN", K_PGDN},
- {"PGUP", K_PGUP},
- {"HOME", K_HOME},
- {"END", K_END},
-
- {"MOUSE1", K_MOUSE1},
- {"MOUSE2", K_MOUSE2},
- {"MOUSE3", K_MOUSE3},
-
- {"JOY1", K_JOY1},
- {"JOY2", K_JOY2},
- {"JOY3", K_JOY3},
- {"JOY4", K_JOY4},
-
- {"AUX1", K_AUX1},
- {"AUX2", K_AUX2},
- {"AUX3", K_AUX3},
- {"AUX4", K_AUX4},
- {"AUX5", K_AUX5},
- {"AUX6", K_AUX6},
- {"AUX7", K_AUX7},
- {"AUX8", K_AUX8},
- {"AUX9", K_AUX9},
- {"AUX10", K_AUX10},
- {"AUX11", K_AUX11},
- {"AUX12", K_AUX12},
- {"AUX13", K_AUX13},
- {"AUX14", K_AUX14},
- {"AUX15", K_AUX15},
- {"AUX16", K_AUX16},
- {"AUX17", K_AUX17},
- {"AUX18", K_AUX18},
- {"AUX19", K_AUX19},
- {"AUX20", K_AUX20},
- {"AUX21", K_AUX21},
- {"AUX22", K_AUX22},
- {"AUX23", K_AUX23},
- {"AUX24", K_AUX24},
- {"AUX25", K_AUX25},
- {"AUX26", K_AUX26},
- {"AUX27", K_AUX27},
- {"AUX28", K_AUX28},
- {"AUX29", K_AUX29},
- {"AUX30", K_AUX30},
- {"AUX31", K_AUX31},
- {"AUX32", K_AUX32},
-
- {"KP_HOME", K_KP_HOME },
- {"KP_UPARROW", K_KP_UPARROW },
- {"KP_PGUP", K_KP_PGUP },
- {"KP_LEFTARROW", K_KP_LEFTARROW },
- {"KP_5", K_KP_5 },
- {"KP_RIGHTARROW", K_KP_RIGHTARROW },
- {"KP_END", K_KP_END },
- {"KP_DOWNARROW", K_KP_DOWNARROW },
- {"KP_PGDN", K_KP_PGDN },
- {"KP_ENTER", K_KP_ENTER },
- {"KP_INS", K_KP_INS },
- {"KP_DEL", K_KP_DEL },
- {"KP_SLASH", K_KP_SLASH },
- {"KP_MINUS", K_KP_MINUS },
- {"KP_PLUS", K_KP_PLUS },
-
- {"MWHEELUP", K_MWHEELUP },
- {"MWHEELDOWN", K_MWHEELDOWN },
-
- {"PAUSE", K_PAUSE},
-
- {"SEMICOLON", ';'}, // because a raw semicolon seperates commands
-
- {NULL,0}
-};
-
-/*
-==============================================================================
-
- LINE TYPING INTO THE CONSOLE
-
-==============================================================================
-*/
-
-void CompleteCommand (void)
-{
- char *cmd, *s;
-
- s = key_lines[edit_line]+1;
- if (*s == '\\' || *s == '/')
- s++;
-
- cmd = Cmd_CompleteCommand (s);
- if (!cmd)
- cmd = Cvar_CompleteVariable (s);
- if (cmd)
- {
- key_lines[edit_line][1] = '/';
- strcpy (key_lines[edit_line]+2, cmd);
- key_linepos = strlen(cmd)+2;
- key_lines[edit_line][key_linepos] = ' ';
- key_linepos++;
- key_lines[edit_line][key_linepos] = 0;
- return;
- }
-}
-
-/*
-====================
-Key_Console
-
-Interactive line editing and console scrollback
-====================
-*/
-void Key_Console (int key)
-{
-
- switch ( key )
- {
- case K_KP_SLASH:
- key = '/';
- break;
- case K_KP_MINUS:
- key = '-';
- break;
- case K_KP_PLUS:
- key = '+';
- break;
- case K_KP_HOME:
- key = '7';
- break;
- case K_KP_UPARROW:
- key = '8';
- break;
- case K_KP_PGUP:
- key = '9';
- break;
- case K_KP_LEFTARROW:
- key = '4';
- break;
- case K_KP_5:
- key = '5';
- break;
- case K_KP_RIGHTARROW:
- key = '6';
- break;
- case K_KP_END:
- key = '1';
- break;
- case K_KP_DOWNARROW:
- key = '2';
- break;
- case K_KP_PGDN:
- key = '3';
- break;
- case K_KP_INS:
- key = '0';
- break;
- case K_KP_DEL:
- key = '.';
- break;
- }
-
- if ( ( toupper( key ) == 'V' && keydown[K_CTRL] ) ||
- ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keydown[K_SHIFT] ) )
- {
- char *cbd;
-
- if ( ( cbd = Sys_GetClipboardData() ) != 0 )
- {
- int i;
-
- strtok( cbd, "\n\r\b" );
-
- i = strlen( cbd );
- if ( i + key_linepos >= MAXCMDLINE)
- i= MAXCMDLINE - key_linepos;
-
- if ( i > 0 )
- {
- cbd[i]=0;
- strcat( key_lines[edit_line], cbd );
- key_linepos += i;
- }
- free( cbd );
- }
-
- return;
- }
-
- if ( key == 'l' )
- {
- if ( keydown[K_CTRL] )
- {
- Cbuf_AddText ("clear\n");
- return;
- }
- }
-
- if ( key == K_ENTER || key == K_KP_ENTER )
- { // backslash text are commands, else chat
- if (key_lines[edit_line][1] == '\\' || key_lines[edit_line][1] == '/')
- Cbuf_AddText (key_lines[edit_line]+2); // skip the >
- else
- Cbuf_AddText (key_lines[edit_line]+1); // valid command
-
- Cbuf_AddText ("\n");
- Com_Printf ("%s\n",key_lines[edit_line]);
- edit_line = (edit_line + 1) & 31;
- history_line = edit_line;
- key_lines[edit_line][0] = ']';
- key_linepos = 1;
- if (cls.state == ca_disconnected)
- SCR_UpdateScreen (); // force an update, because the command
- // may take some time
- return;
- }
-
- if (key == K_TAB)
- { // command completion
- CompleteCommand ();
- return;
- }
-
- if ( ( key == K_BACKSPACE ) || ( key == K_LEFTARROW ) || ( key == K_KP_LEFTARROW ) || ( ( key == 'h' ) && ( keydown[K_CTRL] ) ) )
- {
- if (key_linepos > 1)
- key_linepos--;
- return;
- }
-
- if ( ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
- ( ( key == 'p' ) && keydown[K_CTRL] ) )
- {
- do
- {
- history_line = (history_line - 1) & 31;
- } while (history_line != edit_line
- && !key_lines[history_line][1]);
- if (history_line == edit_line)
- history_line = (edit_line+1)&31;
- strcpy(key_lines[edit_line], key_lines[history_line]);
- key_linepos = strlen(key_lines[edit_line]);
- return;
- }
-
- if ( ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ||
- ( ( key == 'n' ) && keydown[K_CTRL] ) )
- {
- if (history_line == edit_line) return;
- do
- {
- history_line = (history_line + 1) & 31;
- }
- while (history_line != edit_line
- && !key_lines[history_line][1]);
- if (history_line == edit_line)
- {
- key_lines[edit_line][0] = ']';
- key_linepos = 1;
- }
- else
- {
- strcpy(key_lines[edit_line], key_lines[history_line]);
- key_linepos = strlen(key_lines[edit_line]);
- }
- return;
- }
-
- if (key == K_PGUP || key == K_KP_PGUP )
- {
- con.display -= 2;
- return;
- }
-
- if (key == K_PGDN || key == K_KP_PGDN )
- {
- con.display += 2;
- if (con.display > con.current)
- con.display = con.current;
- return;
- }
-
- if (key == K_HOME || key == K_KP_HOME )
- {
- con.display = con.current - con.totallines + 10;
- return;
- }
-
- if (key == K_END || key == K_KP_END )
- {
- con.display = con.current;
- return;
- }
-
- if (key < 32 || key > 127)
- return; // non printable
-
- if (key_linepos < MAXCMDLINE-1)
- {
- key_lines[edit_line][key_linepos] = key;
- key_linepos++;
- key_lines[edit_line][key_linepos] = 0;
- }
-
-}
-
-//============================================================================
-
-qboolean chat_team;
-char chat_buffer[MAXCMDLINE];
-int chat_bufferlen = 0;
-
-void Key_Message (int key)
-{
-
- if ( key == K_ENTER || key == K_KP_ENTER )
- {
- if (chat_team)
- Cbuf_AddText ("say_team \"");
- else
- Cbuf_AddText ("say \"");
- Cbuf_AddText(chat_buffer);
- Cbuf_AddText("\"\n");
-
- cls.key_dest = key_game;
- chat_bufferlen = 0;
- chat_buffer[0] = 0;
- return;
- }
-
- if (key == K_ESCAPE)
- {
- cls.key_dest = key_game;
- chat_bufferlen = 0;
- chat_buffer[0] = 0;
- return;
- }
-
- if (key < 32 || key > 127)
- return; // non printable
-
- if (key == K_BACKSPACE)
- {
- if (chat_bufferlen)
- {
- chat_bufferlen--;
- chat_buffer[chat_bufferlen] = 0;
- }
- return;
- }
-
- if (chat_bufferlen == sizeof(chat_buffer)-1)
- return; // all full
-
- chat_buffer[chat_bufferlen++] = key;
- chat_buffer[chat_bufferlen] = 0;
-}
-
-//============================================================================
-
-
-/*
-===================
-Key_StringToKeynum
-
-Returns a key number to be used to index keybindings[] by looking at
-the given string. Single ascii characters return themselves, while
-the K_* names are matched up.
-===================
-*/
-int Key_StringToKeynum (char *str)
-{
- keyname_t *kn;
-
- if (!str || !str[0])
- return -1;
- if (!str[1])
- return str[0];
-
- for (kn=keynames ; kn->name ; kn++)
- {
- if (!cistrcmp(str,kn->name))
- return kn->keynum;
- }
- return -1;
-}
-
-/*
-===================
-Key_KeynumToString
-
-Returns a string (either a single ascii char, or a K_* name) for the
-given keynum.
-FIXME: handle quote special (general escape sequence?)
-===================
-*/
-char *Key_KeynumToString (int keynum)
-{
- keyname_t *kn;
- static char tinystr[2];
-
- if (keynum == -1)
- return "<KEY NOT FOUND>";
- if (keynum > 32 && keynum < 127)
- { // printable ascii
- tinystr[0] = keynum;
- tinystr[1] = 0;
- return tinystr;
- }
-
- for (kn=keynames ; kn->name ; kn++)
- if (keynum == kn->keynum)
- return kn->name;
-
- return "<UNKNOWN KEYNUM>";
-}
-
-
-/*
-===================
-Key_SetBinding
-===================
-*/
-void Key_SetBinding (int keynum, char *binding)
-{
- char *new;
- int l;
-
- if (keynum == -1)
- return;
-
-// free old bindings
- if (keybindings[keynum])
- {
- Z_Free (keybindings[keynum]);
- keybindings[keynum] = NULL;
- }
-
-// allocate memory for new binding
- l = strlen (binding);
- new = Z_Malloc (l+1);
- strcpy (new, binding);
- new[l] = 0;
- keybindings[keynum] = new;
-}
-
-/*
-===================
-Key_Unbind_f
-===================
-*/
-void Key_Unbind_f (void)
-{
- int b;
-
- if (Cmd_Argc() != 2)
- {
- Com_Printf ("unbind <key> : remove commands from a key\n");
- return;
- }
-
- b = Key_StringToKeynum (Cmd_Argv(1));
- if (b==-1)
- {
- Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
- return;
- }
-
- Key_SetBinding (b, "");
-}
-
-void Key_Unbindall_f (void)
-{
- int i;
-
- for (i=0 ; i<256 ; i++)
- if (keybindings[i])
- Key_SetBinding (i, "");
-}
-
-
-/*
-===================
-Key_Bind_f
-===================
-*/
-void Key_Bind_f (void)
-{
- int i, c, b;
- char cmd[1024];
-
- c = Cmd_Argc();
-
- if (c < 2)
- {
- Com_Printf ("bind <key> [command] : attach a command to a key\n");
- return;
- }
- b = Key_StringToKeynum (Cmd_Argv(1));
- if (b==-1)
- {
- Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
- return;
- }
-
- if (c == 2)
- {
- if (keybindings[b])
- Com_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] );
- else
- Com_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );
- return;
- }
-
-// copy the rest of the command line
- cmd[0] = 0; // start out with a null string
- for (i=2 ; i< c ; i++)
- {
- strcat (cmd, Cmd_Argv(i));
- if (i != (c-1))
- strcat (cmd, " ");
- }
-
- Key_SetBinding (b, cmd);
-}
-
-/*
-============
-Key_WriteBindings
-
-Writes lines containing "bind key value"
-============
-*/
-void Key_WriteBindings (FILE *f)
-{
- int i;
-
- for (i=0 ; i<256 ; i++)
- if (keybindings[i] && keybindings[i][0])
- fprintf (f, "bind %s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
-}
-
-
-/*
-============
-Key_Bindlist_f
-
-============
-*/
-void Key_Bindlist_f (void)
-{
- int i;
-
- for (i=0 ; i<256 ; i++)
- if (keybindings[i] && keybindings[i][0])
- Com_Printf ("%s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
-}
-
-
-/*
-===================
-Key_Init
-===================
-*/
-void Key_Init (void)
-{
- int i;
-
- for (i=0 ; i<32 ; i++)
- {
- key_lines[i][0] = ']';
- key_lines[i][1] = 0;
- }
- key_linepos = 1;
-
-//
-// init ascii characters in console mode
-//
- for (i=32 ; i<128 ; i++)
- consolekeys[i] = true;
- consolekeys[K_ENTER] = true;
- consolekeys[K_KP_ENTER] = true;
- consolekeys[K_TAB] = true;
- consolekeys[K_LEFTARROW] = true;
- consolekeys[K_KP_LEFTARROW] = true;
- consolekeys[K_RIGHTARROW] = true;
- consolekeys[K_KP_RIGHTARROW] = true;
- consolekeys[K_UPARROW] = true;
- consolekeys[K_KP_UPARROW] = true;
- consolekeys[K_DOWNARROW] = true;
- consolekeys[K_KP_DOWNARROW] = true;
- consolekeys[K_BACKSPACE] = true;
- consolekeys[K_HOME] = true;
- consolekeys[K_KP_HOME] = true;
- consolekeys[K_END] = true;
- consolekeys[K_KP_END] = true;
- consolekeys[K_PGUP] = true;
- consolekeys[K_KP_PGUP] = true;
- consolekeys[K_PGDN] = true;
- consolekeys[K_KP_PGDN] = true;
- consolekeys[K_SHIFT] = true;
- consolekeys[K_INS] = true;
- consolekeys[K_KP_INS] = true;
- consolekeys[K_KP_DEL] = true;
- consolekeys[K_KP_SLASH] = true;
- consolekeys[K_KP_PLUS] = true;
- consolekeys[K_KP_MINUS] = true;
- consolekeys[K_KP_5] = true;
-
- consolekeys['`'] = false;
- consolekeys['~'] = false;
-
- for (i=0 ; i<256 ; i++)
- keyshift[i] = i;
- for (i='a' ; i<='z' ; i++)
- keyshift[i] = i - 'a' + 'A';
- keyshift['1'] = '!';
- keyshift['2'] = '@';
- keyshift['3'] = '#';
- keyshift['4'] = '$';
- keyshift['5'] = '%';
- keyshift['6'] = '^';
- keyshift['7'] = '&';
- keyshift['8'] = '*';
- keyshift['9'] = '(';
- keyshift['0'] = ')';
- keyshift['-'] = '_';
- keyshift['='] = '+';
- keyshift[','] = '<';
- keyshift['.'] = '>';
- keyshift['/'] = '?';
- keyshift[';'] = ':';
- keyshift['\''] = '"';
- keyshift['['] = '{';
- keyshift[']'] = '}';
- keyshift['`'] = '~';
- keyshift['\\'] = '|';
-
- menubound[K_ESCAPE] = true;
- for (i=0 ; i<12 ; i++)
- menubound[K_F1+i] = true;
-
-//
-// register our functions
-//
- Cmd_AddCommand ("bind",Key_Bind_f);
- Cmd_AddCommand ("unbind",Key_Unbind_f);
- Cmd_AddCommand ("unbindall",Key_Unbindall_f);
- Cmd_AddCommand ("bindlist",Key_Bindlist_f);
-}
-
-/*
-===================
-Key_Event
-
-Called by the system between frames for both key up and key down events
-Should NOT be called during an interrupt!
-===================
-*/
-void Key_Event (int key, qboolean down, unsigned time)
-{
- char *kb;
- char cmd[1024];
-
- // hack for modal presses
- if (key_waiting == -1)
- {
- if (down)
- key_waiting = key;
- return;
- }
-
- // update auto-repeat status
- if (down)
- {
- key_repeats[key]++;
- if (key != K_BACKSPACE
- && key != K_PAUSE
- && key != K_PGUP
- && key != K_KP_PGUP
- && key != K_PGDN
- && key != K_KP_PGDN
- && key_repeats[key] > 1)
- return; // ignore most autorepeats
-
- if (key >= 200 && !keybindings[key])
- Com_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) );
- }
- else
- {
- key_repeats[key] = 0;
- }
-
- if (key == K_SHIFT)
- shift_down = down;
-
- // console key is hardcoded, so the user can never unbind it
- if (key == '`' || key == '~')
- {
- if (!down)
- return;
- Con_ToggleConsole_f ();
- return;
- }
-
- // any key during the attract mode will bring up the menu
- if (cl.attractloop && cls.key_dest != key_menu)
- key = K_ESCAPE;
-
- // menu key is hardcoded, so the user can never unbind it
- if (key == K_ESCAPE)
- {
- if (!down)
- return;
-
- if (cl.frame.playerstate.stats[STAT_LAYOUTS] && cls.key_dest == key_game)
- { // put away help computer / inventory
- Cbuf_AddText ("cmd putaway\n");
- return;
- }
- switch (cls.key_dest)
- {
- case key_message:
- Key_Message (key);
- break;
- case key_menu:
- M_Keydown (key);
- break;
- case key_game:
- case key_console:
- M_Menu_Main_f ();
- break;
- default:
- Com_Error (ERR_FATAL, "Bad cls.key_dest");
- }
- return;
- }
-
- // track if any key is down for BUTTON_ANY
- keydown[key] = down;
- if (down)
- {
- if (key_repeats[key] == 1)
- anykeydown++;
- }
- else
- {
- anykeydown--;
- if (anykeydown < 0)
- anykeydown = 0;
- }
-
-//
-// key up events only generate commands if the game key binding is
-// a button command (leading + sign). These will occur even in console mode,
-// to keep the character from continuing an action started before a console
-// switch. Button commands include the kenum as a parameter, so multiple
-// downs can be matched with ups
-//
- if (!down)
- {
- kb = keybindings[key];
- if (kb && kb[0] == '+')
- {
- Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
- Cbuf_AddText (cmd);
- }
- if (keyshift[key] != key)
- {
- kb = keybindings[keyshift[key]];
- if (kb && kb[0] == '+')
- {
- Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
- Cbuf_AddText (cmd);
- }
- }
- return;
- }
-
-//
-// if not a consolekey, send to the interpreter no matter what mode is
-//
- if ( (cls.key_dest == key_menu && menubound[key])
- || (cls.key_dest == key_console && !consolekeys[key])
- || (cls.key_dest == key_game && ( cls.state == ca_active || !consolekeys[key] ) ) )
- {
- kb = keybindings[key];
- if (kb)
- {
- if (kb[0] == '+')
- { // button commands add keynum and time as a parm
- Com_sprintf (cmd, sizeof(cmd), "%s %i %i\n", kb, key, time);
- Cbuf_AddText (cmd);
- }
- else
- {
- Cbuf_AddText (kb);
- Cbuf_AddText ("\n");
- }
- }
- return;
- }
-
- if (!down)
- return; // other systems only care about key down events
-
- if (shift_down)
- key = keyshift[key];
-
- switch (cls.key_dest)
- {
- case key_message:
- Key_Message (key);
- break;
- case key_menu:
- M_Keydown (key);
- break;
-
- case key_game:
- case key_console:
- Key_Console (key);
- break;
- default:
- Com_Error (ERR_FATAL, "Bad cls.key_dest");
- }
-}
-
-/*
-===================
-Key_ClearStates
-===================
-*/
-void Key_ClearStates (void)
-{
- int i;
-
- anykeydown = false;
-
- for (i=0 ; i<256 ; i++)
- {
- if ( keydown[i] || key_repeats[i] )
- Key_Event( i, false, 0 );
- keydown[i] = 0;
- key_repeats[i] = 0;
- }
-}
-
-
-/*
-===================
-Key_GetKey
-===================
-*/
-int Key_GetKey (void)
-{
- key_waiting = -1;
-
- while (key_waiting == -1)
- Sys_SendKeyEvents ();
-
- return key_waiting;
-}
-
--- a/client/keys.h
+++ /dev/null
@@ -1,125 +1,0 @@
-//
-// these are the key numbers that should be passed to Key_Event
-//
-#define K_TAB 9
-#define K_ENTER 13
-#define K_ESCAPE 27
-#define K_SPACE 32
-
-// normal keys should be passed as lowercased ascii
-
-#define K_BACKSPACE 127
-#define K_UPARROW 128
-#define K_DOWNARROW 129
-#define K_LEFTARROW 130
-#define K_RIGHTARROW 131
-
-#define K_ALT 132
-#define K_CTRL 133
-#define K_SHIFT 134
-#define K_F1 135
-#define K_F2 136
-#define K_F3 137
-#define K_F4 138
-#define K_F5 139
-#define K_F6 140
-#define K_F7 141
-#define K_F8 142
-#define K_F9 143
-#define K_F10 144
-#define K_F11 145
-#define K_F12 146
-#define K_INS 147
-#define K_DEL 148
-#define K_PGDN 149
-#define K_PGUP 150
-#define K_HOME 151
-#define K_END 152
-
-#define K_KP_HOME 160
-#define K_KP_UPARROW 161
-#define K_KP_PGUP 162
-#define K_KP_LEFTARROW 163
-#define K_KP_5 164
-#define K_KP_RIGHTARROW 165
-#define K_KP_END 166
-#define K_KP_DOWNARROW 167
-#define K_KP_PGDN 168
-#define K_KP_ENTER 169
-#define K_KP_INS 170
-#define K_KP_DEL 171
-#define K_KP_SLASH 172
-#define K_KP_MINUS 173
-#define K_KP_PLUS 174
-
-//
-// mouse buttons generate virtual keys
-//
-#define K_MOUSE1 200
-#define K_MOUSE3 201
-#define K_MOUSE2 202
-#define K_MWHEELUP 203
-#define K_MWHEELDOWN 204
-
-//
-// joystick buttons
-//
-#define K_JOY1 205
-#define K_JOY2 206
-#define K_JOY3 207
-#define K_JOY4 208
-
-//
-// aux keys are for multi-buttoned joysticks to generate so they can use
-// the normal binding process
-//
-#define K_AUX1 209
-#define K_AUX2 210
-#define K_AUX3 211
-#define K_AUX4 212
-#define K_AUX5 213
-#define K_AUX6 214
-#define K_AUX7 215
-#define K_AUX8 216
-#define K_AUX9 217
-#define K_AUX10 218
-#define K_AUX11 219
-#define K_AUX12 220
-#define K_AUX13 221
-#define K_AUX14 222
-#define K_AUX15 223
-#define K_AUX16 224
-#define K_AUX17 225
-#define K_AUX18 226
-#define K_AUX19 227
-#define K_AUX20 228
-#define K_AUX21 229
-#define K_AUX22 230
-#define K_AUX23 231
-#define K_AUX24 232
-#define K_AUX25 233
-#define K_AUX26 234
-#define K_AUX27 235
-#define K_AUX28 236
-#define K_AUX29 237
-#define K_AUX30 238
-#define K_AUX31 239
-#define K_AUX32 240
-
-#define K_PAUSE 255
-
-extern char *keybindings[256];
-extern int key_repeats[256];
-
-extern int anykeydown;
-extern char chat_buffer[];
-extern int chat_bufferlen;
-extern qboolean chat_team;
-
-void Key_Event (int key, qboolean down, unsigned time);
-void Key_Init (void);
-void Key_WriteBindings (FILE *f);
-void Key_SetBinding (int keynum, char *binding);
-void Key_ClearStates (void);
-int Key_GetKey (void);
-
--- a/client/menu.c
+++ /dev/null
@@ -1,3997 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <ctype.h>
-#include "../q_shared.h"
-
-static int m_main_cursor;
-
-#define NUM_CURSOR_FRAMES 15
-
-static char *menu_in_sound = "misc/menu1.wav";
-static char *menu_move_sound = "misc/menu2.wav";
-static char *menu_out_sound = "misc/menu3.wav";
-
-void M_Menu_Main_f (void);
- void M_Menu_Game_f (void);
- void M_Menu_LoadGame_f (void);
- void M_Menu_SaveGame_f (void);
- void M_Menu_PlayerConfig_f (void);
- void M_Menu_DownloadOptions_f (void);
- void M_Menu_Credits_f( void );
- void M_Menu_Multiplayer_f( void );
- void M_Menu_JoinServer_f (void);
- void M_Menu_AddressBook_f( void );
- void M_Menu_StartServer_f (void);
- void M_Menu_DMOptions_f (void);
- void M_Menu_Video_f (void);
- void M_Menu_Options_f (void);
- void M_Menu_Keys_f (void);
- void M_Menu_Quit_f (void);
-
- void M_Menu_Credits( void );
-
-qboolean m_entersound; // play after drawing a frame, so caching
- // won't disrupt the sound
-
-void (*m_drawfunc) (void);
-const char *(*m_keyfunc) (int key);
-
-//=============================================================================
-/* Support Routines */
-
-#define MAX_MENU_DEPTH 8
-
-
-typedef struct
-{
- void (*draw) (void);
- const char *(*key) (int k);
-} menulayer_t;
-
-menulayer_t m_layers[MAX_MENU_DEPTH];
-int m_menudepth;
-
-static void M_Banner( char *name )
-{
- int w, h;
-
- re.DrawGetPicSize (&w, &h, name );
- re.DrawPic( vid.width / 2 - w / 2, vid.height / 2 - 110, name );
-}
-
-void M_PushMenu ( void (*draw) (void), const char *(*key) (int k) )
-{
- int i;
-
- if (Cvar_VariableValue ("maxclients") == 1
- && Com_ServerState ())
- Cvar_Set ("paused", "1");
-
- // if this menu is already present, drop back to that level
- // to avoid stacking menus by hotkeys
- for (i=0 ; i<m_menudepth ; i++)
- if (m_layers[i].draw == draw &&
- m_layers[i].key == key)
- {
- m_menudepth = i;
- }
-
- if (i == m_menudepth)
- {
- if (m_menudepth >= MAX_MENU_DEPTH)
- Com_Error (ERR_FATAL, "M_PushMenu: MAX_MENU_DEPTH");
- m_layers[m_menudepth].draw = m_drawfunc;
- m_layers[m_menudepth].key = m_keyfunc;
- m_menudepth++;
- }
-
- m_drawfunc = draw;
- m_keyfunc = key;
-
- m_entersound = true;
-
- cls.key_dest = key_menu;
-}
-
-void M_ForceMenuOff (void)
-{
- m_drawfunc = 0;
- m_keyfunc = 0;
- cls.key_dest = key_game;
- m_menudepth = 0;
- Key_ClearStates ();
- Cvar_Set ("paused", "0");
- IN_Grabm (1);
-}
-
-void M_PopMenu (void)
-{
- S_StartLocalSound( menu_out_sound );
- if (m_menudepth < 1)
- Com_Error (ERR_FATAL, "M_PopMenu: depth < 1");
- m_menudepth--;
-
- m_drawfunc = m_layers[m_menudepth].draw;
- m_keyfunc = m_layers[m_menudepth].key;
-
- if (!m_menudepth)
- M_ForceMenuOff ();
-}
-
-
-const char *Default_MenuKey( menuframework_s *m, int key )
-{
- const char *sound = NULL;
- menucommon_s *item;
-
- if ( m )
- {
- if ( ( item = Menu_ItemAtCursor( m ) ) != 0 )
- {
- if ( item->type == MTYPE_FIELD )
- {
- if ( Field_Key( ( menufield_s * ) item, key ) )
- return NULL;
- }
- }
- }
-
- switch ( key )
- {
- case K_ESCAPE:
- M_PopMenu();
- return menu_out_sound;
- case K_KP_UPARROW:
- case K_UPARROW:
- if ( m )
- {
- m->cursor--;
- Menu_AdjustCursor( m, -1 );
- sound = menu_move_sound;
- }
- break;
- case K_TAB:
- if ( m )
- {
- m->cursor++;
- Menu_AdjustCursor( m, 1 );
- sound = menu_move_sound;
- }
- break;
- case K_KP_DOWNARROW:
- case K_DOWNARROW:
- if ( m )
- {
- m->cursor++;
- Menu_AdjustCursor( m, 1 );
- sound = menu_move_sound;
- }
- break;
- case K_KP_LEFTARROW:
- case K_LEFTARROW:
- if ( m )
- {
- Menu_SlideItem( m, -1 );
- sound = menu_move_sound;
- }
- break;
- case K_KP_RIGHTARROW:
- case K_RIGHTARROW:
- if ( m )
- {
- Menu_SlideItem( m, 1 );
- sound = menu_move_sound;
- }
- break;
-
- case K_MOUSE1:
- case K_MOUSE2:
- case K_MOUSE3:
- case K_JOY1:
- case K_JOY2:
- case K_JOY3:
- case K_JOY4:
- case K_AUX1:
- case K_AUX2:
- case K_AUX3:
- case K_AUX4:
- case K_AUX5:
- case K_AUX6:
- case K_AUX7:
- case K_AUX8:
- case K_AUX9:
- case K_AUX10:
- case K_AUX11:
- case K_AUX12:
- case K_AUX13:
- case K_AUX14:
- case K_AUX15:
- case K_AUX16:
- case K_AUX17:
- case K_AUX18:
- case K_AUX19:
- case K_AUX20:
- case K_AUX21:
- case K_AUX22:
- case K_AUX23:
- case K_AUX24:
- case K_AUX25:
- case K_AUX26:
- case K_AUX27:
- case K_AUX28:
- case K_AUX29:
- case K_AUX30:
- case K_AUX31:
- case K_AUX32:
-
- case K_KP_ENTER:
- case K_ENTER:
- if ( m )
- Menu_SelectItem( m );
- sound = menu_move_sound;
- break;
- }
-
- return sound;
-}
-
-//=============================================================================
-
-/*
-================
-M_DrawCharacter
-
-Draws one solid graphics character
-cx and cy are in 320*240 coordinates, and will be centered on
-higher res screens.
-================
-*/
-void M_DrawCharacter (int cx, int cy, int num)
-{
- re.DrawChar ( cx + ((vid.width - 320)>>1), cy + ((vid.height - 240)>>1), num);
-}
-
-void M_Print (int cx, int cy, char *str)
-{
- while (*str)
- {
- M_DrawCharacter (cx, cy, (*str)+128);
- str++;
- cx += 8;
- }
-}
-
-void M_PrintWhite (int cx, int cy, char *str)
-{
- while (*str)
- {
- M_DrawCharacter (cx, cy, *str);
- str++;
- cx += 8;
- }
-}
-
-void M_DrawPic (int x, int y, char *pic)
-{
- re.DrawPic (x + ((vid.width - 320)>>1), y + ((vid.height - 240)>>1), pic);
-}
-
-
-/*
-=============
-M_DrawCursor
-
-Draws an animating cursor with the point at
-x,y. The pic will extend to the left of x,
-and both above and below y.
-=============
-*/
-void M_DrawCursor( int x, int y, int f )
-{
- char cursorname[80];
- static qboolean cached;
-
- if ( !cached )
- {
- int i;
-
- for ( i = 0; i < NUM_CURSOR_FRAMES; i++ )
- {
- Com_sprintf( cursorname, sizeof( cursorname ), "m_cursor%d", i );
-
- re.RegisterPic( cursorname );
- }
- cached = true;
- }
-
- Com_sprintf( cursorname, sizeof(cursorname), "m_cursor%d", f );
- re.DrawPic( x, y, cursorname );
-}
-
-void M_DrawTextBox (int x, int y, int width, int lines)
-{
- int cx, cy;
- int n;
-
- // draw left side
- cx = x;
- cy = y;
- M_DrawCharacter (cx, cy, 1);
- for (n = 0; n < lines; n++)
- {
- cy += 8;
- M_DrawCharacter (cx, cy, 4);
- }
- M_DrawCharacter (cx, cy+8, 7);
-
- // draw middle
- cx += 8;
- while (width > 0)
- {
- cy = y;
- M_DrawCharacter (cx, cy, 2);
- for (n = 0; n < lines; n++)
- {
- cy += 8;
- M_DrawCharacter (cx, cy, 5);
- }
- M_DrawCharacter (cx, cy+8, 8);
- width -= 1;
- cx += 8;
- }
-
- // draw right side
- cy = y;
- M_DrawCharacter (cx, cy, 3);
- for (n = 0; n < lines; n++)
- {
- cy += 8;
- M_DrawCharacter (cx, cy, 6);
- }
- M_DrawCharacter (cx, cy+8, 9);
-}
-
-
-/*
-=======================================================================
-
-MAIN MENU
-
-=======================================================================
-*/
-#define MAIN_ITEMS 5
-
-
-void M_Main_Draw (void)
-{
- int i;
- int w, h;
- int ystart;
- int xoffset;
- int widest = -1;
- int totalheight = 0;
- char litname[80];
- char *names[] =
- {
- "m_main_game",
- "m_main_multiplayer",
- "m_main_options",
- "m_main_video",
- "m_main_quit",
- 0
- };
-
- for ( i = 0; names[i] != 0; i++ )
- {
- re.DrawGetPicSize( &w, &h, names[i] );
-
- if ( w > widest )
- widest = w;
- totalheight += ( h + 12 );
- }
-
- ystart = ( vid.height / 2 - 110 );
- xoffset = ( vid.width - widest + 70 ) / 2;
-
- for ( i = 0; names[i] != 0; i++ )
- {
- if ( i != m_main_cursor )
- re.DrawPic( xoffset, ystart + i * 40 + 13, names[i] );
- }
- strcpy( litname, names[m_main_cursor] );
- strcat( litname, "_sel" );
- re.DrawPic( xoffset, ystart + m_main_cursor * 40 + 13, litname );
-
- M_DrawCursor( xoffset - 25, ystart + m_main_cursor * 40 + 11, (int)(cls.realtime / 100)%NUM_CURSOR_FRAMES );
-
- re.DrawGetPicSize( &w, &h, "m_main_plaque" );
- re.DrawPic( xoffset - 30 - w, ystart, "m_main_plaque" );
-
- re.DrawPic( xoffset - 30 - w, ystart + h + 5, "m_main_logo" );
-}
-
-
-const char *M_Main_Key (int key)
-{
- const char *sound = menu_move_sound;
-
- switch (key)
- {
- case K_ESCAPE:
- M_PopMenu ();
- break;
-
- case K_KP_DOWNARROW:
- case K_DOWNARROW:
- if (++m_main_cursor >= MAIN_ITEMS)
- m_main_cursor = 0;
- return sound;
-
- case K_KP_UPARROW:
- case K_UPARROW:
- if (--m_main_cursor < 0)
- m_main_cursor = MAIN_ITEMS - 1;
- return sound;
-
- case K_KP_ENTER:
- case K_ENTER:
- m_entersound = true;
-
- switch (m_main_cursor)
- {
- case 0:
- M_Menu_Game_f ();
- break;
-
- case 1:
- M_Menu_Multiplayer_f();
- break;
-
- case 2:
- M_Menu_Options_f ();
- break;
-
- case 3:
- M_Menu_Video_f ();
- break;
-
- case 4:
- M_Menu_Quit_f ();
- break;
- }
- }
-
- return NULL;
-}
-
-
-void M_Menu_Main_f (void)
-{
- IN_Grabm (0);
- M_PushMenu (M_Main_Draw, M_Main_Key);
-}
-
-/*
-=======================================================================
-
-MULTIPLAYER MENU
-
-=======================================================================
-*/
-static menuframework_s s_multiplayer_menu;
-static menuaction_s s_join_network_server_action;
-static menuaction_s s_start_network_server_action;
-static menuaction_s s_player_setup_action;
-
-static void Multiplayer_MenuDraw (void)
-{
- M_Banner( "m_banner_multiplayer" );
-
- Menu_AdjustCursor( &s_multiplayer_menu, 1 );
- Menu_Draw( &s_multiplayer_menu );
-}
-
-static void PlayerSetupFunc( void * )
-{
- M_Menu_PlayerConfig_f();
-}
-
-static void JoinNetworkServerFunc( void * )
-{
- M_Menu_JoinServer_f();
-}
-
-static void StartNetworkServerFunc( void * )
-{
- M_Menu_StartServer_f ();
-}
-
-void Multiplayer_MenuInit( void )
-{
- s_multiplayer_menu.x = vid.width * 0.50 - 64;
- s_multiplayer_menu.nitems = 0;
-
- s_join_network_server_action.generic.type = MTYPE_ACTION;
- s_join_network_server_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_join_network_server_action.generic.x = 0;
- s_join_network_server_action.generic.y = 0;
- s_join_network_server_action.generic.name = " join network server";
- s_join_network_server_action.generic.callback = JoinNetworkServerFunc;
-
- s_start_network_server_action.generic.type = MTYPE_ACTION;
- s_start_network_server_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_start_network_server_action.generic.x = 0;
- s_start_network_server_action.generic.y = 10;
- s_start_network_server_action.generic.name = " start network server";
- s_start_network_server_action.generic.callback = StartNetworkServerFunc;
-
- s_player_setup_action.generic.type = MTYPE_ACTION;
- s_player_setup_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_player_setup_action.generic.x = 0;
- s_player_setup_action.generic.y = 20;
- s_player_setup_action.generic.name = " player setup";
- s_player_setup_action.generic.callback = PlayerSetupFunc;
-
- Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_join_network_server_action );
- Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_start_network_server_action );
- Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_player_setup_action );
-
- Menu_SetStatusBar( &s_multiplayer_menu, NULL );
-
- Menu_Center( &s_multiplayer_menu );
-}
-
-const char *Multiplayer_MenuKey( int key )
-{
- return Default_MenuKey( &s_multiplayer_menu, key );
-}
-
-void M_Menu_Multiplayer_f( void )
-{
- Multiplayer_MenuInit();
- M_PushMenu( Multiplayer_MenuDraw, Multiplayer_MenuKey );
-}
-
-/*
-=======================================================================
-
-KEYS MENU
-
-=======================================================================
-*/
-char *bindnames[][2] =
-{
-{"+attack", "attack"},
-{"weapnext", "next weapon"},
-{"+forward", "walk forward"},
-{"+back", "backpedal"},
-{"+left", "turn left"},
-{"+right", "turn right"},
-{"+speed", "run"},
-{"+moveleft", "step left"},
-{"+moveright", "step right"},
-{"+strafe", "sidestep"},
-{"+lookup", "look up"},
-{"+lookdown", "look down"},
-{"centerview", "center view"},
-{"+mlook", "mouse look"},
-{"+klook", "keyboard look"},
-{"+moveup", "up / jump"},
-{"+movedown", "down / crouch"},
-
-{"inven", "inventory"},
-{"invuse", "use item"},
-{"invdrop", "drop item"},
-{"invprev", "prev item"},
-{"invnext", "next item"},
-
-{"cmd help", "help computer" },
-{ 0, 0 }
-};
-
-int keys_cursor;
-static int bind_grab;
-
-static menuframework_s s_keys_menu;
-static menuaction_s s_keys_attack_action;
-static menuaction_s s_keys_change_weapon_action;
-static menuaction_s s_keys_walk_forward_action;
-static menuaction_s s_keys_backpedal_action;
-static menuaction_s s_keys_turn_left_action;
-static menuaction_s s_keys_turn_right_action;
-static menuaction_s s_keys_run_action;
-static menuaction_s s_keys_step_left_action;
-static menuaction_s s_keys_step_right_action;
-static menuaction_s s_keys_sidestep_action;
-static menuaction_s s_keys_look_up_action;
-static menuaction_s s_keys_look_down_action;
-static menuaction_s s_keys_center_view_action;
-static menuaction_s s_keys_mouse_look_action;
-static menuaction_s s_keys_keyboard_look_action;
-static menuaction_s s_keys_move_up_action;
-static menuaction_s s_keys_move_down_action;
-static menuaction_s s_keys_inventory_action;
-static menuaction_s s_keys_inv_use_action;
-static menuaction_s s_keys_inv_drop_action;
-static menuaction_s s_keys_inv_prev_action;
-static menuaction_s s_keys_inv_next_action;
-
-static menuaction_s s_keys_help_computer_action;
-
-static void M_UnbindCommand (char *command)
-{
- int j;
- int l;
- char *b;
-
- l = strlen(command);
-
- for (j=0 ; j<256 ; j++)
- {
- b = keybindings[j];
- if (!b)
- continue;
- if (!strncmp (b, command, l) )
- Key_SetBinding (j, "");
- }
-}
-
-static void M_FindKeysForCommand (char *command, int *twokeys)
-{
- int count;
- int j;
- int l;
- char *b;
-
- twokeys[0] = twokeys[1] = -1;
- l = strlen(command);
- count = 0;
-
- for (j=0 ; j<256 ; j++)
- {
- b = keybindings[j];
- if (!b)
- continue;
- if (!strncmp (b, command, l) )
- {
- twokeys[count] = j;
- count++;
- if (count == 2)
- break;
- }
- }
-}
-
-static void KeyCursorDrawFunc( menuframework_s *menu )
-{
- if ( bind_grab )
- re.DrawChar( menu->x, menu->y + menu->cursor * 9, '=' );
- else
- re.DrawChar( menu->x, menu->y + menu->cursor * 9, 12 + ( ( int ) ( Sys_Milliseconds() / 250 ) & 1 ) );
-}
-
-static void DrawKeyBindingFunc( void *self )
-{
- int keys[2];
- menuaction_s *a = ( menuaction_s * ) self;
-
- M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys);
-
- if (keys[0] == -1)
- {
- Menu_DrawString( a->generic.x + a->generic.parent->x + 16, a->generic.y + a->generic.parent->y, "???" );
- }
- else
- {
- int x;
- const char *name;
-
- name = Key_KeynumToString (keys[0]);
-
- Menu_DrawString( a->generic.x + a->generic.parent->x + 16, a->generic.y + a->generic.parent->y, name );
-
- x = strlen(name) * 8;
-
- if (keys[1] != -1)
- {
- Menu_DrawString( a->generic.x + a->generic.parent->x + 24 + x, a->generic.y + a->generic.parent->y, "or" );
- Menu_DrawString( a->generic.x + a->generic.parent->x + 48 + x, a->generic.y + a->generic.parent->y, Key_KeynumToString (keys[1]) );
- }
- }
-}
-
-static void KeyBindingFunc( void *self )
-{
- menuaction_s *a = ( menuaction_s * ) self;
- int keys[2];
-
- M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys );
-
- if (keys[1] != -1)
- M_UnbindCommand( bindnames[a->generic.localdata[0]][0]);
-
- bind_grab = true;
-
- Menu_SetStatusBar( &s_keys_menu, "press a key or button for this action" );
-}
-
-static void Keys_MenuInit( void )
-{
- int y = 0;
- int i = 0;
-
- s_keys_menu.x = vid.width * 0.50;
- s_keys_menu.nitems = 0;
- s_keys_menu.cursordraw = KeyCursorDrawFunc;
-
- s_keys_attack_action.generic.type = MTYPE_ACTION;
- s_keys_attack_action.generic.flags = QMF_GRAYED;
- s_keys_attack_action.generic.x = 0;
- s_keys_attack_action.generic.y = y;
- s_keys_attack_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_attack_action.generic.localdata[0] = i;
- s_keys_attack_action.generic.name = bindnames[s_keys_attack_action.generic.localdata[0]][1];
-
- s_keys_change_weapon_action.generic.type = MTYPE_ACTION;
- s_keys_change_weapon_action.generic.flags = QMF_GRAYED;
- s_keys_change_weapon_action.generic.x = 0;
- s_keys_change_weapon_action.generic.y = y += 9;
- s_keys_change_weapon_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_change_weapon_action.generic.localdata[0] = ++i;
- s_keys_change_weapon_action.generic.name = bindnames[s_keys_change_weapon_action.generic.localdata[0]][1];
-
- s_keys_walk_forward_action.generic.type = MTYPE_ACTION;
- s_keys_walk_forward_action.generic.flags = QMF_GRAYED;
- s_keys_walk_forward_action.generic.x = 0;
- s_keys_walk_forward_action.generic.y = y += 9;
- s_keys_walk_forward_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_walk_forward_action.generic.localdata[0] = ++i;
- s_keys_walk_forward_action.generic.name = bindnames[s_keys_walk_forward_action.generic.localdata[0]][1];
-
- s_keys_backpedal_action.generic.type = MTYPE_ACTION;
- s_keys_backpedal_action.generic.flags = QMF_GRAYED;
- s_keys_backpedal_action.generic.x = 0;
- s_keys_backpedal_action.generic.y = y += 9;
- s_keys_backpedal_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_backpedal_action.generic.localdata[0] = ++i;
- s_keys_backpedal_action.generic.name = bindnames[s_keys_backpedal_action.generic.localdata[0]][1];
-
- s_keys_turn_left_action.generic.type = MTYPE_ACTION;
- s_keys_turn_left_action.generic.flags = QMF_GRAYED;
- s_keys_turn_left_action.generic.x = 0;
- s_keys_turn_left_action.generic.y = y += 9;
- s_keys_turn_left_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_turn_left_action.generic.localdata[0] = ++i;
- s_keys_turn_left_action.generic.name = bindnames[s_keys_turn_left_action.generic.localdata[0]][1];
-
- s_keys_turn_right_action.generic.type = MTYPE_ACTION;
- s_keys_turn_right_action.generic.flags = QMF_GRAYED;
- s_keys_turn_right_action.generic.x = 0;
- s_keys_turn_right_action.generic.y = y += 9;
- s_keys_turn_right_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_turn_right_action.generic.localdata[0] = ++i;
- s_keys_turn_right_action.generic.name = bindnames[s_keys_turn_right_action.generic.localdata[0]][1];
-
- s_keys_run_action.generic.type = MTYPE_ACTION;
- s_keys_run_action.generic.flags = QMF_GRAYED;
- s_keys_run_action.generic.x = 0;
- s_keys_run_action.generic.y = y += 9;
- s_keys_run_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_run_action.generic.localdata[0] = ++i;
- s_keys_run_action.generic.name = bindnames[s_keys_run_action.generic.localdata[0]][1];
-
- s_keys_step_left_action.generic.type = MTYPE_ACTION;
- s_keys_step_left_action.generic.flags = QMF_GRAYED;
- s_keys_step_left_action.generic.x = 0;
- s_keys_step_left_action.generic.y = y += 9;
- s_keys_step_left_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_step_left_action.generic.localdata[0] = ++i;
- s_keys_step_left_action.generic.name = bindnames[s_keys_step_left_action.generic.localdata[0]][1];
-
- s_keys_step_right_action.generic.type = MTYPE_ACTION;
- s_keys_step_right_action.generic.flags = QMF_GRAYED;
- s_keys_step_right_action.generic.x = 0;
- s_keys_step_right_action.generic.y = y += 9;
- s_keys_step_right_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_step_right_action.generic.localdata[0] = ++i;
- s_keys_step_right_action.generic.name = bindnames[s_keys_step_right_action.generic.localdata[0]][1];
-
- s_keys_sidestep_action.generic.type = MTYPE_ACTION;
- s_keys_sidestep_action.generic.flags = QMF_GRAYED;
- s_keys_sidestep_action.generic.x = 0;
- s_keys_sidestep_action.generic.y = y += 9;
- s_keys_sidestep_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_sidestep_action.generic.localdata[0] = ++i;
- s_keys_sidestep_action.generic.name = bindnames[s_keys_sidestep_action.generic.localdata[0]][1];
-
- s_keys_look_up_action.generic.type = MTYPE_ACTION;
- s_keys_look_up_action.generic.flags = QMF_GRAYED;
- s_keys_look_up_action.generic.x = 0;
- s_keys_look_up_action.generic.y = y += 9;
- s_keys_look_up_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_look_up_action.generic.localdata[0] = ++i;
- s_keys_look_up_action.generic.name = bindnames[s_keys_look_up_action.generic.localdata[0]][1];
-
- s_keys_look_down_action.generic.type = MTYPE_ACTION;
- s_keys_look_down_action.generic.flags = QMF_GRAYED;
- s_keys_look_down_action.generic.x = 0;
- s_keys_look_down_action.generic.y = y += 9;
- s_keys_look_down_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_look_down_action.generic.localdata[0] = ++i;
- s_keys_look_down_action.generic.name = bindnames[s_keys_look_down_action.generic.localdata[0]][1];
-
- s_keys_center_view_action.generic.type = MTYPE_ACTION;
- s_keys_center_view_action.generic.flags = QMF_GRAYED;
- s_keys_center_view_action.generic.x = 0;
- s_keys_center_view_action.generic.y = y += 9;
- s_keys_center_view_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_center_view_action.generic.localdata[0] = ++i;
- s_keys_center_view_action.generic.name = bindnames[s_keys_center_view_action.generic.localdata[0]][1];
-
- s_keys_mouse_look_action.generic.type = MTYPE_ACTION;
- s_keys_mouse_look_action.generic.flags = QMF_GRAYED;
- s_keys_mouse_look_action.generic.x = 0;
- s_keys_mouse_look_action.generic.y = y += 9;
- s_keys_mouse_look_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_mouse_look_action.generic.localdata[0] = ++i;
- s_keys_mouse_look_action.generic.name = bindnames[s_keys_mouse_look_action.generic.localdata[0]][1];
-
- s_keys_keyboard_look_action.generic.type = MTYPE_ACTION;
- s_keys_keyboard_look_action.generic.flags = QMF_GRAYED;
- s_keys_keyboard_look_action.generic.x = 0;
- s_keys_keyboard_look_action.generic.y = y += 9;
- s_keys_keyboard_look_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_keyboard_look_action.generic.localdata[0] = ++i;
- s_keys_keyboard_look_action.generic.name = bindnames[s_keys_keyboard_look_action.generic.localdata[0]][1];
-
- s_keys_move_up_action.generic.type = MTYPE_ACTION;
- s_keys_move_up_action.generic.flags = QMF_GRAYED;
- s_keys_move_up_action.generic.x = 0;
- s_keys_move_up_action.generic.y = y += 9;
- s_keys_move_up_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_move_up_action.generic.localdata[0] = ++i;
- s_keys_move_up_action.generic.name = bindnames[s_keys_move_up_action.generic.localdata[0]][1];
-
- s_keys_move_down_action.generic.type = MTYPE_ACTION;
- s_keys_move_down_action.generic.flags = QMF_GRAYED;
- s_keys_move_down_action.generic.x = 0;
- s_keys_move_down_action.generic.y = y += 9;
- s_keys_move_down_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_move_down_action.generic.localdata[0] = ++i;
- s_keys_move_down_action.generic.name = bindnames[s_keys_move_down_action.generic.localdata[0]][1];
-
- s_keys_inventory_action.generic.type = MTYPE_ACTION;
- s_keys_inventory_action.generic.flags = QMF_GRAYED;
- s_keys_inventory_action.generic.x = 0;
- s_keys_inventory_action.generic.y = y += 9;
- s_keys_inventory_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_inventory_action.generic.localdata[0] = ++i;
- s_keys_inventory_action.generic.name = bindnames[s_keys_inventory_action.generic.localdata[0]][1];
-
- s_keys_inv_use_action.generic.type = MTYPE_ACTION;
- s_keys_inv_use_action.generic.flags = QMF_GRAYED;
- s_keys_inv_use_action.generic.x = 0;
- s_keys_inv_use_action.generic.y = y += 9;
- s_keys_inv_use_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_inv_use_action.generic.localdata[0] = ++i;
- s_keys_inv_use_action.generic.name = bindnames[s_keys_inv_use_action.generic.localdata[0]][1];
-
- s_keys_inv_drop_action.generic.type = MTYPE_ACTION;
- s_keys_inv_drop_action.generic.flags = QMF_GRAYED;
- s_keys_inv_drop_action.generic.x = 0;
- s_keys_inv_drop_action.generic.y = y += 9;
- s_keys_inv_drop_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_inv_drop_action.generic.localdata[0] = ++i;
- s_keys_inv_drop_action.generic.name = bindnames[s_keys_inv_drop_action.generic.localdata[0]][1];
-
- s_keys_inv_prev_action.generic.type = MTYPE_ACTION;
- s_keys_inv_prev_action.generic.flags = QMF_GRAYED;
- s_keys_inv_prev_action.generic.x = 0;
- s_keys_inv_prev_action.generic.y = y += 9;
- s_keys_inv_prev_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_inv_prev_action.generic.localdata[0] = ++i;
- s_keys_inv_prev_action.generic.name = bindnames[s_keys_inv_prev_action.generic.localdata[0]][1];
-
- s_keys_inv_next_action.generic.type = MTYPE_ACTION;
- s_keys_inv_next_action.generic.flags = QMF_GRAYED;
- s_keys_inv_next_action.generic.x = 0;
- s_keys_inv_next_action.generic.y = y += 9;
- s_keys_inv_next_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_inv_next_action.generic.localdata[0] = ++i;
- s_keys_inv_next_action.generic.name = bindnames[s_keys_inv_next_action.generic.localdata[0]][1];
-
- s_keys_help_computer_action.generic.type = MTYPE_ACTION;
- s_keys_help_computer_action.generic.flags = QMF_GRAYED;
- s_keys_help_computer_action.generic.x = 0;
- s_keys_help_computer_action.generic.y = y += 9;
- s_keys_help_computer_action.generic.ownerdraw = DrawKeyBindingFunc;
- s_keys_help_computer_action.generic.localdata[0] = ++i;
- s_keys_help_computer_action.generic.name = bindnames[s_keys_help_computer_action.generic.localdata[0]][1];
-
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_attack_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_change_weapon_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_walk_forward_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_backpedal_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_turn_left_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_turn_right_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_run_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_step_left_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_step_right_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_sidestep_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_look_up_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_look_down_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_center_view_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_mouse_look_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_keyboard_look_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_move_up_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_move_down_action );
-
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inventory_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_use_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_drop_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_prev_action );
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_next_action );
-
- Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_help_computer_action );
-
- Menu_SetStatusBar( &s_keys_menu, "enter to change, backspace to clear" );
- Menu_Center( &s_keys_menu );
-}
-
-static void Keys_MenuDraw (void)
-{
- Menu_AdjustCursor( &s_keys_menu, 1 );
- Menu_Draw( &s_keys_menu );
-}
-
-static const char *Keys_MenuKey( int key )
-{
- menuaction_s *item = ( menuaction_s * ) Menu_ItemAtCursor( &s_keys_menu );
-
- if ( bind_grab )
- {
- if ( key != K_ESCAPE && key != '`' )
- {
- char cmd[1024];
-
- Com_sprintf (cmd, sizeof(cmd), "bind \"%s\" \"%s\"\n", Key_KeynumToString(key), bindnames[item->generic.localdata[0]][0]);
- Cbuf_InsertText (cmd);
- }
-
- Menu_SetStatusBar( &s_keys_menu, "enter to change, backspace to clear" );
- bind_grab = false;
- return menu_out_sound;
- }
-
- switch ( key )
- {
- case K_KP_ENTER:
- case K_ENTER:
- KeyBindingFunc( item );
- return menu_in_sound;
- case K_BACKSPACE: // delete bindings
- case K_DEL: // delete bindings
- case K_KP_DEL:
- M_UnbindCommand( bindnames[item->generic.localdata[0]][0] );
- return menu_out_sound;
- default:
- return Default_MenuKey( &s_keys_menu, key );
- }
-}
-
-void M_Menu_Keys_f (void)
-{
- Keys_MenuInit();
- M_PushMenu( Keys_MenuDraw, Keys_MenuKey );
-}
-
-
-/*
-=======================================================================
-
-CONTROLS MENU
-
-=======================================================================
-*/
-static cvar_t *win_noalttab;
-
-static menuframework_s s_options_menu;
-static menuaction_s s_options_defaults_action;
-static menuaction_s s_options_customize_options_action;
-static menuslider_s s_options_sensitivity_slider;
-static menulist_s s_options_freelook_box;
-static menulist_s s_options_noalttab_box;
-static menulist_s s_options_alwaysrun_box;
-static menulist_s s_options_invertmouse_box;
-static menulist_s s_options_lookspring_box;
-static menulist_s s_options_lookstrafe_box;
-static menulist_s s_options_crosshair_box;
-static menuslider_s s_options_sfxvolume_slider;
-static menulist_s s_options_joystick_box;
-static menulist_s s_options_cdvolume_box;
-static menulist_s s_options_quality_list;
-static menulist_s s_options_compatibility_list;
-static menulist_s s_options_console_action;
-
-static void CrosshairFunc( void * )
-{
- Cvar_SetValue( "crosshair", s_options_crosshair_box.curvalue );
-}
-
-static void JoystickFunc( void * )
-{
- Cvar_SetValue( "in_joystick", s_options_joystick_box.curvalue );
-}
-
-static void CustomizeControlsFunc( void * )
-{
- M_Menu_Keys_f();
-}
-
-static void AlwaysRunFunc( void * )
-{
- Cvar_SetValue( "cl_run", s_options_alwaysrun_box.curvalue );
-}
-
-static void FreeLookFunc( void * )
-{
- Cvar_SetValue( "freelook", s_options_freelook_box.curvalue );
-}
-
-static void MouseSpeedFunc( void * )
-{
- Cvar_SetValue( "sensitivity", s_options_sensitivity_slider.curvalue / 2.0F );
-}
-
-static void NoAltTabFunc( void * )
-{
- Cvar_SetValue( "win_noalttab", s_options_noalttab_box.curvalue );
-}
-
-static float ClampCvar( float min, float max, float value )
-{
- if ( value < min ) return min;
- if ( value > max ) return max;
- return value;
-}
-
-static void ControlsSetMenuItemValues( void )
-{
- s_options_sfxvolume_slider.curvalue = Cvar_VariableValue( "s_volume" ) * 10;
- s_options_cdvolume_box.curvalue = !Cvar_VariableValue("cd_nocd");
- s_options_quality_list.curvalue = !Cvar_VariableValue( "s_loadas8bit" );
- s_options_sensitivity_slider.curvalue = ( sensitivity->value ) * 2;
-
- Cvar_SetValue( "cl_run", ClampCvar( 0, 1, cl_run->value ) );
- s_options_alwaysrun_box.curvalue = cl_run->value;
-
- s_options_invertmouse_box.curvalue = m_pitch->value < 0;
-
- Cvar_SetValue( "lookspring", ClampCvar( 0, 1, lookspring->value ) );
- s_options_lookspring_box.curvalue = lookspring->value;
-
- Cvar_SetValue( "lookstrafe", ClampCvar( 0, 1, lookstrafe->value ) );
- s_options_lookstrafe_box.curvalue = lookstrafe->value;
-
- Cvar_SetValue( "freelook", ClampCvar( 0, 1, freelook->value ) );
- s_options_freelook_box.curvalue = freelook->value;
-
- Cvar_SetValue( "crosshair", ClampCvar( 0, 3, crosshair->value ) );
- s_options_crosshair_box.curvalue = crosshair->value;
-
- Cvar_SetValue( "in_joystick", ClampCvar( 0, 1, in_joystick->value ) );
- s_options_joystick_box.curvalue = in_joystick->value;
-
- s_options_noalttab_box.curvalue = win_noalttab->value;
-}
-
-static void ControlsResetDefaultsFunc( void * )
-{
- Cbuf_AddText ("exec default.cfg\n");
- Cbuf_Execute();
-
- ControlsSetMenuItemValues();
-}
-
-static void InvertMouseFunc( void * )
-{
- if ( s_options_invertmouse_box.curvalue == 0 )
- {
- Cvar_SetValue( "m_pitch", fabs( m_pitch->value ) );
- }
- else
- {
- Cvar_SetValue( "m_pitch", -fabs( m_pitch->value ) );
- }
-}
-
-static void LookspringFunc( void * )
-{
- Cvar_SetValue( "lookspring", s_options_lookspring_box.curvalue );
-}
-
-static void LookstrafeFunc( void * )
-{
- Cvar_SetValue( "lookstrafe", s_options_lookstrafe_box.curvalue );
-}
-
-static void UpdateVolumeFunc( void * )
-{
- Cvar_SetValue( "s_volume", s_options_sfxvolume_slider.curvalue / 10 );
-}
-
-static void UpdateCDVolumeFunc( void * )
-{
- Cvar_SetValue( "cd_nocd", !s_options_cdvolume_box.curvalue );
-}
-
-static void ConsoleFunc( void * )
-{
- /*
- ** the proper way to do this is probably to have ToggleConsole_f accept a parameter
- */
- extern void Key_ClearTyping( void );
-
- if ( cl.attractloop )
- {
- Cbuf_AddText ("killserver\n");
- return;
- }
-
- Key_ClearTyping ();
- Con_ClearNotify ();
-
- M_ForceMenuOff ();
- cls.key_dest = key_console;
-}
-
-static void UpdateSoundQualityFunc( void * )
-{
- if ( s_options_quality_list.curvalue )
- {
- Cvar_SetValue( "s_khz", 22 );
- Cvar_SetValue( "s_loadas8bit", false );
- }
- else
- {
- Cvar_SetValue( "s_khz", 11 );
- Cvar_SetValue( "s_loadas8bit", true );
- }
-
- Cvar_SetValue( "s_primary", s_options_compatibility_list.curvalue );
-
- M_DrawTextBox( 8, 120 - 48, 36, 3 );
- M_Print( 16 + 16, 120 - 48 + 8, "Restarting the sound system. This" );
- M_Print( 16 + 16, 120 - 48 + 16, "could take up to a minute, so" );
- M_Print( 16 + 16, 120 - 48 + 24, "please be patient." );
-
- // the text box won't show up unless we do a buffer swap
- re.EndFrame();
-
- CL_Snd_Restart_f();
-}
-
-void Options_MenuInit( void )
-{
- static const char *cd_music_items[] =
- {
- "disabled",
- "enabled",
- 0
- };
- static const char *quality_items[] =
- {
- "low", "high", 0
- };
-
- static const char *compatibility_items[] =
- {
- "max compatibility", "max performance", 0
- };
-
- static const char *yesno_names[] =
- {
- "no",
- "yes",
- 0
- };
-
- static const char *crosshair_names[] =
- {
- "none",
- "cross",
- "dot",
- "angle",
- 0
- };
-
- win_noalttab = Cvar_Get( "win_noalttab", "0", CVAR_ARCHIVE );
-
- /*
- ** configure controls menu and menu items
- */
- s_options_menu.x = vid.width / 2;
- s_options_menu.y = vid.height / 2 - 58;
- s_options_menu.nitems = 0;
-
- s_options_sfxvolume_slider.generic.type = MTYPE_SLIDER;
- s_options_sfxvolume_slider.generic.x = 0;
- s_options_sfxvolume_slider.generic.y = 0;
- s_options_sfxvolume_slider.generic.name = "effects volume";
- s_options_sfxvolume_slider.generic.callback = UpdateVolumeFunc;
- s_options_sfxvolume_slider.minvalue = 0;
- s_options_sfxvolume_slider.maxvalue = 10;
- s_options_sfxvolume_slider.curvalue = Cvar_VariableValue( "s_volume" ) * 10;
-
- s_options_cdvolume_box.generic.type = MTYPE_SPINCONTROL;
- s_options_cdvolume_box.generic.x = 0;
- s_options_cdvolume_box.generic.y = 10;
- s_options_cdvolume_box.generic.name = "CD music";
- s_options_cdvolume_box.generic.callback = UpdateCDVolumeFunc;
- s_options_cdvolume_box.itemnames = cd_music_items;
- s_options_cdvolume_box.curvalue = !Cvar_VariableValue("cd_nocd");
-
- s_options_quality_list.generic.type = MTYPE_SPINCONTROL;
- s_options_quality_list.generic.x = 0;
- s_options_quality_list.generic.y = 20;;
- s_options_quality_list.generic.name = "sound quality";
- s_options_quality_list.generic.callback = UpdateSoundQualityFunc;
- s_options_quality_list.itemnames = quality_items;
- s_options_quality_list.curvalue = !Cvar_VariableValue( "s_loadas8bit" );
-
- s_options_compatibility_list.generic.type = MTYPE_SPINCONTROL;
- s_options_compatibility_list.generic.x = 0;
- s_options_compatibility_list.generic.y = 30;
- s_options_compatibility_list.generic.name = "sound compatibility";
- s_options_compatibility_list.generic.callback = UpdateSoundQualityFunc;
- s_options_compatibility_list.itemnames = compatibility_items;
- s_options_compatibility_list.curvalue = Cvar_VariableValue( "s_primary" );
-
- s_options_sensitivity_slider.generic.type = MTYPE_SLIDER;
- s_options_sensitivity_slider.generic.x = 0;
- s_options_sensitivity_slider.generic.y = 50;
- s_options_sensitivity_slider.generic.name = "mouse speed";
- s_options_sensitivity_slider.generic.callback = MouseSpeedFunc;
- s_options_sensitivity_slider.minvalue = 2;
- s_options_sensitivity_slider.maxvalue = 22;
-
- s_options_alwaysrun_box.generic.type = MTYPE_SPINCONTROL;
- s_options_alwaysrun_box.generic.x = 0;
- s_options_alwaysrun_box.generic.y = 60;
- s_options_alwaysrun_box.generic.name = "always run";
- s_options_alwaysrun_box.generic.callback = AlwaysRunFunc;
- s_options_alwaysrun_box.itemnames = yesno_names;
-
- s_options_invertmouse_box.generic.type = MTYPE_SPINCONTROL;
- s_options_invertmouse_box.generic.x = 0;
- s_options_invertmouse_box.generic.y = 70;
- s_options_invertmouse_box.generic.name = "invert mouse";
- s_options_invertmouse_box.generic.callback = InvertMouseFunc;
- s_options_invertmouse_box.itemnames = yesno_names;
-
- s_options_lookspring_box.generic.type = MTYPE_SPINCONTROL;
- s_options_lookspring_box.generic.x = 0;
- s_options_lookspring_box.generic.y = 80;
- s_options_lookspring_box.generic.name = "lookspring";
- s_options_lookspring_box.generic.callback = LookspringFunc;
- s_options_lookspring_box.itemnames = yesno_names;
-
- s_options_lookstrafe_box.generic.type = MTYPE_SPINCONTROL;
- s_options_lookstrafe_box.generic.x = 0;
- s_options_lookstrafe_box.generic.y = 90;
- s_options_lookstrafe_box.generic.name = "lookstrafe";
- s_options_lookstrafe_box.generic.callback = LookstrafeFunc;
- s_options_lookstrafe_box.itemnames = yesno_names;
-
- s_options_freelook_box.generic.type = MTYPE_SPINCONTROL;
- s_options_freelook_box.generic.x = 0;
- s_options_freelook_box.generic.y = 100;
- s_options_freelook_box.generic.name = "free look";
- s_options_freelook_box.generic.callback = FreeLookFunc;
- s_options_freelook_box.itemnames = yesno_names;
-
- s_options_crosshair_box.generic.type = MTYPE_SPINCONTROL;
- s_options_crosshair_box.generic.x = 0;
- s_options_crosshair_box.generic.y = 110;
- s_options_crosshair_box.generic.name = "crosshair";
- s_options_crosshair_box.generic.callback = CrosshairFunc;
- s_options_crosshair_box.itemnames = crosshair_names;
-/*
- s_options_noalttab_box.generic.type = MTYPE_SPINCONTROL;
- s_options_noalttab_box.generic.x = 0;
- s_options_noalttab_box.generic.y = 110;
- s_options_noalttab_box.generic.name = "disable alt-tab";
- s_options_noalttab_box.generic.callback = NoAltTabFunc;
- s_options_noalttab_box.itemnames = yesno_names;
-*/
- s_options_joystick_box.generic.type = MTYPE_SPINCONTROL;
- s_options_joystick_box.generic.x = 0;
- s_options_joystick_box.generic.y = 120;
- s_options_joystick_box.generic.name = "use joystick";
- s_options_joystick_box.generic.callback = JoystickFunc;
- s_options_joystick_box.itemnames = yesno_names;
-
- s_options_customize_options_action.generic.type = MTYPE_ACTION;
- s_options_customize_options_action.generic.x = 0;
- s_options_customize_options_action.generic.y = 140;
- s_options_customize_options_action.generic.name = "customize controls";
- s_options_customize_options_action.generic.callback = CustomizeControlsFunc;
-
- s_options_defaults_action.generic.type = MTYPE_ACTION;
- s_options_defaults_action.generic.x = 0;
- s_options_defaults_action.generic.y = 150;
- s_options_defaults_action.generic.name = "reset defaults";
- s_options_defaults_action.generic.callback = ControlsResetDefaultsFunc;
-
- s_options_console_action.generic.type = MTYPE_ACTION;
- s_options_console_action.generic.x = 0;
- s_options_console_action.generic.y = 160;
- s_options_console_action.generic.name = "go to console";
- s_options_console_action.generic.callback = ConsoleFunc;
-
- ControlsSetMenuItemValues();
-
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_sfxvolume_slider );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_cdvolume_box );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_quality_list );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_compatibility_list );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_sensitivity_slider );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_alwaysrun_box );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_invertmouse_box );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_lookspring_box );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_lookstrafe_box );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_freelook_box );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_crosshair_box );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_joystick_box );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_customize_options_action );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_defaults_action );
- Menu_AddItem( &s_options_menu, ( void * ) &s_options_console_action );
-}
-
-void Options_MenuDraw (void)
-{
- M_Banner( "m_banner_options" );
- Menu_AdjustCursor( &s_options_menu, 1 );
- Menu_Draw( &s_options_menu );
-}
-
-const char *Options_MenuKey( int key )
-{
- return Default_MenuKey( &s_options_menu, key );
-}
-
-void M_Menu_Options_f (void)
-{
- Options_MenuInit();
- M_PushMenu ( Options_MenuDraw, Options_MenuKey );
-}
-
-/*
-=======================================================================
-
-VIDEO MENU
-
-=======================================================================
-*/
-
-void M_Menu_Video_f (void)
-{
- VID_MenuInit();
- M_PushMenu( VID_MenuDraw, VID_MenuKey );
-}
-
-/*
-=============================================================================
-
-END GAME MENU
-
-=============================================================================
-*/
-static int credits_start_time;
-static const char **credits;
-static char *creditsIndex[256];
-static char *creditsBuffer;
-static const char *idcredits[] =
-{
- "+QUAKE II BY ID SOFTWARE",
- "",
- "+PROGRAMMING",
- "John Carmack",
- "John Cash",
- "Brian Hook",
- "",
- "+ART",
- "Adrian Carmack",
- "Kevin Cloud",
- "Paul Steed",
- "",
- "+LEVEL DESIGN",
- "Tim Willits",
- "American McGee",
- "Christian Antkow",
- "Paul Jaquays",
- "Brandon James",
- "",
- "+BIZ",
- "Todd Hollenshead",
- "Barrett (Bear) Alexander",
- "Donna Jackson",
- "",
- "",
- "+SPECIAL THANKS",
- "Ben Donges for beta testing",
- "",
- "",
- "",
- "",
- "",
- "",
- "+ADDITIONAL SUPPORT",
- "",
- "+LINUX PORT AND CTF",
- "Dave \"Zoid\" Kirsch",
- "",
- "+CINEMATIC SEQUENCES",
- "Ending Cinematic by Blur Studio - ",
- "Venice, CA",
- "",
- "Environment models for Introduction",
- "Cinematic by Karl Dolgener",
- "",
- "Assistance with environment design",
- "by Cliff Iwai",
- "",
- "+SOUND EFFECTS AND MUSIC",
- "Sound Design by Soundelux Media Labs.",
- "Music Composed and Produced by",
- "Soundelux Media Labs. Special thanks",
- "to Bill Brown, Tom Ozanich, Brian",
- "Celano, Jeff Eisner, and The Soundelux",
- "Players.",
- "",
- "\"Level Music\" by Sonic Mayhem",
- "www.sonicmayhem.com",
- "",
- "\"Quake II Theme Song\"",
- "(C) 1997 Rob Zombie. All Rights",
- "Reserved.",
- "",
- "Track 10 (\"Climb\") by Jer Sypult",
- "",
- "Voice of computers by",
- "Carly Staehlin-Taylor",
- "",
- "+THANKS TO ACTIVISION",
- "+IN PARTICULAR:",
- "",
- "John Tam",
- "Steve Rosenthal",
- "Marty Stratton",
- "Henk Hartong",
- "",
- "Quake II(tm) (C)1997 Id Software, Inc.",
- "All Rights Reserved. Distributed by",
- "Activision, Inc. under license.",
- "Quake II(tm), the Id Software name,",
- "the \"Q II\"(tm) logo and id(tm)",
- "logo are trademarks of Id Software,",
- "Inc. Activision(R) is a registered",
- "trademark of Activision, Inc. All",
- "other trademarks and trade names are",
- "properties of their respective owners.",
- 0
-};
-
-static const char *xatcredits[] =
-{
- "+QUAKE II MISSION PACK: THE RECKONING",
- "+BY",
- "+XATRIX ENTERTAINMENT, INC.",
- "",
- "+DESIGN AND DIRECTION",
- "Drew Markham",
- "",
- "+PRODUCED BY",
- "Greg Goodrich",
- "",
- "+PROGRAMMING",
- "Rafael Paiz",
- "",
- "+LEVEL DESIGN / ADDITIONAL GAME DESIGN",
- "Alex Mayberry",
- "",
- "+LEVEL DESIGN",
- "Mal Blackwell",
- "Dan Koppel",
- "",
- "+ART DIRECTION",
- "Michael \"Maxx\" Kaufman",
- "",
- "+COMPUTER GRAPHICS SUPERVISOR AND",
- "+CHARACTER ANIMATION DIRECTION",
- "Barry Dempsey",
- "",
- "+SENIOR ANIMATOR AND MODELER",
- "Jason Hoover",
- "",
- "+CHARACTER ANIMATION AND",
- "+MOTION CAPTURE SPECIALIST",
- "Amit Doron",
- "",
- "+ART",
- "Claire Praderie-Markham",
- "Viktor Antonov",
- "Corky Lehmkuhl",
- "",
- "+INTRODUCTION ANIMATION",
- "Dominique Drozdz",
- "",
- "+ADDITIONAL LEVEL DESIGN",
- "Aaron Barber",
- "Rhett Baldwin",
- "",
- "+3D CHARACTER ANIMATION TOOLS",
- "Gerry Tyra, SA Technology",
- "",
- "+ADDITIONAL EDITOR TOOL PROGRAMMING",
- "Robert Duffy",
- "",
- "+ADDITIONAL PROGRAMMING",
- "Ryan Feltrin",
- "",
- "+PRODUCTION COORDINATOR",
- "Victoria Sylvester",
- "",
- "+SOUND DESIGN",
- "Gary Bradfield",
- "",
- "+MUSIC BY",
- "Sonic Mayhem",
- "",
- "",
- "",
- "+SPECIAL THANKS",
- "+TO",
- "+OUR FRIENDS AT ID SOFTWARE",
- "",
- "John Carmack",
- "John Cash",
- "Brian Hook",
- "Adrian Carmack",
- "Kevin Cloud",
- "Paul Steed",
- "Tim Willits",
- "Christian Antkow",
- "Paul Jaquays",
- "Brandon James",
- "Todd Hollenshead",
- "Barrett (Bear) Alexander",
- "Dave \"Zoid\" Kirsch",
- "Donna Jackson",
- "",
- "",
- "",
- "+THANKS TO ACTIVISION",
- "+IN PARTICULAR:",
- "",
- "Marty Stratton",
- "Henk \"The Original Ripper\" Hartong",
- "Kevin Kraff",
- "Jamey Gottlieb",
- "Chris Hepburn",
- "",
- "+AND THE GAME TESTERS",
- "",
- "Tim Vanlaw",
- "Doug Jacobs",
- "Steven Rosenthal",
- "David Baker",
- "Chris Campbell",
- "Aaron Casillas",
- "Steve Elwell",
- "Derek Johnstone",
- "Igor Krinitskiy",
- "Samantha Lee",
- "Michael Spann",
- "Chris Toft",
- "Juan Valdes",
- "",
- "+THANKS TO INTERGRAPH COMPUTER SYTEMS",
- "+IN PARTICULAR:",
- "",
- "Michael T. Nicolaou",
- "",
- "",
- "Quake II Mission Pack: The Reckoning",
- "(tm) (C)1998 Id Software, Inc. All",
- "Rights Reserved. Developed by Xatrix",
- "Entertainment, Inc. for Id Software,",
- "Inc. Distributed by Activision Inc.",
- "under license. Quake(R) is a",
- "registered trademark of Id Software,",
- "Inc. Quake II Mission Pack: The",
- "Reckoning(tm), Quake II(tm), the Id",
- "Software name, the \"Q II\"(tm) logo",
- "and id(tm) logo are trademarks of Id",
- "Software, Inc. Activision(R) is a",
- "registered trademark of Activision,",
- "Inc. Xatrix(R) is a registered",
- "trademark of Xatrix Entertainment,",
- "Inc. All other trademarks and trade",
- "names are properties of their",
- "respective owners.",
- 0
-};
-
-static const char *roguecredits[] =
-{
- "+QUAKE II MISSION PACK 2: GROUND ZERO",
- "+BY",
- "+ROGUE ENTERTAINMENT, INC.",
- "",
- "+PRODUCED BY",
- "Jim Molinets",
- "",
- "+PROGRAMMING",
- "Peter Mack",
- "Patrick Magruder",
- "",
- "+LEVEL DESIGN",
- "Jim Molinets",
- "Cameron Lamprecht",
- "Berenger Fish",
- "Robert Selitto",
- "Steve Tietze",
- "Steve Thoms",
- "",
- "+ART DIRECTION",
- "Rich Fleider",
- "",
- "+ART",
- "Rich Fleider",
- "Steve Maines",
- "Won Choi",
- "",
- "+ANIMATION SEQUENCES",
- "Creat Studios",
- "Steve Maines",
- "",
- "+ADDITIONAL LEVEL DESIGN",
- "Rich Fleider",
- "Steve Maines",
- "Peter Mack",
- "",
- "+SOUND",
- "James Grunke",
- "",
- "+GROUND ZERO THEME",
- "+AND",
- "+MUSIC BY",
- "Sonic Mayhem",
- "",
- "+VWEP MODELS",
- "Brent \"Hentai\" Dill",
- "",
- "",
- "",
- "+SPECIAL THANKS",
- "+TO",
- "+OUR FRIENDS AT ID SOFTWARE",
- "",
- "John Carmack",
- "John Cash",
- "Brian Hook",
- "Adrian Carmack",
- "Kevin Cloud",
- "Paul Steed",
- "Tim Willits",
- "Christian Antkow",
- "Paul Jaquays",
- "Brandon James",
- "Todd Hollenshead",
- "Barrett (Bear) Alexander",
- "Katherine Anna Kang",
- "Donna Jackson",
- "Dave \"Zoid\" Kirsch",
- "",
- "",
- "",
- "+THANKS TO ACTIVISION",
- "+IN PARTICULAR:",
- "",
- "Marty Stratton",
- "Henk Hartong",
- "Mitch Lasky",
- "Steve Rosenthal",
- "Steve Elwell",
- "",
- "+AND THE GAME TESTERS",
- "",
- "The Ranger Clan",
- "Dave \"Zoid\" Kirsch",
- "Nihilistic Software",
- "Robert Duffy",
- "",
- "And Countless Others",
- "",
- "",
- "",
- "Quake II Mission Pack 2: Ground Zero",
- "(tm) (C)1998 Id Software, Inc. All",
- "Rights Reserved. Developed by Rogue",
- "Entertainment, Inc. for Id Software,",
- "Inc. Distributed by Activision Inc.",
- "under license. Quake(R) is a",
- "registered trademark of Id Software,",
- "Inc. Quake II Mission Pack 2: Ground",
- "Zero(tm), Quake II(tm), the Id",
- "Software name, the \"Q II\"(tm) logo",
- "and id(tm) logo are trademarks of Id",
- "Software, Inc. Activision(R) is a",
- "registered trademark of Activision,",
- "Inc. Rogue(R) is a registered",
- "trademark of Rogue Entertainment,",
- "Inc. All other trademarks and trade",
- "names are properties of their",
- "respective owners.",
- 0
-};
-
-
-void M_Credits_MenuDraw( void )
-{
- int i, y;
-
- /*
- ** draw the credits
- */
- for ( i = 0, y = vid.height - ( ( cls.realtime - credits_start_time ) / 40.0F ); credits[i] && y < vid.height; y += 10, i++ )
- {
- int j, stringoffset;
- int bold;
-
- if ( y <= -8 )
- continue;
-
- if ( credits[i][0] == '+' )
- {
- bold = true;
- stringoffset = 1;
- }
- else
- {
- bold = false;
- stringoffset = 0;
- }
-
- for ( j = 0; credits[i][j+stringoffset]; j++ )
- {
- int x;
-
- x = ( vid.width - strlen( credits[i] ) * 8 - stringoffset * 8 ) / 2 + ( j + stringoffset ) * 8;
-
- if ( bold )
- re.DrawChar( x, y, credits[i][j+stringoffset] + 128 );
- else
- re.DrawChar( x, y, credits[i][j+stringoffset] );
- }
- }
-
- if ( y < 0 )
- credits_start_time = cls.realtime;
-}
-
-const char *M_Credits_Key( int key )
-{
- switch (key)
- {
- case K_ESCAPE:
- if (creditsBuffer)
- FS_FreeFile (creditsBuffer);
- M_PopMenu ();
- break;
- }
-
- return menu_out_sound;
-
-}
-
-extern int Developer_searchpath (int who);
-
-void M_Menu_Credits_f( void )
-{
- int n;
- int count;
- char *p;
- int isdeveloper;
-
- creditsBuffer = NULL;
- count = FS_LoadFile ("credits", &creditsBuffer);
- if (count != -1)
- {
- p = creditsBuffer;
- for (n = 0; n < 255; n++)
- {
- creditsIndex[n] = p;
- while (*p != '\r' && *p != '\n')
- {
- p++;
- if (--count == 0)
- break;
- }
- if (*p == '\r')
- {
- *p++ = 0;
- if (--count == 0)
- break;
- }
- *p++ = 0;
- if (--count == 0)
- break;
- }
- creditsIndex[++n] = 0;
- credits = creditsIndex;
- }
- else
- {
- isdeveloper = Developer_searchpath (1);
-
- if (isdeveloper == 1) // xatrix
- credits = xatcredits;
- else if (isdeveloper == 2) // ROGUE
- credits = roguecredits;
- else
- {
- credits = idcredits;
- }
-
- }
-
- credits_start_time = cls.realtime;
- M_PushMenu( M_Credits_MenuDraw, M_Credits_Key);
-}
-
-/*
-=============================================================================
-
-GAME MENU
-
-=============================================================================
-*/
-
-static int m_game_cursor;
-
-static menuframework_s s_game_menu;
-static menuaction_s s_easy_game_action;
-static menuaction_s s_medium_game_action;
-static menuaction_s s_hard_game_action;
-static menuaction_s s_load_game_action;
-static menuaction_s s_save_game_action;
-static menuaction_s s_credits_action;
-static menuseparator_s s_blankline;
-
-static void StartGame( void )
-{
- // disable updates and start the cinematic going
- cl.servercount = -1;
- M_ForceMenuOff ();
- Cvar_SetValue( "deathmatch", 0 );
- Cvar_SetValue( "coop", 0 );
-
- Cvar_SetValue( "gamerules", 0 ); //PGM
-
- Cbuf_AddText ("loading ; killserver ; wait ; newgame\n");
- cls.key_dest = key_game;
-}
-
-static void EasyGameFunc( void * )
-{
- Cvar_ForceSet( "skill", "0" );
- StartGame();
-}
-
-static void MediumGameFunc( void * )
-{
- Cvar_ForceSet( "skill", "1" );
- StartGame();
-}
-
-static void HardGameFunc( void * )
-{
- Cvar_ForceSet( "skill", "2" );
- StartGame();
-}
-
-static void LoadGameFunc( void * )
-{
- M_Menu_LoadGame_f ();
-}
-
-static void SaveGameFunc( void * )
-{
- M_Menu_SaveGame_f();
-}
-
-static void CreditsFunc( void * )
-{
- M_Menu_Credits_f();
-}
-
-void Game_MenuInit( void )
-{
- static const char *difficulty_names[] =
- {
- "easy",
- "medium",
- "hard",
- 0
- };
-
- s_game_menu.x = vid.width * 0.50;
- s_game_menu.nitems = 0;
-
- s_easy_game_action.generic.type = MTYPE_ACTION;
- s_easy_game_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_easy_game_action.generic.x = 0;
- s_easy_game_action.generic.y = 0;
- s_easy_game_action.generic.name = "easy";
- s_easy_game_action.generic.callback = EasyGameFunc;
-
- s_medium_game_action.generic.type = MTYPE_ACTION;
- s_medium_game_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_medium_game_action.generic.x = 0;
- s_medium_game_action.generic.y = 10;
- s_medium_game_action.generic.name = "medium";
- s_medium_game_action.generic.callback = MediumGameFunc;
-
- s_hard_game_action.generic.type = MTYPE_ACTION;
- s_hard_game_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_hard_game_action.generic.x = 0;
- s_hard_game_action.generic.y = 20;
- s_hard_game_action.generic.name = "hard";
- s_hard_game_action.generic.callback = HardGameFunc;
-
- s_blankline.generic.type = MTYPE_SEPARATOR;
-
- s_load_game_action.generic.type = MTYPE_ACTION;
- s_load_game_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_load_game_action.generic.x = 0;
- s_load_game_action.generic.y = 40;
- s_load_game_action.generic.name = "load game";
- s_load_game_action.generic.callback = LoadGameFunc;
-
- s_save_game_action.generic.type = MTYPE_ACTION;
- s_save_game_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_save_game_action.generic.x = 0;
- s_save_game_action.generic.y = 50;
- s_save_game_action.generic.name = "save game";
- s_save_game_action.generic.callback = SaveGameFunc;
-
- s_credits_action.generic.type = MTYPE_ACTION;
- s_credits_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_credits_action.generic.x = 0;
- s_credits_action.generic.y = 60;
- s_credits_action.generic.name = "credits";
- s_credits_action.generic.callback = CreditsFunc;
-
- Menu_AddItem( &s_game_menu, ( void * ) &s_easy_game_action );
- Menu_AddItem( &s_game_menu, ( void * ) &s_medium_game_action );
- Menu_AddItem( &s_game_menu, ( void * ) &s_hard_game_action );
- Menu_AddItem( &s_game_menu, ( void * ) &s_blankline );
- Menu_AddItem( &s_game_menu, ( void * ) &s_load_game_action );
- Menu_AddItem( &s_game_menu, ( void * ) &s_save_game_action );
- Menu_AddItem( &s_game_menu, ( void * ) &s_blankline );
- Menu_AddItem( &s_game_menu, ( void * ) &s_credits_action );
-
- Menu_Center( &s_game_menu );
-}
-
-void Game_MenuDraw( void )
-{
- M_Banner( "m_banner_game" );
- Menu_AdjustCursor( &s_game_menu, 1 );
- Menu_Draw( &s_game_menu );
-}
-
-const char *Game_MenuKey( int key )
-{
- return Default_MenuKey( &s_game_menu, key );
-}
-
-void M_Menu_Game_f (void)
-{
- Game_MenuInit();
- M_PushMenu( Game_MenuDraw, Game_MenuKey );
- m_game_cursor = 1;
-}
-
-/*
-=============================================================================
-
-LOADGAME MENU
-
-=============================================================================
-*/
-
-#define MAX_SAVEGAMES 15
-
-static menuframework_s s_savegame_menu;
-
-static menuframework_s s_loadgame_menu;
-static menuaction_s s_loadgame_actions[MAX_SAVEGAMES];
-
-char m_savestrings[MAX_SAVEGAMES][32];
-qboolean m_savevalid[MAX_SAVEGAMES];
-
-void Create_Savestrings (void)
-{
- int i;
- FILE *f;
- char name[MAX_OSPATH];
-
- for (i=0 ; i<MAX_SAVEGAMES ; i++)
- {
- Com_sprintf (name, sizeof(name), "%s/save/save%i/server.ssv", FS_Gamedir(), i);
- f = fopen (name, "rb");
- if (!f)
- {
- strcpy (m_savestrings[i], "<EMPTY>");
- m_savevalid[i] = false;
- }
- else
- {
- FS_Read (m_savestrings[i], sizeof(m_savestrings[i]), f);
- fclose (f);
- m_savevalid[i] = true;
- }
- }
-}
-
-void LoadGameCallback( void *self )
-{
- menuaction_s *a = ( menuaction_s * ) self;
-
- if ( m_savevalid[ a->generic.localdata[0] ] )
- Cbuf_AddText (va("load save%i\n", a->generic.localdata[0] ) );
- M_ForceMenuOff ();
-}
-
-void LoadGame_MenuInit( void )
-{
- int i;
-
- s_loadgame_menu.x = vid.width / 2 - 120;
- s_loadgame_menu.y = vid.height / 2 - 58;
- s_loadgame_menu.nitems = 0;
-
- Create_Savestrings();
-
- for ( i = 0; i < MAX_SAVEGAMES; i++ )
- {
- s_loadgame_actions[i].generic.name = m_savestrings[i];
- s_loadgame_actions[i].generic.flags = QMF_LEFT_JUSTIFY;
- s_loadgame_actions[i].generic.localdata[0] = i;
- s_loadgame_actions[i].generic.callback = LoadGameCallback;
-
- s_loadgame_actions[i].generic.x = 0;
- s_loadgame_actions[i].generic.y = ( i ) * 10;
- if (i>0) // separate from autosave
- s_loadgame_actions[i].generic.y += 10;
-
- s_loadgame_actions[i].generic.type = MTYPE_ACTION;
-
- Menu_AddItem( &s_loadgame_menu, &s_loadgame_actions[i] );
- }
-}
-
-void LoadGame_MenuDraw( void )
-{
- M_Banner( "m_banner_load_game" );
-// Menu_AdjustCursor( &s_loadgame_menu, 1 );
- Menu_Draw( &s_loadgame_menu );
-}
-
-const char *LoadGame_MenuKey( int key )
-{
- if ( key == K_ESCAPE || key == K_ENTER )
- {
- s_savegame_menu.cursor = s_loadgame_menu.cursor - 1;
- if ( s_savegame_menu.cursor < 0 )
- s_savegame_menu.cursor = 0;
- }
- return Default_MenuKey( &s_loadgame_menu, key );
-}
-
-void M_Menu_LoadGame_f (void)
-{
- LoadGame_MenuInit();
- M_PushMenu( LoadGame_MenuDraw, LoadGame_MenuKey );
-}
-
-
-/*
-=============================================================================
-
-SAVEGAME MENU
-
-=============================================================================
-*/
-static menuframework_s s_savegame_menu;
-static menuaction_s s_savegame_actions[MAX_SAVEGAMES];
-
-void SaveGameCallback( void *self )
-{
- menuaction_s *a = ( menuaction_s * ) self;
-
- Cbuf_AddText (va("save save%i\n", a->generic.localdata[0] ));
- M_ForceMenuOff ();
-}
-
-void SaveGame_MenuDraw( void )
-{
- M_Banner( "m_banner_save_game" );
- Menu_AdjustCursor( &s_savegame_menu, 1 );
- Menu_Draw( &s_savegame_menu );
-}
-
-void SaveGame_MenuInit( void )
-{
- int i;
-
- s_savegame_menu.x = vid.width / 2 - 120;
- s_savegame_menu.y = vid.height / 2 - 58;
- s_savegame_menu.nitems = 0;
-
- Create_Savestrings();
-
- // don't include the autosave slot
- for ( i = 0; i < MAX_SAVEGAMES-1; i++ )
- {
- s_savegame_actions[i].generic.name = m_savestrings[i+1];
- s_savegame_actions[i].generic.localdata[0] = i+1;
- s_savegame_actions[i].generic.flags = QMF_LEFT_JUSTIFY;
- s_savegame_actions[i].generic.callback = SaveGameCallback;
-
- s_savegame_actions[i].generic.x = 0;
- s_savegame_actions[i].generic.y = ( i ) * 10;
-
- s_savegame_actions[i].generic.type = MTYPE_ACTION;
-
- Menu_AddItem( &s_savegame_menu, &s_savegame_actions[i] );
- }
-}
-
-const char *SaveGame_MenuKey( int key )
-{
- if ( key == K_ENTER || key == K_ESCAPE )
- {
- s_loadgame_menu.cursor = s_savegame_menu.cursor - 1;
- if ( s_loadgame_menu.cursor < 0 )
- s_loadgame_menu.cursor = 0;
- }
- return Default_MenuKey( &s_savegame_menu, key );
-}
-
-void M_Menu_SaveGame_f (void)
-{
- if (!Com_ServerState())
- return; // not playing a game
-
- SaveGame_MenuInit();
- M_PushMenu( SaveGame_MenuDraw, SaveGame_MenuKey );
- Create_Savestrings ();
-}
-
-
-/*
-=============================================================================
-
-JOIN SERVER MENU
-
-=============================================================================
-*/
-#define MAX_LOCAL_SERVERS 8
-
-static menuframework_s s_joinserver_menu;
-static menuseparator_s s_joinserver_server_title;
-static menuaction_s s_joinserver_search_action;
-static menuaction_s s_joinserver_address_book_action;
-static menuaction_s s_joinserver_server_actions[MAX_LOCAL_SERVERS];
-
-int m_num_servers;
-#define NO_SERVER_STRING "<no server>"
-
-// user readable information
-static char local_server_names[MAX_LOCAL_SERVERS][80];
-
-// network address
-static netadr_t local_server_netadr[MAX_LOCAL_SERVERS];
-
-void M_AddToServerList (netadr_t adr, char *info)
-{
- int i;
-
- if (m_num_servers == MAX_LOCAL_SERVERS)
- return;
- while ( *info == ' ' )
- info++;
-
- // ignore if duplicated
- for (i=0 ; i<m_num_servers ; i++)
- if (!strcmp(info, local_server_names[i]))
- return;
-
- local_server_netadr[m_num_servers] = adr;
- strncpy (local_server_names[m_num_servers], info, sizeof(local_server_names[0])-1);
- m_num_servers++;
-}
-
-
-void JoinServerFunc( void *self )
-{
- char buffer[128];
- int index;
-
- index = ( menuaction_s * ) self - s_joinserver_server_actions;
-
- if ( cistrcmp( local_server_names[index], NO_SERVER_STRING ) == 0 )
- return;
-
- if (index >= m_num_servers)
- return;
-
- Com_sprintf (buffer, sizeof(buffer), "connect %s\n", NET_AdrToString (local_server_netadr[index]));
- Cbuf_AddText (buffer);
- M_ForceMenuOff ();
-}
-
-void AddressBookFunc( void * )
-{
- M_Menu_AddressBook_f();
-}
-
-void NullCursorDraw( void * )
-{
-}
-
-void SearchLocalGames( void )
-{
- int i;
-
- m_num_servers = 0;
- for (i=0 ; i<MAX_LOCAL_SERVERS ; i++)
- strcpy (local_server_names[i], NO_SERVER_STRING);
-
- M_DrawTextBox( 8, 120 - 48, 36, 3 );
- M_Print( 16 + 16, 120 - 48 + 8, "Searching for local servers, this" );
- M_Print( 16 + 16, 120 - 48 + 16, "could take up to a minute, so" );
- M_Print( 16 + 16, 120 - 48 + 24, "please be patient." );
-
- // the text box won't show up unless we do a buffer swap
- re.EndFrame();
-
- // send out info packets
- CL_PingServers_f();
-}
-
-void SearchLocalGamesFunc( void * )
-{
- SearchLocalGames();
-}
-
-void JoinServer_MenuInit( void )
-{
- int i;
-
- s_joinserver_menu.x = vid.width * 0.50 - 120;
- s_joinserver_menu.nitems = 0;
-
- s_joinserver_address_book_action.generic.type = MTYPE_ACTION;
- s_joinserver_address_book_action.generic.name = "address book";
- s_joinserver_address_book_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_joinserver_address_book_action.generic.x = 0;
- s_joinserver_address_book_action.generic.y = 0;
- s_joinserver_address_book_action.generic.callback = AddressBookFunc;
-
- s_joinserver_search_action.generic.type = MTYPE_ACTION;
- s_joinserver_search_action.generic.name = "refresh server list";
- s_joinserver_search_action.generic.flags = QMF_LEFT_JUSTIFY;
- s_joinserver_search_action.generic.x = 0;
- s_joinserver_search_action.generic.y = 10;
- s_joinserver_search_action.generic.callback = SearchLocalGamesFunc;
- s_joinserver_search_action.generic.statusbar = "search for servers";
-
- s_joinserver_server_title.generic.type = MTYPE_SEPARATOR;
- s_joinserver_server_title.generic.name = "connect to...";
- s_joinserver_server_title.generic.x = 80;
- s_joinserver_server_title.generic.y = 30;
-
- for ( i = 0; i < MAX_LOCAL_SERVERS; i++ )
- {
- s_joinserver_server_actions[i].generic.type = MTYPE_ACTION;
- strcpy (local_server_names[i], NO_SERVER_STRING);
- s_joinserver_server_actions[i].generic.name = local_server_names[i];
- s_joinserver_server_actions[i].generic.flags = QMF_LEFT_JUSTIFY;
- s_joinserver_server_actions[i].generic.x = 0;
- s_joinserver_server_actions[i].generic.y = 40 + i*10;
- s_joinserver_server_actions[i].generic.callback = JoinServerFunc;
- s_joinserver_server_actions[i].generic.statusbar = "press ENTER to connect";
- }
-
- Menu_AddItem( &s_joinserver_menu, &s_joinserver_address_book_action );
- Menu_AddItem( &s_joinserver_menu, &s_joinserver_server_title );
- Menu_AddItem( &s_joinserver_menu, &s_joinserver_search_action );
-
- for ( i = 0; i < 8; i++ )
- Menu_AddItem( &s_joinserver_menu, &s_joinserver_server_actions[i] );
-
- Menu_Center( &s_joinserver_menu );
-
- SearchLocalGames();
-}
-
-void JoinServer_MenuDraw(void)
-{
- M_Banner( "m_banner_join_server" );
- Menu_Draw( &s_joinserver_menu );
-}
-
-
-const char *JoinServer_MenuKey( int key )
-{
- return Default_MenuKey( &s_joinserver_menu, key );
-}
-
-void M_Menu_JoinServer_f (void)
-{
- JoinServer_MenuInit();
- M_PushMenu( JoinServer_MenuDraw, JoinServer_MenuKey );
-}
-
-
-/*
-=============================================================================
-
-START SERVER MENU
-
-=============================================================================
-*/
-static menuframework_s s_startserver_menu;
-static char **mapnames;
-static int nummaps;
-
-static menuaction_s s_startserver_start_action;
-static menuaction_s s_startserver_dmoptions_action;
-static menufield_s s_timelimit_field;
-static menufield_s s_fraglimit_field;
-static menufield_s s_maxclients_field;
-static menufield_s s_hostname_field;
-static menulist_s s_startmap_list;
-static menulist_s s_rules_box;
-
-void DMOptionsFunc( void * )
-{
- if (s_rules_box.curvalue == 1)
- return;
- M_Menu_DMOptions_f();
-}
-
-void RulesChangeFunc ( void * )
-{
- // DM
- if (s_rules_box.curvalue == 0)
- {
- s_maxclients_field.generic.statusbar = NULL;
- s_startserver_dmoptions_action.generic.statusbar = NULL;
- }
- else if(s_rules_box.curvalue == 1) // coop // PGM
- {
- s_maxclients_field.generic.statusbar = "4 maximum for cooperative";
- if (atoi(s_maxclients_field.buffer) > 4)
- strcpy( s_maxclients_field.buffer, "4" );
- s_startserver_dmoptions_action.generic.statusbar = "N/A for cooperative";
- }
-//=====
-//PGM
- // ROGUE GAMES
- else if(Developer_searchpath(2) == 2)
- {
- if (s_rules_box.curvalue == 2) // tag
- {
- s_maxclients_field.generic.statusbar = NULL;
- s_startserver_dmoptions_action.generic.statusbar = NULL;
- }
-/*
- else if(s_rules_box.curvalue == 3) // deathball
- {
- s_maxclients_field.generic.statusbar = NULL;
- s_startserver_dmoptions_action.generic.statusbar = NULL;
- }
-*/
- }
-//PGM
-//=====
-}
-
-void StartServerActionFunc( void * )
-{
- char startmap[1024];
- int timelimit;
- int fraglimit;
- int maxclients;
- char *spot;
-
- strcpy( startmap, strchr( mapnames[s_startmap_list.curvalue], '\n' ) + 1 );
-
- maxclients = atoi( s_maxclients_field.buffer );
- timelimit = atoi( s_timelimit_field.buffer );
- fraglimit = atoi( s_fraglimit_field.buffer );
-
- Cvar_SetValue( "maxclients", ClampCvar( 0, maxclients, maxclients ) );
- Cvar_SetValue ("timelimit", ClampCvar( 0, timelimit, timelimit ) );
- Cvar_SetValue ("fraglimit", ClampCvar( 0, fraglimit, fraglimit ) );
- Cvar_Set("hostname", s_hostname_field.buffer );
-// Cvar_SetValue ("deathmatch", !s_rules_box.curvalue );
-// Cvar_SetValue ("coop", s_rules_box.curvalue );
-
-//PGM
- if((s_rules_box.curvalue < 2) || (Developer_searchpath(2) != 2))
- {
- Cvar_SetValue ("deathmatch", !s_rules_box.curvalue );
- Cvar_SetValue ("coop", s_rules_box.curvalue );
- Cvar_SetValue ("gamerules", 0 );
- }
- else
- {
- Cvar_SetValue ("deathmatch", 1 ); // deathmatch is always true for rogue games, right?
- Cvar_SetValue ("coop", 0 ); // FIXME - this might need to depend on which game we're running
- Cvar_SetValue ("gamerules", s_rules_box.curvalue );
- }
-//PGM
-
- spot = NULL;
- if (s_rules_box.curvalue == 1) // PGM
- {
- if(cistrcmp(startmap, "bunk1") == 0)
- spot = "start";
- else if(cistrcmp(startmap, "mintro") == 0)
- spot = "start";
- else if(cistrcmp(startmap, "fact1") == 0)
- spot = "start";
- else if(cistrcmp(startmap, "power1") == 0)
- spot = "pstart";
- else if(cistrcmp(startmap, "biggun") == 0)
- spot = "bstart";
- else if(cistrcmp(startmap, "hangar1") == 0)
- spot = "unitstart";
- else if(cistrcmp(startmap, "city1") == 0)
- spot = "unitstart";
- else if(cistrcmp(startmap, "boss1") == 0)
- spot = "bosstart";
- }
-
- if (spot)
- {
- if (Com_ServerState())
- Cbuf_AddText ("disconnect\n");
- Cbuf_AddText (va("gamemap \"*%s$%s\"\n", startmap, spot));
- }
- else
- {
- Cbuf_AddText (va("map %s\n", startmap));
- }
-
- M_ForceMenuOff ();
-}
-
-void StartServer_MenuInit( void )
-{
- static const char *dm_coop_names[] =
- {
- "deathmatch",
- "cooperative",
- 0
- };
-//=======
-//PGM
- static const char *dm_coop_names_rogue[] =
- {
- "deathmatch",
- "cooperative",
- "tag",
-// "deathball",
- 0
- };
-//PGM
-//=======
- char *buffer;
- char mapsname[1024];
- char *s;
- int length;
- int i;
- FILE *fp;
-
- /*
- ** load the list of map names
- */
- Com_sprintf( mapsname, sizeof( mapsname ), "%s/maps.lst", FS_Gamedir() );
- if ( ( fp = fopen( mapsname, "rb" ) ) == 0 )
- {
- if ( ( length = FS_LoadFile( "maps.lst", ( void ** ) &buffer ) ) == -1 )
- Com_Error( ERR_DROP, "couldn't find maps.lst\n" );
- }
- else
- {
-#ifdef _WIN32
- length = filelength( fileno( fp ) );
-#else
- fseek(fp, 0, SEEK_END);
- length = ftell(fp);
- fseek(fp, 0, SEEK_SET);
-#endif
- buffer = malloc( length );
- fread( buffer, length, 1, fp );
- }
-
- s = buffer;
-
- i = 0;
- while ( i < length )
- {
- if ( s[i] == '\r' )
- nummaps++;
- i++;
- }
-
- if ( nummaps == 0 )
- Com_Error( ERR_DROP, "no maps in maps.lst\n" );
-
- mapnames = malloc( sizeof( char * ) * ( nummaps + 1 ) );
- memset( mapnames, 0, sizeof( char * ) * ( nummaps + 1 ) );
-
- s = buffer;
-
- for ( i = 0; i < nummaps; i++ )
- {
- char shortname[MAX_TOKEN_CHARS];
- char longname[MAX_TOKEN_CHARS];
- char scratch[200];
- int j, l;
-
- strcpy( shortname, COM_Parse( &s ) );
- l = strlen(shortname);
- for (j=0 ; j<l ; j++)
- shortname[j] = toupper(shortname[j]);
- strcpy( longname, COM_Parse( &s ) );
- Com_sprintf( scratch, sizeof( scratch ), "%s\n%s", longname, shortname );
-
- mapnames[i] = malloc( strlen( scratch ) + 1 );
- strcpy( mapnames[i], scratch );
- }
- mapnames[nummaps] = 0;
-
- if ( fp != 0 )
- {
- free( buffer );
- }
- else
- {
- FS_FreeFile( buffer );
- }
-
- /*
- ** initialize the menu stuff
- */
- s_startserver_menu.x = vid.width * 0.50;
- s_startserver_menu.nitems = 0;
-
- s_startmap_list.generic.type = MTYPE_SPINCONTROL;
- s_startmap_list.generic.x = 0;
- s_startmap_list.generic.y = 0;
- s_startmap_list.generic.name = "initial map";
- s_startmap_list.itemnames = mapnames;
-
- s_rules_box.generic.type = MTYPE_SPINCONTROL;
- s_rules_box.generic.x = 0;
- s_rules_box.generic.y = 20;
- s_rules_box.generic.name = "rules";
-
-//PGM - rogue games only available with rogue DLL.
- if(Developer_searchpath(2) == 2)
- s_rules_box.itemnames = dm_coop_names_rogue;
- else
- s_rules_box.itemnames = dm_coop_names;
-//PGM
-
- if (Cvar_VariableValue("coop"))
- s_rules_box.curvalue = 1;
- else
- s_rules_box.curvalue = 0;
- s_rules_box.generic.callback = RulesChangeFunc;
-
- s_timelimit_field.generic.type = MTYPE_FIELD;
- s_timelimit_field.generic.name = "time limit";
- s_timelimit_field.generic.flags = QMF_NUMBERSONLY;
- s_timelimit_field.generic.x = 0;
- s_timelimit_field.generic.y = 36;
- s_timelimit_field.generic.statusbar = "0 = no limit";
- s_timelimit_field.length = 3;
- s_timelimit_field.visible_length = 3;
- strcpy( s_timelimit_field.buffer, Cvar_VariableString("timelimit") );
-
- s_fraglimit_field.generic.type = MTYPE_FIELD;
- s_fraglimit_field.generic.name = "frag limit";
- s_fraglimit_field.generic.flags = QMF_NUMBERSONLY;
- s_fraglimit_field.generic.x = 0;
- s_fraglimit_field.generic.y = 54;
- s_fraglimit_field.generic.statusbar = "0 = no limit";
- s_fraglimit_field.length = 3;
- s_fraglimit_field.visible_length = 3;
- strcpy( s_fraglimit_field.buffer, Cvar_VariableString("fraglimit") );
-
- /*
- ** maxclients determines the maximum number of players that can join
- ** the game. If maxclients is only "1" then we should default the menu
- ** option to 8 players, otherwise use whatever its current value is.
- ** Clamping will be done when the server is actually started.
- */
- s_maxclients_field.generic.type = MTYPE_FIELD;
- s_maxclients_field.generic.name = "max players";
- s_maxclients_field.generic.flags = QMF_NUMBERSONLY;
- s_maxclients_field.generic.x = 0;
- s_maxclients_field.generic.y = 72;
- s_maxclients_field.generic.statusbar = NULL;
- s_maxclients_field.length = 3;
- s_maxclients_field.visible_length = 3;
- if ( Cvar_VariableValue( "maxclients" ) == 1 )
- strcpy( s_maxclients_field.buffer, "8" );
- else
- strcpy( s_maxclients_field.buffer, Cvar_VariableString("maxclients") );
-
- s_hostname_field.generic.type = MTYPE_FIELD;
- s_hostname_field.generic.name = "hostname";
- s_hostname_field.generic.flags = 0;
- s_hostname_field.generic.x = 0;
- s_hostname_field.generic.y = 90;
- s_hostname_field.generic.statusbar = NULL;
- s_hostname_field.length = 12;
- s_hostname_field.visible_length = 12;
- strcpy( s_hostname_field.buffer, Cvar_VariableString("hostname") );
-
- s_startserver_dmoptions_action.generic.type = MTYPE_ACTION;
- s_startserver_dmoptions_action.generic.name = " deathmatch flags";
- s_startserver_dmoptions_action.generic.flags= QMF_LEFT_JUSTIFY;
- s_startserver_dmoptions_action.generic.x = 24;
- s_startserver_dmoptions_action.generic.y = 108;
- s_startserver_dmoptions_action.generic.statusbar = NULL;
- s_startserver_dmoptions_action.generic.callback = DMOptionsFunc;
-
- s_startserver_start_action.generic.type = MTYPE_ACTION;
- s_startserver_start_action.generic.name = " begin";
- s_startserver_start_action.generic.flags= QMF_LEFT_JUSTIFY;
- s_startserver_start_action.generic.x = 24;
- s_startserver_start_action.generic.y = 128;
- s_startserver_start_action.generic.callback = StartServerActionFunc;
-
- Menu_AddItem( &s_startserver_menu, &s_startmap_list );
- Menu_AddItem( &s_startserver_menu, &s_rules_box );
- Menu_AddItem( &s_startserver_menu, &s_timelimit_field );
- Menu_AddItem( &s_startserver_menu, &s_fraglimit_field );
- Menu_AddItem( &s_startserver_menu, &s_maxclients_field );
- Menu_AddItem( &s_startserver_menu, &s_hostname_field );
- Menu_AddItem( &s_startserver_menu, &s_startserver_dmoptions_action );
- Menu_AddItem( &s_startserver_menu, &s_startserver_start_action );
-
- Menu_Center( &s_startserver_menu );
-
- // call this now to set proper inital state
- RulesChangeFunc ( NULL );
-}
-
-void StartServer_MenuDraw(void)
-{
- Menu_Draw( &s_startserver_menu );
-}
-
-const char *StartServer_MenuKey( int key )
-{
- if ( key == K_ESCAPE )
- {
- if ( mapnames )
- {
- int i;
-
- for ( i = 0; i < nummaps; i++ )
- free( mapnames[i] );
- free( mapnames );
- }
- mapnames = 0;
- nummaps = 0;
- }
-
- return Default_MenuKey( &s_startserver_menu, key );
-}
-
-void M_Menu_StartServer_f (void)
-{
- StartServer_MenuInit();
- M_PushMenu( StartServer_MenuDraw, StartServer_MenuKey );
-}
-
-/*
-=============================================================================
-
-DMOPTIONS BOOK MENU
-
-=============================================================================
-*/
-static char dmoptions_statusbar[128];
-
-static menuframework_s s_dmoptions_menu;
-
-static menulist_s s_friendlyfire_box;
-static menulist_s s_falls_box;
-static menulist_s s_weapons_stay_box;
-static menulist_s s_instant_powerups_box;
-static menulist_s s_powerups_box;
-static menulist_s s_health_box;
-static menulist_s s_spawn_farthest_box;
-static menulist_s s_teamplay_box;
-static menulist_s s_samelevel_box;
-static menulist_s s_force_respawn_box;
-static menulist_s s_armor_box;
-static menulist_s s_allow_exit_box;
-static menulist_s s_infinite_ammo_box;
-static menulist_s s_fixed_fov_box;
-static menulist_s s_quad_drop_box;
-
-//ROGUE
-static menulist_s s_no_mines_box;
-static menulist_s s_no_nukes_box;
-static menulist_s s_stack_double_box;
-static menulist_s s_no_spheres_box;
-//ROGUE
-
-static void DMFlagCallback( void *self )
-{
- menulist_s *f = ( menulist_s * ) self;
- int flags;
- int bit = 0;
-
- flags = Cvar_VariableValue( "dmflags" );
-
- if ( f == &s_friendlyfire_box )
- {
- if ( f->curvalue )
- flags &= ~DF_NO_FRIENDLY_FIRE;
- else
- flags |= DF_NO_FRIENDLY_FIRE;
- goto setvalue;
- }
- else if ( f == &s_falls_box )
- {
- if ( f->curvalue )
- flags &= ~DF_NO_FALLING;
- else
- flags |= DF_NO_FALLING;
- goto setvalue;
- }
- else if ( f == &s_weapons_stay_box )
- {
- bit = DF_WEAPONS_STAY;
- }
- else if ( f == &s_instant_powerups_box )
- {
- bit = DF_INSTANT_ITEMS;
- }
- else if ( f == &s_allow_exit_box )
- {
- bit = DF_ALLOW_EXIT;
- }
- else if ( f == &s_powerups_box )
- {
- if ( f->curvalue )
- flags &= ~DF_NO_ITEMS;
- else
- flags |= DF_NO_ITEMS;
- goto setvalue;
- }
- else if ( f == &s_health_box )
- {
- if ( f->curvalue )
- flags &= ~DF_NO_HEALTH;
- else
- flags |= DF_NO_HEALTH;
- goto setvalue;
- }
- else if ( f == &s_spawn_farthest_box )
- {
- bit = DF_SPAWN_FARTHEST;
- }
- else if ( f == &s_teamplay_box )
- {
- if ( f->curvalue == 1 )
- {
- flags |= DF_SKINTEAMS;
- flags &= ~DF_MODELTEAMS;
- }
- else if ( f->curvalue == 2 )
- {
- flags |= DF_MODELTEAMS;
- flags &= ~DF_SKINTEAMS;
- }
- else
- {
- flags &= ~( DF_MODELTEAMS | DF_SKINTEAMS );
- }
-
- goto setvalue;
- }
- else if ( f == &s_samelevel_box )
- {
- bit = DF_SAME_LEVEL;
- }
- else if ( f == &s_force_respawn_box )
- {
- bit = DF_FORCE_RESPAWN;
- }
- else if ( f == &s_armor_box )
- {
- if ( f->curvalue )
- flags &= ~DF_NO_ARMOR;
- else
- flags |= DF_NO_ARMOR;
- goto setvalue;
- }
- else if ( f == &s_infinite_ammo_box )
- {
- bit = DF_INFINITE_AMMO;
- }
- else if ( f == &s_fixed_fov_box )
- {
- bit = DF_FIXED_FOV;
- }
- else if ( f == &s_quad_drop_box )
- {
- bit = DF_QUAD_DROP;
- }
-
-//=======
-//ROGUE
- else if (Developer_searchpath(2) == 2)
- {
- if ( f == &s_no_mines_box)
- {
- bit = DF_NO_MINES;
- }
- else if ( f == &s_no_nukes_box)
- {
- bit = DF_NO_NUKES;
- }
- else if ( f == &s_stack_double_box)
- {
- bit = DF_NO_STACK_DOUBLE;
- }
- else if ( f == &s_no_spheres_box)
- {
- bit = DF_NO_SPHERES;
- }
- }
-//ROGUE
-//=======
-
- if ( f )
- {
- if ( f->curvalue == 0 )
- flags &= ~bit;
- else
- flags |= bit;
- }
-
-setvalue:
- Cvar_SetValue ("dmflags", flags);
-
- Com_sprintf( dmoptions_statusbar, sizeof( dmoptions_statusbar ), "dmflags = %d", flags );
-
-}
-
-void DMOptions_MenuInit( void )
-{
- static const char *yes_no_names[] =
- {
- "no", "yes", 0
- };
- static const char *teamplay_names[] =
- {
- "disabled", "by skin", "by model", 0
- };
- int dmflags = Cvar_VariableValue( "dmflags" );
- int y = 0;
-
- s_dmoptions_menu.x = vid.width * 0.50;
- s_dmoptions_menu.nitems = 0;
-
- s_falls_box.generic.type = MTYPE_SPINCONTROL;
- s_falls_box.generic.x = 0;
- s_falls_box.generic.y = y;
- s_falls_box.generic.name = "falling damage";
- s_falls_box.generic.callback = DMFlagCallback;
- s_falls_box.itemnames = yes_no_names;
- s_falls_box.curvalue = ( dmflags & DF_NO_FALLING ) == 0;
-
- s_weapons_stay_box.generic.type = MTYPE_SPINCONTROL;
- s_weapons_stay_box.generic.x = 0;
- s_weapons_stay_box.generic.y = y += 10;
- s_weapons_stay_box.generic.name = "weapons stay";
- s_weapons_stay_box.generic.callback = DMFlagCallback;
- s_weapons_stay_box.itemnames = yes_no_names;
- s_weapons_stay_box.curvalue = ( dmflags & DF_WEAPONS_STAY ) != 0;
-
- s_instant_powerups_box.generic.type = MTYPE_SPINCONTROL;
- s_instant_powerups_box.generic.x = 0;
- s_instant_powerups_box.generic.y = y += 10;
- s_instant_powerups_box.generic.name = "instant powerups";
- s_instant_powerups_box.generic.callback = DMFlagCallback;
- s_instant_powerups_box.itemnames = yes_no_names;
- s_instant_powerups_box.curvalue = ( dmflags & DF_INSTANT_ITEMS ) != 0;
-
- s_powerups_box.generic.type = MTYPE_SPINCONTROL;
- s_powerups_box.generic.x = 0;
- s_powerups_box.generic.y = y += 10;
- s_powerups_box.generic.name = "allow powerups";
- s_powerups_box.generic.callback = DMFlagCallback;
- s_powerups_box.itemnames = yes_no_names;
- s_powerups_box.curvalue = ( dmflags & DF_NO_ITEMS ) == 0;
-
- s_health_box.generic.type = MTYPE_SPINCONTROL;
- s_health_box.generic.x = 0;
- s_health_box.generic.y = y += 10;
- s_health_box.generic.callback = DMFlagCallback;
- s_health_box.generic.name = "allow health";
- s_health_box.itemnames = yes_no_names;
- s_health_box.curvalue = ( dmflags & DF_NO_HEALTH ) == 0;
-
- s_armor_box.generic.type = MTYPE_SPINCONTROL;
- s_armor_box.generic.x = 0;
- s_armor_box.generic.y = y += 10;
- s_armor_box.generic.name = "allow armor";
- s_armor_box.generic.callback = DMFlagCallback;
- s_armor_box.itemnames = yes_no_names;
- s_armor_box.curvalue = ( dmflags & DF_NO_ARMOR ) == 0;
-
- s_spawn_farthest_box.generic.type = MTYPE_SPINCONTROL;
- s_spawn_farthest_box.generic.x = 0;
- s_spawn_farthest_box.generic.y = y += 10;
- s_spawn_farthest_box.generic.name = "spawn farthest";
- s_spawn_farthest_box.generic.callback = DMFlagCallback;
- s_spawn_farthest_box.itemnames = yes_no_names;
- s_spawn_farthest_box.curvalue = ( dmflags & DF_SPAWN_FARTHEST ) != 0;
-
- s_samelevel_box.generic.type = MTYPE_SPINCONTROL;
- s_samelevel_box.generic.x = 0;
- s_samelevel_box.generic.y = y += 10;
- s_samelevel_box.generic.name = "same map";
- s_samelevel_box.generic.callback = DMFlagCallback;
- s_samelevel_box.itemnames = yes_no_names;
- s_samelevel_box.curvalue = ( dmflags & DF_SAME_LEVEL ) != 0;
-
- s_force_respawn_box.generic.type = MTYPE_SPINCONTROL;
- s_force_respawn_box.generic.x = 0;
- s_force_respawn_box.generic.y = y += 10;
- s_force_respawn_box.generic.name = "force respawn";
- s_force_respawn_box.generic.callback = DMFlagCallback;
- s_force_respawn_box.itemnames = yes_no_names;
- s_force_respawn_box.curvalue = ( dmflags & DF_FORCE_RESPAWN ) != 0;
-
- s_teamplay_box.generic.type = MTYPE_SPINCONTROL;
- s_teamplay_box.generic.x = 0;
- s_teamplay_box.generic.y = y += 10;
- s_teamplay_box.generic.name = "teamplay";
- s_teamplay_box.generic.callback = DMFlagCallback;
- s_teamplay_box.itemnames = teamplay_names;
-
- s_allow_exit_box.generic.type = MTYPE_SPINCONTROL;
- s_allow_exit_box.generic.x = 0;
- s_allow_exit_box.generic.y = y += 10;
- s_allow_exit_box.generic.name = "allow exit";
- s_allow_exit_box.generic.callback = DMFlagCallback;
- s_allow_exit_box.itemnames = yes_no_names;
- s_allow_exit_box.curvalue = ( dmflags & DF_ALLOW_EXIT ) != 0;
-
- s_infinite_ammo_box.generic.type = MTYPE_SPINCONTROL;
- s_infinite_ammo_box.generic.x = 0;
- s_infinite_ammo_box.generic.y = y += 10;
- s_infinite_ammo_box.generic.name = "infinite ammo";
- s_infinite_ammo_box.generic.callback = DMFlagCallback;
- s_infinite_ammo_box.itemnames = yes_no_names;
- s_infinite_ammo_box.curvalue = ( dmflags & DF_INFINITE_AMMO ) != 0;
-
- s_fixed_fov_box.generic.type = MTYPE_SPINCONTROL;
- s_fixed_fov_box.generic.x = 0;
- s_fixed_fov_box.generic.y = y += 10;
- s_fixed_fov_box.generic.name = "fixed FOV";
- s_fixed_fov_box.generic.callback = DMFlagCallback;
- s_fixed_fov_box.itemnames = yes_no_names;
- s_fixed_fov_box.curvalue = ( dmflags & DF_FIXED_FOV ) != 0;
-
- s_quad_drop_box.generic.type = MTYPE_SPINCONTROL;
- s_quad_drop_box.generic.x = 0;
- s_quad_drop_box.generic.y = y += 10;
- s_quad_drop_box.generic.name = "quad drop";
- s_quad_drop_box.generic.callback = DMFlagCallback;
- s_quad_drop_box.itemnames = yes_no_names;
- s_quad_drop_box.curvalue = ( dmflags & DF_QUAD_DROP ) != 0;
-
- s_friendlyfire_box.generic.type = MTYPE_SPINCONTROL;
- s_friendlyfire_box.generic.x = 0;
- s_friendlyfire_box.generic.y = y += 10;
- s_friendlyfire_box.generic.name = "friendly fire";
- s_friendlyfire_box.generic.callback = DMFlagCallback;
- s_friendlyfire_box.itemnames = yes_no_names;
- s_friendlyfire_box.curvalue = ( dmflags & DF_NO_FRIENDLY_FIRE ) == 0;
-
-//============
-//ROGUE
- if(Developer_searchpath(2) == 2)
- {
- s_no_mines_box.generic.type = MTYPE_SPINCONTROL;
- s_no_mines_box.generic.x = 0;
- s_no_mines_box.generic.y = y += 10;
- s_no_mines_box.generic.name = "remove mines";
- s_no_mines_box.generic.callback = DMFlagCallback;
- s_no_mines_box.itemnames = yes_no_names;
- s_no_mines_box.curvalue = ( dmflags & DF_NO_MINES ) != 0;
-
- s_no_nukes_box.generic.type = MTYPE_SPINCONTROL;
- s_no_nukes_box.generic.x = 0;
- s_no_nukes_box.generic.y = y += 10;
- s_no_nukes_box.generic.name = "remove nukes";
- s_no_nukes_box.generic.callback = DMFlagCallback;
- s_no_nukes_box.itemnames = yes_no_names;
- s_no_nukes_box.curvalue = ( dmflags & DF_NO_NUKES ) != 0;
-
- s_stack_double_box.generic.type = MTYPE_SPINCONTROL;
- s_stack_double_box.generic.x = 0;
- s_stack_double_box.generic.y = y += 10;
- s_stack_double_box.generic.name = "2x/4x stacking off";
- s_stack_double_box.generic.callback = DMFlagCallback;
- s_stack_double_box.itemnames = yes_no_names;
- s_stack_double_box.curvalue = ( dmflags & DF_NO_STACK_DOUBLE ) != 0;
-
- s_no_spheres_box.generic.type = MTYPE_SPINCONTROL;
- s_no_spheres_box.generic.x = 0;
- s_no_spheres_box.generic.y = y += 10;
- s_no_spheres_box.generic.name = "remove spheres";
- s_no_spheres_box.generic.callback = DMFlagCallback;
- s_no_spheres_box.itemnames = yes_no_names;
- s_no_spheres_box.curvalue = ( dmflags & DF_NO_SPHERES ) != 0;
-
- }
-//ROGUE
-//============
-
- Menu_AddItem( &s_dmoptions_menu, &s_falls_box );
- Menu_AddItem( &s_dmoptions_menu, &s_weapons_stay_box );
- Menu_AddItem( &s_dmoptions_menu, &s_instant_powerups_box );
- Menu_AddItem( &s_dmoptions_menu, &s_powerups_box );
- Menu_AddItem( &s_dmoptions_menu, &s_health_box );
- Menu_AddItem( &s_dmoptions_menu, &s_armor_box );
- Menu_AddItem( &s_dmoptions_menu, &s_spawn_farthest_box );
- Menu_AddItem( &s_dmoptions_menu, &s_samelevel_box );
- Menu_AddItem( &s_dmoptions_menu, &s_force_respawn_box );
- Menu_AddItem( &s_dmoptions_menu, &s_teamplay_box );
- Menu_AddItem( &s_dmoptions_menu, &s_allow_exit_box );
- Menu_AddItem( &s_dmoptions_menu, &s_infinite_ammo_box );
- Menu_AddItem( &s_dmoptions_menu, &s_fixed_fov_box );
- Menu_AddItem( &s_dmoptions_menu, &s_quad_drop_box );
- Menu_AddItem( &s_dmoptions_menu, &s_friendlyfire_box );
-
-//=======
-//ROGUE
- if(Developer_searchpath(2) == 2)
- {
- Menu_AddItem( &s_dmoptions_menu, &s_no_mines_box );
- Menu_AddItem( &s_dmoptions_menu, &s_no_nukes_box );
- Menu_AddItem( &s_dmoptions_menu, &s_stack_double_box );
- Menu_AddItem( &s_dmoptions_menu, &s_no_spheres_box );
- }
-//ROGUE
-//=======
-
- Menu_Center( &s_dmoptions_menu );
-
- // set the original dmflags statusbar
- DMFlagCallback( 0 );
- Menu_SetStatusBar( &s_dmoptions_menu, dmoptions_statusbar );
-}
-
-void DMOptions_MenuDraw(void)
-{
- Menu_Draw( &s_dmoptions_menu );
-}
-
-const char *DMOptions_MenuKey( int key )
-{
- return Default_MenuKey( &s_dmoptions_menu, key );
-}
-
-void M_Menu_DMOptions_f (void)
-{
- DMOptions_MenuInit();
- M_PushMenu( DMOptions_MenuDraw, DMOptions_MenuKey );
-}
-
-/*
-=============================================================================
-
-DOWNLOADOPTIONS BOOK MENU
-
-=============================================================================
-*/
-static menuframework_s s_downloadoptions_menu;
-
-static menuseparator_s s_download_title;
-static menulist_s s_allow_download_box;
-static menulist_s s_allow_download_maps_box;
-static menulist_s s_allow_download_models_box;
-static menulist_s s_allow_download_players_box;
-static menulist_s s_allow_download_sounds_box;
-
-static void DownloadCallback( void *self )
-{
- menulist_s *f = ( menulist_s * ) self;
-
- if (f == &s_allow_download_box)
- {
- Cvar_SetValue("allow_download", f->curvalue);
- }
-
- else if (f == &s_allow_download_maps_box)
- {
- Cvar_SetValue("allow_download_maps", f->curvalue);
- }
-
- else if (f == &s_allow_download_models_box)
- {
- Cvar_SetValue("allow_download_models", f->curvalue);
- }
-
- else if (f == &s_allow_download_players_box)
- {
- Cvar_SetValue("allow_download_players", f->curvalue);
- }
-
- else if (f == &s_allow_download_sounds_box)
- {
- Cvar_SetValue("allow_download_sounds", f->curvalue);
- }
-}
-
-void DownloadOptions_MenuInit( void )
-{
- static const char *yes_no_names[] =
- {
- "no", "yes", 0
- };
- int y = 0;
-
- s_downloadoptions_menu.x = vid.width * 0.50;
- s_downloadoptions_menu.nitems = 0;
-
- s_download_title.generic.type = MTYPE_SEPARATOR;
- s_download_title.generic.name = "Download Options";
- s_download_title.generic.x = 48;
- s_download_title.generic.y = y;
-
- s_allow_download_box.generic.type = MTYPE_SPINCONTROL;
- s_allow_download_box.generic.x = 0;
- s_allow_download_box.generic.y = y += 20;
- s_allow_download_box.generic.name = "allow downloading";
- s_allow_download_box.generic.callback = DownloadCallback;
- s_allow_download_box.itemnames = yes_no_names;
- s_allow_download_box.curvalue = (Cvar_VariableValue("allow_download") != 0);
-
- s_allow_download_maps_box.generic.type = MTYPE_SPINCONTROL;
- s_allow_download_maps_box.generic.x = 0;
- s_allow_download_maps_box.generic.y = y += 20;
- s_allow_download_maps_box.generic.name = "maps";
- s_allow_download_maps_box.generic.callback = DownloadCallback;
- s_allow_download_maps_box.itemnames = yes_no_names;
- s_allow_download_maps_box.curvalue = (Cvar_VariableValue("allow_download_maps") != 0);
-
- s_allow_download_players_box.generic.type = MTYPE_SPINCONTROL;
- s_allow_download_players_box.generic.x = 0;
- s_allow_download_players_box.generic.y = y += 10;
- s_allow_download_players_box.generic.name = "player models/skins";
- s_allow_download_players_box.generic.callback = DownloadCallback;
- s_allow_download_players_box.itemnames = yes_no_names;
- s_allow_download_players_box.curvalue = (Cvar_VariableValue("allow_download_players") != 0);
-
- s_allow_download_models_box.generic.type = MTYPE_SPINCONTROL;
- s_allow_download_models_box.generic.x = 0;
- s_allow_download_models_box.generic.y = y += 10;
- s_allow_download_models_box.generic.name = "models";
- s_allow_download_models_box.generic.callback = DownloadCallback;
- s_allow_download_models_box.itemnames = yes_no_names;
- s_allow_download_models_box.curvalue = (Cvar_VariableValue("allow_download_models") != 0);
-
- s_allow_download_sounds_box.generic.type = MTYPE_SPINCONTROL;
- s_allow_download_sounds_box.generic.x = 0;
- s_allow_download_sounds_box.generic.y = y += 10;
- s_allow_download_sounds_box.generic.name = "sounds";
- s_allow_download_sounds_box.generic.callback = DownloadCallback;
- s_allow_download_sounds_box.itemnames = yes_no_names;
- s_allow_download_sounds_box.curvalue = (Cvar_VariableValue("allow_download_sounds") != 0);
-
- Menu_AddItem( &s_downloadoptions_menu, &s_download_title );
- Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_box );
- Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_maps_box );
- Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_players_box );
- Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_models_box );
- Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_sounds_box );
-
- Menu_Center( &s_downloadoptions_menu );
-
- // skip over title
- if (s_downloadoptions_menu.cursor == 0)
- s_downloadoptions_menu.cursor = 1;
-}
-
-void DownloadOptions_MenuDraw(void)
-{
- Menu_Draw( &s_downloadoptions_menu );
-}
-
-const char *DownloadOptions_MenuKey( int key )
-{
- return Default_MenuKey( &s_downloadoptions_menu, key );
-}
-
-void M_Menu_DownloadOptions_f (void)
-{
- DownloadOptions_MenuInit();
- M_PushMenu( DownloadOptions_MenuDraw, DownloadOptions_MenuKey );
-}
-/*
-=============================================================================
-
-ADDRESS BOOK MENU
-
-=============================================================================
-*/
-#define NUM_ADDRESSBOOK_ENTRIES 9
-
-static menuframework_s s_addressbook_menu;
-static menufield_s s_addressbook_fields[NUM_ADDRESSBOOK_ENTRIES];
-
-void AddressBook_MenuInit( void )
-{
- int i;
-
- s_addressbook_menu.x = vid.width / 2 - 142;
- s_addressbook_menu.y = vid.height / 2 - 58;
- s_addressbook_menu.nitems = 0;
-
- for ( i = 0; i < NUM_ADDRESSBOOK_ENTRIES; i++ )
- {
- cvar_t *adr;
- char buffer[20];
-
- Com_sprintf( buffer, sizeof( buffer ), "adr%d", i );
-
- adr = Cvar_Get( buffer, "", CVAR_ARCHIVE );
-
- s_addressbook_fields[i].generic.type = MTYPE_FIELD;
- s_addressbook_fields[i].generic.name = 0;
- s_addressbook_fields[i].generic.callback = 0;
- s_addressbook_fields[i].generic.x = 0;
- s_addressbook_fields[i].generic.y = i * 18 + 0;
- s_addressbook_fields[i].generic.localdata[0] = i;
- s_addressbook_fields[i].cursor = 0;
- s_addressbook_fields[i].length = 60;
- s_addressbook_fields[i].visible_length = 30;
-
- strcpy( s_addressbook_fields[i].buffer, adr->string );
-
- Menu_AddItem( &s_addressbook_menu, &s_addressbook_fields[i] );
- }
-}
-
-const char *AddressBook_MenuKey( int key )
-{
- if ( key == K_ESCAPE )
- {
- int index;
- char buffer[20];
-
- for ( index = 0; index < NUM_ADDRESSBOOK_ENTRIES; index++ )
- {
- Com_sprintf( buffer, sizeof( buffer ), "adr%d", index );
- Cvar_Set( buffer, s_addressbook_fields[index].buffer );
- }
- }
- return Default_MenuKey( &s_addressbook_menu, key );
-}
-
-void AddressBook_MenuDraw(void)
-{
- M_Banner( "m_banner_addressbook" );
- Menu_Draw( &s_addressbook_menu );
-}
-
-void M_Menu_AddressBook_f(void)
-{
- AddressBook_MenuInit();
- M_PushMenu( AddressBook_MenuDraw, AddressBook_MenuKey );
-}
-
-/*
-=============================================================================
-
-PLAYER CONFIG MENU
-
-=============================================================================
-*/
-static menuframework_s s_player_config_menu;
-static menufield_s s_player_name_field;
-static menulist_s s_player_model_box;
-static menulist_s s_player_skin_box;
-static menulist_s s_player_handedness_box;
-static menulist_s s_player_rate_box;
-static menuseparator_s s_player_skin_title;
-static menuseparator_s s_player_model_title;
-static menuseparator_s s_player_hand_title;
-static menuseparator_s s_player_rate_title;
-static menuaction_s s_player_download_action;
-
-#define MAX_DISPLAYNAME 16
-#define MAX_PLAYERMODELS 1024
-
-typedef struct
-{
- int nskins;
- char **skindisplaynames;
- char displayname[MAX_DISPLAYNAME];
- char directory[MAX_QPATH];
-} playermodelinfo_s;
-
-static playermodelinfo_s s_pmi[MAX_PLAYERMODELS];
-static char *s_pmnames[MAX_PLAYERMODELS];
-static int s_numplayermodels;
-
-static int rate_tbl[] = { 2500, 3200, 5000, 10000, 25000, 0 };
-static const char *rate_names[] = { "28.8 Modem", "33.6 Modem", "Single ISDN",
- "Dual ISDN/Cable", "T1/LAN", "User defined", 0 };
-
-void DownloadOptionsFunc( void * )
-{
- M_Menu_DownloadOptions_f();
-}
-
-static void HandednessCallback( void * )
-{
- Cvar_SetValue( "hand", s_player_handedness_box.curvalue );
-}
-
-static void RateCallback( void * )
-{
- if (s_player_rate_box.curvalue != sizeof(rate_tbl) / sizeof(*rate_tbl) - 1)
- Cvar_SetValue( "rate", rate_tbl[s_player_rate_box.curvalue] );
-}
-
-static void ModelCallback( void * )
-{
- s_player_skin_box.itemnames = s_pmi[s_player_model_box.curvalue].skindisplaynames;
- s_player_skin_box.curvalue = 0;
-}
-
-static void FreeFileList( char **list, int n )
-{
- int i;
-
- for ( i = 0; i < n; i++ )
- {
- if ( list[i] )
- {
- free( list[i] );
- list[i] = 0;
- }
- }
- free( list );
-}
-
-static qboolean IconOfSkinExists( char *skin, char **pcxfiles, int npcxfiles )
-{
- int i;
- char scratch[1024];
-
- strcpy( scratch, skin );
- *strrchr( scratch, '.' ) = 0;
- strcat( scratch, "_i.pcx" );
-
- for ( i = 0; i < npcxfiles; i++ )
- {
- if ( strcmp( pcxfiles[i], scratch ) == 0 )
- return true;
- }
-
- return false;
-}
-
-static qboolean PlayerConfig_ScanDirectories( void )
-{
- char findname[1024];
- char scratch[1024];
- int ndirs = 0, npms;
- char **dirnames = NULL;
- char *path = NULL;
- int i;
-
- extern char **FS_ListFiles( char *, int *, unsigned, unsigned );
-
- s_numplayermodels = 0;
-
- /*
- ** get a list of directories
- */
- do
- {
- if ( ( path = FS_NextPath( path ) ) == NULL)
- break;
- Com_sprintf( findname, sizeof(findname), "%s/players/*.*", path );
-
- if ( ( dirnames = FS_ListFiles( findname, &ndirs, SFF_SUBDIR, 0 ) ) != 0 )
- break;
- } while ( path );
-
- if ( !dirnames )
- return false;
-
- /*
- ** go through the subdirectories
- */
- npms = ndirs;
- if ( npms > MAX_PLAYERMODELS )
- npms = MAX_PLAYERMODELS;
-
- for ( i = 0; i < npms; i++ )
- {
- int k, s;
- char *a, *b, *c;
- char **pcxnames;
- char **skinnames;
- int npcxfiles;
- int nskins = 0;
-
- if ( dirnames[i] == 0 )
- continue;
-
- // verify the existence of tris.md2
- strcpy( scratch, dirnames[i] );
- strcat( scratch, "/tris.md2" );
- if ( !Sys_FindFirst( scratch, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM ) )
- {
- free( dirnames[i] );
- dirnames[i] = 0;
- Sys_FindClose();
- continue;
- }
- Sys_FindClose();
-
- // verify the existence of at least one pcx skin
- strcpy( scratch, dirnames[i] );
- strcat( scratch, "/*.pcx" );
- pcxnames = FS_ListFiles( scratch, &npcxfiles, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM );
-
- if ( !pcxnames )
- {
- free( dirnames[i] );
- dirnames[i] = 0;
- continue;
- }
-
- // count valid skins, which consist of a skin with a matching "_i" icon
- for ( k = 0; k < npcxfiles-1; k++ )
- {
- if ( !strstr( pcxnames[k], "_i.pcx" ) )
- {
- if ( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles - 1 ) )
- {
- nskins++;
- }
- }
- }
- if ( !nskins )
- continue;
-
- skinnames = malloc( sizeof( char * ) * ( nskins + 1 ) );
- memset( skinnames, 0, sizeof( char * ) * ( nskins + 1 ) );
-
- // copy the valid skins
- for ( s = 0, k = 0; k < npcxfiles-1; k++ )
- {
- char *a, *b, *c;
-
- if ( !strstr( pcxnames[k], "_i.pcx" ) )
- {
- if ( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles - 1 ) )
- {
- a = strrchr( pcxnames[k], '/' );
- b = strrchr( pcxnames[k], '\\' );
-
- if ( a > b )
- c = a;
- else
- c = b;
-
- strcpy( scratch, c + 1 );
-
- if ( strrchr( scratch, '.' ) )
- *strrchr( scratch, '.' ) = 0;
-
- skinnames[s] = strdup( scratch );
- s++;
- }
- }
- }
-
- // at this point we have a valid player model
- s_pmi[s_numplayermodels].nskins = nskins;
- s_pmi[s_numplayermodels].skindisplaynames = skinnames;
-
- // make short name for the model
- a = strrchr( dirnames[i], '/' );
- b = strrchr( dirnames[i], '\\' );
-
- if ( a > b )
- c = a;
- else
- c = b;
-
- strncpy( s_pmi[s_numplayermodels].displayname, c + 1, MAX_DISPLAYNAME-1 );
- strcpy( s_pmi[s_numplayermodels].directory, c + 1 );
-
- FreeFileList( pcxnames, npcxfiles );
-
- s_numplayermodels++;
- }
- if ( dirnames )
- FreeFileList( dirnames, ndirs );
- return true;
-}
-
-static int pmicmpfnc( const void *_a, const void *_b )
-{
- const playermodelinfo_s *a = ( const playermodelinfo_s * ) _a;
- const playermodelinfo_s *b = ( const playermodelinfo_s * ) _b;
-
- /*
- ** sort by male, female, then alphabetical
- */
- if ( strcmp( a->directory, "male" ) == 0 )
- return -1;
- else if ( strcmp( b->directory, "male" ) == 0 )
- return 1;
-
- if ( strcmp( a->directory, "female" ) == 0 )
- return -1;
- else if ( strcmp( b->directory, "female" ) == 0 )
- return 1;
-
- return strcmp( a->directory, b->directory );
-}
-
-
-qboolean PlayerConfig_MenuInit( void )
-{
- extern cvar_t *name;
- extern cvar_t *team;
- extern cvar_t *skin;
- char currentdirectory[1024];
- char currentskin[1024];
- int i;
-
- int currentdirectoryindex = 0;
- int currentskinindex = 0;
-
- cvar_t *hand = Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE );
-
- static const char *handedness[] = { "right", "left", "center", 0 };
-
- PlayerConfig_ScanDirectories();
-
- if (s_numplayermodels == 0)
- return false;
-
- if ( hand->value < 0 || hand->value > 2 )
- Cvar_SetValue( "hand", 0 );
-
- strcpy( currentdirectory, skin->string );
-
- if ( strchr( currentdirectory, '/' ) )
- {
- strcpy( currentskin, strchr( currentdirectory, '/' ) + 1 );
- *strchr( currentdirectory, '/' ) = 0;
- }
- else if ( strchr( currentdirectory, '\\' ) )
- {
- strcpy( currentskin, strchr( currentdirectory, '\\' ) + 1 );
- *strchr( currentdirectory, '\\' ) = 0;
- }
- else
- {
- strcpy( currentdirectory, "male" );
- strcpy( currentskin, "grunt" );
- }
-
- qsort( s_pmi, s_numplayermodels, sizeof( s_pmi[0] ), pmicmpfnc );
-
- memset( s_pmnames, 0, sizeof( s_pmnames ) );
- for ( i = 0; i < s_numplayermodels; i++ )
- {
- s_pmnames[i] = s_pmi[i].displayname;
- if ( cistrcmp( s_pmi[i].directory, currentdirectory ) == 0 )
- {
- int j;
-
- currentdirectoryindex = i;
-
- for ( j = 0; j < s_pmi[i].nskins; j++ )
- {
- if ( cistrcmp( s_pmi[i].skindisplaynames[j], currentskin ) == 0 )
- {
- currentskinindex = j;
- break;
- }
- }
- }
- }
-
- s_player_config_menu.x = vid.width / 2 - 95;
- s_player_config_menu.y = vid.height / 2 - 97;
- s_player_config_menu.nitems = 0;
-
- s_player_name_field.generic.type = MTYPE_FIELD;
- s_player_name_field.generic.name = "name";
- s_player_name_field.generic.callback = 0;
- s_player_name_field.generic.x = 0;
- s_player_name_field.generic.y = 0;
- s_player_name_field.length = 20;
- s_player_name_field.visible_length = 20;
- strcpy( s_player_name_field.buffer, name->string );
- s_player_name_field.cursor = strlen( name->string );
-
- s_player_model_title.generic.type = MTYPE_SEPARATOR;
- s_player_model_title.generic.name = "model";
- s_player_model_title.generic.x = -8;
- s_player_model_title.generic.y = 60;
-
- s_player_model_box.generic.type = MTYPE_SPINCONTROL;
- s_player_model_box.generic.x = -56;
- s_player_model_box.generic.y = 70;
- s_player_model_box.generic.callback = ModelCallback;
- s_player_model_box.generic.cursor_offset = -48;
- s_player_model_box.curvalue = currentdirectoryindex;
- s_player_model_box.itemnames = s_pmnames;
-
- s_player_skin_title.generic.type = MTYPE_SEPARATOR;
- s_player_skin_title.generic.name = "skin";
- s_player_skin_title.generic.x = -16;
- s_player_skin_title.generic.y = 84;
-
- s_player_skin_box.generic.type = MTYPE_SPINCONTROL;
- s_player_skin_box.generic.x = -56;
- s_player_skin_box.generic.y = 94;
- s_player_skin_box.generic.name = 0;
- s_player_skin_box.generic.callback = 0;
- s_player_skin_box.generic.cursor_offset = -48;
- s_player_skin_box.curvalue = currentskinindex;
- s_player_skin_box.itemnames = s_pmi[currentdirectoryindex].skindisplaynames;
-
- s_player_hand_title.generic.type = MTYPE_SEPARATOR;
- s_player_hand_title.generic.name = "handedness";
- s_player_hand_title.generic.x = 32;
- s_player_hand_title.generic.y = 108;
-
- s_player_handedness_box.generic.type = MTYPE_SPINCONTROL;
- s_player_handedness_box.generic.x = -56;
- s_player_handedness_box.generic.y = 118;
- s_player_handedness_box.generic.name = 0;
- s_player_handedness_box.generic.cursor_offset = -48;
- s_player_handedness_box.generic.callback = HandednessCallback;
- s_player_handedness_box.curvalue = Cvar_VariableValue( "hand" );
- s_player_handedness_box.itemnames = handedness;
-
- for (i = 0; i < sizeof(rate_tbl) / sizeof(*rate_tbl) - 1; i++)
- if (Cvar_VariableValue("rate") == rate_tbl[i])
- break;
-
- s_player_rate_title.generic.type = MTYPE_SEPARATOR;
- s_player_rate_title.generic.name = "connect speed";
- s_player_rate_title.generic.x = 56;
- s_player_rate_title.generic.y = 156;
-
- s_player_rate_box.generic.type = MTYPE_SPINCONTROL;
- s_player_rate_box.generic.x = -56;
- s_player_rate_box.generic.y = 166;
- s_player_rate_box.generic.name = 0;
- s_player_rate_box.generic.cursor_offset = -48;
- s_player_rate_box.generic.callback = RateCallback;
- s_player_rate_box.curvalue = i;
- s_player_rate_box.itemnames = rate_names;
-
- s_player_download_action.generic.type = MTYPE_ACTION;
- s_player_download_action.generic.name = "download options";
- s_player_download_action.generic.flags= QMF_LEFT_JUSTIFY;
- s_player_download_action.generic.x = -24;
- s_player_download_action.generic.y = 186;
- s_player_download_action.generic.statusbar = NULL;
- s_player_download_action.generic.callback = DownloadOptionsFunc;
-
- Menu_AddItem( &s_player_config_menu, &s_player_name_field );
- Menu_AddItem( &s_player_config_menu, &s_player_model_title );
- Menu_AddItem( &s_player_config_menu, &s_player_model_box );
- if ( s_player_skin_box.itemnames )
- {
- Menu_AddItem( &s_player_config_menu, &s_player_skin_title );
- Menu_AddItem( &s_player_config_menu, &s_player_skin_box );
- }
- Menu_AddItem( &s_player_config_menu, &s_player_hand_title );
- Menu_AddItem( &s_player_config_menu, &s_player_handedness_box );
- Menu_AddItem( &s_player_config_menu, &s_player_rate_title );
- Menu_AddItem( &s_player_config_menu, &s_player_rate_box );
- Menu_AddItem( &s_player_config_menu, &s_player_download_action );
-
- return true;
-}
-
-void PlayerConfig_MenuDraw( void )
-{
- extern float CalcFov( float fov_x, float w, float h );
- refdef_t refdef;
- char scratch[MAX_QPATH];
-
- memset( &refdef, 0, sizeof( refdef ) );
-
- refdef.x = vid.width / 2;
- refdef.y = vid.height / 2 - 72;
- refdef.width = 144;
- refdef.height = 168;
- refdef.fov_x = 40;
- refdef.fov_y = CalcFov( refdef.fov_x, refdef.width, refdef.height );
- refdef.time = cls.realtime*0.001;
-
- if ( s_pmi[s_player_model_box.curvalue].skindisplaynames )
- {
- static int yaw;
- entity_t entity;
-
- memset( &entity, 0, sizeof( entity ) );
-
- Com_sprintf( scratch, sizeof( scratch ), "players/%s/tris.md2", s_pmi[s_player_model_box.curvalue].directory );
- entity.model = re.RegisterModel( scratch );
- Com_sprintf( scratch, sizeof( scratch ), "players/%s/%s.pcx", s_pmi[s_player_model_box.curvalue].directory, s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
- entity.skin = re.RegisterSkin( scratch );
- entity.flags = RF_FULLBRIGHT;
- entity.origin[0] = 80;
- entity.origin[1] = 0;
- entity.origin[2] = 0;
- VectorCopy( entity.origin, entity.oldorigin );
- entity.frame = 0;
- entity.oldframe = 0;
- entity.backlerp = 0.0;
- entity.angles[1] = yaw++;
- if ( ++yaw > 360 )
- yaw -= 360;
-
- refdef.areabits = 0;
- refdef.num_entities = 1;
- refdef.entities = &entity;
- refdef.lightstyles = 0;
- refdef.rdflags = RDF_NOWORLDMODEL;
-
- Menu_Draw( &s_player_config_menu );
-
- M_DrawTextBox( ( refdef.x ) * ( 320.0F / vid.width ) - 8, ( vid.height / 2 ) * ( 240.0F / vid.height) - 77, refdef.width / 8, refdef.height / 8 );
- refdef.height += 4;
-
- re.RenderFrame( &refdef );
-
- Com_sprintf( scratch, sizeof( scratch ), "/players/%s/%s_i.pcx",
- s_pmi[s_player_model_box.curvalue].directory,
- s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
- re.DrawPic( s_player_config_menu.x - 40, refdef.y, scratch );
- }
-}
-
-const char *PlayerConfig_MenuKey (int key)
-{
- int i;
-
- if ( key == K_ESCAPE )
- {
- char scratch[1024];
-
- Cvar_Set( "name", s_player_name_field.buffer );
-
- Com_sprintf( scratch, sizeof( scratch ), "%s/%s",
- s_pmi[s_player_model_box.curvalue].directory,
- s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
-
- Cvar_Set( "skin", scratch );
-
- for ( i = 0; i < s_numplayermodels; i++ )
- {
- int j;
-
- for ( j = 0; j < s_pmi[i].nskins; j++ )
- {
- if ( s_pmi[i].skindisplaynames[j] )
- free( s_pmi[i].skindisplaynames[j] );
- s_pmi[i].skindisplaynames[j] = 0;
- }
- free( s_pmi[i].skindisplaynames );
- s_pmi[i].skindisplaynames = 0;
- s_pmi[i].nskins = 0;
- }
- }
- return Default_MenuKey( &s_player_config_menu, key );
-}
-
-
-void M_Menu_PlayerConfig_f (void)
-{
- if (!PlayerConfig_MenuInit())
- {
- Menu_SetStatusBar( &s_multiplayer_menu, "No valid player models found" );
- return;
- }
- Menu_SetStatusBar( &s_multiplayer_menu, NULL );
- M_PushMenu( PlayerConfig_MenuDraw, PlayerConfig_MenuKey );
-}
-
-
-/*
-=======================================================================
-
-GALLERY MENU
-
-=======================================================================
-*/
-/* commented out in release
-void M_Menu_Gallery_f( void )
-{
- extern void Gallery_MenuDraw( void );
- extern const char *Gallery_MenuKey( int key );
-
- M_PushMenu( Gallery_MenuDraw, Gallery_MenuKey );
-}
-*/
-
-/*
-=======================================================================
-
-QUIT MENU
-
-=======================================================================
-*/
-
-const char *M_Quit_Key (int key)
-{
- switch (key)
- {
- case K_ESCAPE:
- case 'n':
- case 'N':
- M_PopMenu ();
- break;
-
- case 'Y':
- case 'y':
- cls.key_dest = key_console;
- CL_Quit_f ();
- break;
-
- default:
- break;
- }
-
- return NULL;
-
-}
-
-
-void M_Quit_Draw (void)
-{
- int w, h;
-
- re.DrawGetPicSize (&w, &h, "quit");
- re.DrawPic ( (vid.width-w)/2, (vid.height-h)/2, "quit");
-}
-
-
-void M_Menu_Quit_f (void)
-{
- M_PushMenu (M_Quit_Draw, M_Quit_Key);
-}
-
-
-
-//=============================================================================
-/* Menu Subsystem */
-
-
-/*
-=================
-M_Init
-=================
-*/
-void M_Init (void)
-{
- Cmd_AddCommand ("menu_main", M_Menu_Main_f);
- Cmd_AddCommand ("menu_game", M_Menu_Game_f);
- Cmd_AddCommand ("menu_loadgame", M_Menu_LoadGame_f);
- Cmd_AddCommand ("menu_savegame", M_Menu_SaveGame_f);
- Cmd_AddCommand ("menu_joinserver", M_Menu_JoinServer_f);
- Cmd_AddCommand ("menu_addressbook", M_Menu_AddressBook_f);
- Cmd_AddCommand ("menu_startserver", M_Menu_StartServer_f);
- Cmd_AddCommand ("menu_dmoptions", M_Menu_DMOptions_f);
- Cmd_AddCommand ("menu_playerconfig", M_Menu_PlayerConfig_f);
- Cmd_AddCommand ("menu_downloadoptions", M_Menu_DownloadOptions_f);
- Cmd_AddCommand ("menu_credits", M_Menu_Credits_f );
- Cmd_AddCommand ("menu_multiplayer", M_Menu_Multiplayer_f );
- Cmd_AddCommand ("menu_video", M_Menu_Video_f);
- Cmd_AddCommand ("menu_options", M_Menu_Options_f);
- Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
- Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
-}
-
-
-/*
-=================
-M_Draw
-=================
-*/
-void M_Draw (void)
-{
- if (cls.key_dest != key_menu)
- return;
-
- // repaint everything next frame
- SCR_DirtyScreen ();
-
- // dim everything behind it down
- if (cl.cinematictime > 0)
- re.DrawFill (0,0,vid.width, vid.height, 0);
- else
- re.DrawFadeScreen ();
-
- m_drawfunc ();
-
- // delay playing the enter sound until after the
- // menu has been drawn, to avoid delay while
- // caching images
- if (m_entersound)
- {
- S_StartLocalSound( menu_in_sound );
- m_entersound = false;
- }
-}
-
-
-/*
-=================
-M_Keydown
-=================
-*/
-void M_Keydown (int key)
-{
- const char *s;
-
- if (m_keyfunc)
- if ( ( s = m_keyfunc( key ) ) != 0 )
- S_StartLocalSound( ( char * ) s );
-}
-
-
--- a/client/qmenu.c
+++ /dev/null
@@ -1,651 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <ctype.h>
-#include "../q_shared.h"
-
-void Action_DoEnter( menuaction_s *a );
-void Action_Draw( menuaction_s *a );
-void Menu_DrawStatusBar( const char *string );
-void Menulist_DoEnter( menulist_s *l );
-void MenuList_Draw( menulist_s *l );
-void Separator_Draw( menuseparator_s *s );
-void Slider_DoSlide( menuslider_s *s, int dir );
-void Slider_Draw( menuslider_s *s );
-void SpinControl_DoEnter( menulist_s *s );
-void SpinControl_Draw( menulist_s *s );
-void SpinControl_DoSlide( menulist_s *s, int dir );
-
-#define RCOLUMN_OFFSET 16
-#define LCOLUMN_OFFSET -16
-
-extern refexport_t re;
-
-#define Draw_Char re.DrawChar
-#define Draw_Fill re.DrawFill
-
-void Action_DoEnter( menuaction_s *a )
-{
- if ( a->generic.callback )
- a->generic.callback( a );
-}
-
-void Action_Draw( menuaction_s *a )
-{
- if ( a->generic.flags & QMF_LEFT_JUSTIFY )
- {
- if ( a->generic.flags & QMF_GRAYED )
- Menu_DrawStringDark( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
- else
- Menu_DrawString( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
- }
- else
- {
- if ( a->generic.flags & QMF_GRAYED )
- Menu_DrawStringR2LDark( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
- else
- Menu_DrawStringR2L( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
- }
- if ( a->generic.ownerdraw )
- a->generic.ownerdraw( a );
-}
-
-qboolean Field_DoEnter( menufield_s *f )
-{
- if ( f->generic.callback )
- {
- f->generic.callback( f );
- return true;
- }
- return false;
-}
-
-void Field_Draw( menufield_s *f )
-{
- int i;
- char tempbuffer[128]="";
-
- if ( f->generic.name )
- Menu_DrawStringR2LDark( f->generic.x + f->generic.parent->x + LCOLUMN_OFFSET, f->generic.y + f->generic.parent->y, f->generic.name );
-
- strncpy( tempbuffer, f->buffer + f->visible_offset, f->visible_length );
-
- Draw_Char( f->generic.x + f->generic.parent->x + 16, f->generic.y + f->generic.parent->y - 4, 18 );
- Draw_Char( f->generic.x + f->generic.parent->x + 16, f->generic.y + f->generic.parent->y + 4, 24 );
-
- Draw_Char( f->generic.x + f->generic.parent->x + 24 + f->visible_length * 8, f->generic.y + f->generic.parent->y - 4, 20 );
- Draw_Char( f->generic.x + f->generic.parent->x + 24 + f->visible_length * 8, f->generic.y + f->generic.parent->y + 4, 26 );
-
- for ( i = 0; i < f->visible_length; i++ )
- {
- Draw_Char( f->generic.x + f->generic.parent->x + 24 + i * 8, f->generic.y + f->generic.parent->y - 4, 19 );
- Draw_Char( f->generic.x + f->generic.parent->x + 24 + i * 8, f->generic.y + f->generic.parent->y + 4, 25 );
- }
-
- Menu_DrawString( f->generic.x + f->generic.parent->x + 24, f->generic.y + f->generic.parent->y, tempbuffer );
-
- if ( Menu_ItemAtCursor( f->generic.parent ) == f )
- {
- int offset;
-
- if ( f->visible_offset )
- offset = f->visible_length;
- else
- offset = f->cursor;
-
- if ( ( ( int ) ( Sys_Milliseconds() / 250 ) ) & 1 )
- {
- Draw_Char( f->generic.x + f->generic.parent->x + ( offset + 2 ) * 8 + 8,
- f->generic.y + f->generic.parent->y,
- 11 );
- }
- else
- {
- Draw_Char( f->generic.x + f->generic.parent->x + ( offset + 2 ) * 8 + 8,
- f->generic.y + f->generic.parent->y,
- ' ' );
- }
- }
-}
-
-qboolean Field_Key( menufield_s *f, int key )
-{
- extern int keydown[];
-
- switch ( key )
- {
- case K_KP_SLASH:
- key = '/';
- break;
- case K_KP_MINUS:
- key = '-';
- break;
- case K_KP_PLUS:
- key = '+';
- break;
- case K_KP_HOME:
- key = '7';
- break;
- case K_KP_UPARROW:
- key = '8';
- break;
- case K_KP_PGUP:
- key = '9';
- break;
- case K_KP_LEFTARROW:
- key = '4';
- break;
- case K_KP_5:
- key = '5';
- break;
- case K_KP_RIGHTARROW:
- key = '6';
- break;
- case K_KP_END:
- key = '1';
- break;
- case K_KP_DOWNARROW:
- key = '2';
- break;
- case K_KP_PGDN:
- key = '3';
- break;
- case K_KP_INS:
- key = '0';
- break;
- case K_KP_DEL:
- key = '.';
- break;
- }
-
- if ( key > 127 )
- {
- switch ( key )
- {
- case K_DEL:
- default:
- return false;
- }
- }
-
- /*
- ** support pasting from the clipboard
- */
- if ( ( toupper( key ) == 'V' && keydown[K_CTRL] ) ||
- ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keydown[K_SHIFT] ) )
- {
- char *cbd;
-
- if ( ( cbd = Sys_GetClipboardData() ) != 0 )
- {
- strtok( cbd, "\n\r\b" );
-
- strncpy( f->buffer, cbd, f->length - 1 );
- f->cursor = strlen( f->buffer );
- f->visible_offset = f->cursor - f->visible_length;
- if ( f->visible_offset < 0 )
- f->visible_offset = 0;
-
- free( cbd );
- }
- return true;
- }
-
- switch ( key )
- {
- case K_KP_LEFTARROW:
- case K_LEFTARROW:
- case K_BACKSPACE:
- if ( f->cursor > 0 )
- {
- memmove( &f->buffer[f->cursor-1], &f->buffer[f->cursor], strlen( &f->buffer[f->cursor] ) + 1 );
- f->cursor--;
-
- if ( f->visible_offset )
- {
- f->visible_offset--;
- }
- }
- break;
-
- case K_KP_DEL:
- case K_DEL:
- memmove( &f->buffer[f->cursor], &f->buffer[f->cursor+1], strlen( &f->buffer[f->cursor+1] ) + 1 );
- break;
-
- case K_KP_ENTER:
- case K_ENTER:
- case K_ESCAPE:
- case K_TAB:
- return false;
-
- case K_SPACE:
- default:
- if ( !isdigit( key ) && ( f->generic.flags & QMF_NUMBERSONLY ) )
- return false;
-
- if ( f->cursor < f->length )
- {
- f->buffer[f->cursor++] = key;
- f->buffer[f->cursor] = 0;
-
- if ( f->cursor > f->visible_length )
- {
- f->visible_offset++;
- }
- }
- }
-
- return true;
-}
-
-void Menu_AddItem( menuframework_s *menu, void *item )
-{
- if ( menu->nitems == 0 )
- menu->nslots = 0;
-
- if ( menu->nitems < MAXMENUITEMS )
- {
- menu->items[menu->nitems] = item;
- ( ( menucommon_s * ) menu->items[menu->nitems] )->parent = menu;
- menu->nitems++;
- }
-
- menu->nslots = Menu_TallySlots( menu );
-}
-
-/*
-** Menu_AdjustCursor
-**
-** This function takes the given menu, the direction, and attempts
-** to adjust the menu's cursor so that it's at the next available
-** slot.
-*/
-void Menu_AdjustCursor( menuframework_s *m, int dir )
-{
- menucommon_s *citem;
-
- /*
- ** see if it's in a valid spot
- */
- if ( m->cursor >= 0 && m->cursor < m->nitems )
- {
- if ( ( citem = Menu_ItemAtCursor( m ) ) != 0 )
- {
- if ( citem->type != MTYPE_SEPARATOR )
- return;
- }
- }
-
- /*
- ** it's not in a valid spot, so crawl in the direction indicated until we
- ** find a valid spot
- */
- if ( dir == 1 )
- {
- while ( 1 )
- {
- citem = Menu_ItemAtCursor( m );
- if ( citem )
- if ( citem->type != MTYPE_SEPARATOR )
- break;
- m->cursor += dir;
- if ( m->cursor >= m->nitems )
- m->cursor = 0;
- }
- }
- else
- {
- while ( 1 )
- {
- citem = Menu_ItemAtCursor( m );
- if ( citem )
- if ( citem->type != MTYPE_SEPARATOR )
- break;
- m->cursor += dir;
- if ( m->cursor < 0 )
- m->cursor = m->nitems - 1;
- }
- }
-}
-
-void Menu_Center( menuframework_s *menu )
-{
- int height;
-
- height = ( ( menucommon_s * ) menu->items[menu->nitems-1])->y;
- height += 10;
-
- menu->y = ( vid.height - height ) / 2;
-}
-
-void Menu_Draw( menuframework_s *menu )
-{
- int i;
- menucommon_s *item;
-
- /*
- ** draw contents
- */
- for ( i = 0; i < menu->nitems; i++ )
- {
- switch ( ( ( menucommon_s * ) menu->items[i] )->type )
- {
- case MTYPE_FIELD:
- Field_Draw( ( menufield_s * ) menu->items[i] );
- break;
- case MTYPE_SLIDER:
- Slider_Draw( ( menuslider_s * ) menu->items[i] );
- break;
- case MTYPE_LIST:
- MenuList_Draw( ( menulist_s * ) menu->items[i] );
- break;
- case MTYPE_SPINCONTROL:
- SpinControl_Draw( ( menulist_s * ) menu->items[i] );
- break;
- case MTYPE_ACTION:
- Action_Draw( ( menuaction_s * ) menu->items[i] );
- break;
- case MTYPE_SEPARATOR:
- Separator_Draw( ( menuseparator_s * ) menu->items[i] );
- break;
- }
- }
-
- item = Menu_ItemAtCursor( menu );
-
- if ( item && item->cursordraw )
- {
- item->cursordraw( item );
- }
- else if ( menu->cursordraw )
- {
- menu->cursordraw( menu );
- }
- else if ( item && item->type != MTYPE_FIELD )
- {
- if ( item->flags & QMF_LEFT_JUSTIFY )
- {
- Draw_Char( menu->x + item->x - 24 + item->cursor_offset, menu->y + item->y, 12 + ( ( int ) ( Sys_Milliseconds()/250 ) & 1 ) );
- }
- else
- {
- Draw_Char( menu->x + item->cursor_offset, menu->y + item->y, 12 + ( ( int ) ( Sys_Milliseconds()/250 ) & 1 ) );
- }
- }
-
- if ( item )
- {
- if ( item->statusbarfunc )
- item->statusbarfunc( ( void * ) item );
- else if ( item->statusbar )
- Menu_DrawStatusBar( item->statusbar );
- else
- Menu_DrawStatusBar( menu->statusbar );
-
- }
- else
- {
- Menu_DrawStatusBar( menu->statusbar );
- }
-}
-
-void Menu_DrawStatusBar( const char *string )
-{
- if ( string )
- {
- int l = strlen( string );
- //int maxrow = vid.height / 8;
- int maxcol = vid.width / 8;
- int col = maxcol / 2 - l / 2;
-
- Draw_Fill( 0, vid.height-8, vid.width, 8, 4 );
- Menu_DrawString( col*8, vid.height - 8, string );
- }
- else
- {
- Draw_Fill( 0, vid.height-8, vid.width, 8, 0 );
- }
-}
-
-void Menu_DrawString( int x, int y, const char *string )
-{
- unsigned i;
-
- for ( i = 0; i < strlen( string ); i++ )
- {
- Draw_Char( ( x + i*8 ), y, string[i] );
- }
-}
-
-void Menu_DrawStringDark( int x, int y, const char *string )
-{
- unsigned i;
-
- for ( i = 0; i < strlen( string ); i++ )
- {
- Draw_Char( ( x + i*8 ), y, string[i] + 128 );
- }
-}
-
-void Menu_DrawStringR2L( int x, int y, const char *string )
-{
- unsigned i;
-
- for ( i = 0; i < strlen( string ); i++ )
- {
- Draw_Char( ( x - i*8 ), y, string[strlen(string)-i-1] );
- }
-}
-
-void Menu_DrawStringR2LDark( int x, int y, const char *string )
-{
- unsigned i;
-
- for ( i = 0; i < strlen( string ); i++ )
- {
- Draw_Char( ( x - i*8 ), y, string[strlen(string)-i-1]+128 );
- }
-}
-
-void *Menu_ItemAtCursor( menuframework_s *m )
-{
- if ( m->cursor < 0 || m->cursor >= m->nitems )
- return 0;
-
- return m->items[m->cursor];
-}
-
-qboolean Menu_SelectItem( menuframework_s *s )
-{
- menucommon_s *item = ( menucommon_s * ) Menu_ItemAtCursor( s );
-
- if ( item )
- {
- switch ( item->type )
- {
- case MTYPE_FIELD:
- return Field_DoEnter( ( menufield_s * ) item ) ;
- case MTYPE_ACTION:
- Action_DoEnter( ( menuaction_s * ) item );
- return true;
- case MTYPE_LIST:
-// Menulist_DoEnter( ( menulist_s * ) item );
- return false;
- case MTYPE_SPINCONTROL:
-// SpinControl_DoEnter( ( menulist_s * ) item );
- return false;
- }
- }
- return false;
-}
-
-void Menu_SetStatusBar( menuframework_s *m, const char *string )
-{
- m->statusbar = string;
-}
-
-void Menu_SlideItem( menuframework_s *s, int dir )
-{
- menucommon_s *item = ( menucommon_s * ) Menu_ItemAtCursor( s );
-
- if ( item )
- {
- switch ( item->type )
- {
- case MTYPE_SLIDER:
- Slider_DoSlide( ( menuslider_s * ) item, dir );
- break;
- case MTYPE_SPINCONTROL:
- SpinControl_DoSlide( ( menulist_s * ) item, dir );
- break;
- }
- }
-}
-
-int Menu_TallySlots( menuframework_s *menu )
-{
- int i;
- int total = 0;
-
- for ( i = 0; i < menu->nitems; i++ )
- {
- if ( ( ( menucommon_s * ) menu->items[i] )->type == MTYPE_LIST )
- {
- int nitems = 0;
- const char **n = ( ( menulist_s * ) menu->items[i] )->itemnames;
-
- while (*n)
- nitems++, n++;
-
- total += nitems;
- }
- else
- {
- total++;
- }
- }
-
- return total;
-}
-
-void Menulist_DoEnter( menulist_s *l )
-{
- int start;
-
- start = l->generic.y / 10 + 1;
-
- l->curvalue = l->generic.parent->cursor - start;
-
- if ( l->generic.callback )
- l->generic.callback( l );
-}
-
-void MenuList_Draw( menulist_s *l )
-{
- const char **n;
- int y = 0;
-
- Menu_DrawStringR2LDark( l->generic.x + l->generic.parent->x + LCOLUMN_OFFSET, l->generic.y + l->generic.parent->y, l->generic.name );
-
- n = l->itemnames;
-
- Draw_Fill( l->generic.x - 112 + l->generic.parent->x, l->generic.parent->y + l->generic.y + l->curvalue*10 + 10, 128, 10, 16 );
- while ( *n )
- {
- Menu_DrawStringR2LDark( l->generic.x + l->generic.parent->x + LCOLUMN_OFFSET, l->generic.y + l->generic.parent->y + y + 10, *n );
-
- n++;
- y += 10;
- }
-}
-
-void Separator_Draw( menuseparator_s *s )
-{
- if ( s->generic.name )
- Menu_DrawStringR2LDark( s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y, s->generic.name );
-}
-
-void Slider_DoSlide( menuslider_s *s, int dir )
-{
- s->curvalue += dir;
-
- if ( s->curvalue > s->maxvalue )
- s->curvalue = s->maxvalue;
- else if ( s->curvalue < s->minvalue )
- s->curvalue = s->minvalue;
-
- if ( s->generic.callback )
- s->generic.callback( s );
-}
-
-#define SLIDER_RANGE 10
-
-void Slider_Draw( menuslider_s *s )
-{
- int i;
-
- Menu_DrawStringR2LDark( s->generic.x + s->generic.parent->x + LCOLUMN_OFFSET,
- s->generic.y + s->generic.parent->y,
- s->generic.name );
-
- s->range = ( s->curvalue - s->minvalue ) / ( float ) ( s->maxvalue - s->minvalue );
-
- if ( s->range < 0)
- s->range = 0;
- if ( s->range > 1)
- s->range = 1;
- Draw_Char( s->generic.x + s->generic.parent->x + RCOLUMN_OFFSET, s->generic.y + s->generic.parent->y, 128);
- for ( i = 0; i < SLIDER_RANGE; i++ )
- Draw_Char( RCOLUMN_OFFSET + s->generic.x + i*8 + s->generic.parent->x + 8, s->generic.y + s->generic.parent->y, 129);
- Draw_Char( RCOLUMN_OFFSET + s->generic.x + i*8 + s->generic.parent->x + 8, s->generic.y + s->generic.parent->y, 130);
- Draw_Char( ( int ) ( 8 + RCOLUMN_OFFSET + s->generic.parent->x + s->generic.x + (SLIDER_RANGE-1)*8 * s->range ), s->generic.y + s->generic.parent->y, 131);
-}
-
-void SpinControl_DoEnter( menulist_s *s )
-{
- s->curvalue++;
- if ( s->itemnames[s->curvalue] == 0 )
- s->curvalue = 0;
-
- if ( s->generic.callback )
- s->generic.callback( s );
-}
-
-void SpinControl_DoSlide( menulist_s *s, int dir )
-{
- s->curvalue += dir;
-
- if ( s->curvalue < 0 )
- s->curvalue = 0;
- else if ( s->itemnames[s->curvalue] == 0 )
- s->curvalue--;
-
- if ( s->generic.callback )
- s->generic.callback( s );
-}
-
-void SpinControl_Draw( menulist_s *s )
-{
- char buffer[100];
-
- if ( s->generic.name )
- {
- Menu_DrawStringR2LDark( s->generic.x + s->generic.parent->x + LCOLUMN_OFFSET,
- s->generic.y + s->generic.parent->y,
- s->generic.name );
- }
- if ( !strchr( s->itemnames[s->curvalue], '\n' ) )
- {
- Menu_DrawString( RCOLUMN_OFFSET + s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y, s->itemnames[s->curvalue] );
- }
- else
- {
- strcpy( buffer, s->itemnames[s->curvalue] );
- *strchr( buffer, '\n' ) = 0;
- Menu_DrawString( RCOLUMN_OFFSET + s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y, buffer );
- strcpy( buffer, strchr( s->itemnames[s->curvalue], '\n' ) + 1 );
- Menu_DrawString( RCOLUMN_OFFSET + s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y + 10, buffer );
- }
-}
-
--- a/client/qmenu.h
+++ /dev/null
@@ -1,108 +1,0 @@
-#ifndef __QMENU_H__
-#define __QMENU_H__
-
-#define MAXMENUITEMS 64
-
-#define MTYPE_SLIDER 0
-#define MTYPE_LIST 1
-#define MTYPE_ACTION 2
-#define MTYPE_SPINCONTROL 3
-#define MTYPE_SEPARATOR 4
-#define MTYPE_FIELD 5
-
-#define QMF_LEFT_JUSTIFY 0x00000001
-#define QMF_GRAYED 0x00000002
-#define QMF_NUMBERSONLY 0x00000004
-
-typedef struct _tag_menuframework
-{
- int x, y;
- int cursor;
-
- int nitems;
- int nslots;
- void *items[64];
-
- const char *statusbar;
-
- void (*cursordraw)( struct _tag_menuframework *m );
-
-} menuframework_s;
-
-typedef struct
-{
- int type;
- const char *name;
- int x, y;
- menuframework_s *parent;
- int cursor_offset;
- int localdata[4];
- unsigned flags;
-
- const char *statusbar;
-
- void (*callback)( void *self );
- void (*statusbarfunc)( void *self );
- void (*ownerdraw)( void *self );
- void (*cursordraw)( void *self );
-} menucommon_s;
-
-typedef struct
-{
- menucommon_s generic;
-
- char buffer[80];
- int cursor;
- int length;
- int visible_length;
- int visible_offset;
-} menufield_s;
-
-typedef struct
-{
- menucommon_s generic;
-
- float minvalue;
- float maxvalue;
- float curvalue;
-
- float range;
-} menuslider_s;
-
-typedef struct
-{
- menucommon_s generic;
-
- int curvalue;
-
- const char **itemnames;
-} menulist_s;
-
-typedef struct
-{
- menucommon_s generic;
-} menuaction_s;
-
-typedef struct
-{
- menucommon_s generic;
-} menuseparator_s;
-
-qboolean Field_Key( menufield_s *field, int key );
-
-void Menu_AddItem( menuframework_s *menu, void *item );
-void Menu_AdjustCursor( menuframework_s *menu, int dir );
-void Menu_Center( menuframework_s *menu );
-void Menu_Draw( menuframework_s *menu );
-void *Menu_ItemAtCursor( menuframework_s *m );
-qboolean Menu_SelectItem( menuframework_s *s );
-void Menu_SetStatusBar( menuframework_s *s, const char *string );
-void Menu_SlideItem( menuframework_s *s, int dir );
-int Menu_TallySlots( menuframework_s *menu );
-
-void Menu_DrawString( int, int, const char * );
-void Menu_DrawStringDark( int, int, const char * );
-void Menu_DrawStringR2L( int, int, const char * );
-void Menu_DrawStringR2LDark( int, int, const char * );
-
-#endif
--- a/client/ref.h
+++ /dev/null
@@ -1,205 +1,0 @@
-#define MAX_DLIGHTS 32
-#define MAX_ENTITIES 128
-#define MAX_PARTICLES 4096
-//#define MAX_LIGHTSTYLES 256 /* macro redifinition */
-
-#define POWERSUIT_SCALE 4.0F
-
-#define SHELL_RED_COLOR 0xF2
-#define SHELL_GREEN_COLOR 0xD0
-#define SHELL_BLUE_COLOR 0xF3
-
-#define SHELL_RG_COLOR 0xDC
-//#define SHELL_RB_COLOR 0x86
-#define SHELL_RB_COLOR 0x68
-#define SHELL_BG_COLOR 0x78
-
-//ROGUE
-#define SHELL_DOUBLE_COLOR 0xDF // 223
-#define SHELL_HALF_DAM_COLOR 0x90
-#define SHELL_CYAN_COLOR 0x72
-//ROGUE
-
-#define SHELL_WHITE_COLOR 0xD7
-
-typedef struct entity_s
-{
- struct model_s *model; // opaque type outside refresh
- float angles[3];
-
- /*
- ** most recent data
- */
- float origin[3]; // also used as RF_BEAM's "from"
- int frame; // also used as RF_BEAM's diameter
-
- /*
- ** previous data for lerping
- */
- float oldorigin[3]; // also used as RF_BEAM's "to"
- int oldframe;
-
- /*
- ** misc
- */
- float backlerp; // 0.0 = current, 1.0 = old
- int skinnum; // also used as RF_BEAM's palette index
-
- int lightstyle; // for flashing entities
- float alpha; // ignore if RF_TRANSLUCENT isn't set
-
- struct image_s *skin; // NULL for inline skin
- int flags;
-
-} entity_t;
-
-#define ENTITY_FLAGS 68
-
-typedef struct
-{
- vec3_t origin;
- vec3_t color;
- float intensity;
-} dlight_t;
-
-typedef struct
-{
- vec3_t origin;
- int color;
- float alpha;
-} particle_t;
-
-typedef struct
-{
- float rgb[3]; // 0.0 - 2.0
- float white; // highest of rgb
-} lightstyle_t;
-
-typedef struct
-{
- int x, y, width, height;// in virtual screen coordinates
- float fov_x, fov_y;
- float vieworg[3];
- float viewangles[3];
- float blend[4]; // rgba 0-1 full screen blend
- float time; // time is uesed to auto animate
- int rdflags; // RDF_UNDERWATER, etc
-
- byte *areabits; // if not NULL, only areas with set bits will be drawn
-
- lightstyle_t *lightstyles; // [MAX_LIGHTSTYLES]
-
- int num_entities;
- entity_t *entities;
-
- int num_dlights;
- dlight_t *dlights;
-
- int num_particles;
- particle_t *particles;
-} refdef_t;
-
-
-
-#define API_VERSION 3
-
-//
-// these are the functions exported by the refresh module
-//
-typedef struct
-{
- // if api_version is different, the dll cannot be used
- int api_version;
-
- // called when the library is loaded
- qboolean (*Init) ( void *hinstance, void *wndproc );
-
- // called before the library is unloaded
- void (*Shutdown) (void);
-
- // All data that will be used in a level should be
- // registered before rendering any frames to prevent disk hits,
- // but they can still be registered at a later time
- // if necessary.
- //
- // EndRegistration will free any remaining data that wasn't registered.
- // Any model_s or skin_s pointers from before the BeginRegistration
- // are no longer valid after EndRegistration.
- //
- // Skins and images need to be differentiated, because skins
- // are flood filled to eliminate mip map edge errors, and pics have
- // an implicit "pics/" prepended to the name. (a pic name that starts with a
- // slash will not use the "pics/" prefix or the ".pcx" postfix)
- void (*BeginRegistration) (char *map);
- struct model_s *(*RegisterModel) (char *name);
- struct image_s *(*RegisterSkin) (char *name);
- struct image_s *(*RegisterPic) (char *name);
- void (*SetSky) (char *name, float rotate, vec3_t axis);
- void (*EndRegistration) (void);
-
- void (*RenderFrame) (refdef_t *fd);
-
- void (*DrawGetPicSize) (int *w, int *h, char *name); // will return 0 0 if not found
- void (*DrawPic) (int x, int y, char *name);
- void (*DrawStretchPic) (int x, int y, int w, int h, char *name);
- void (*DrawChar) (int x, int y, int c);
- void (*DrawTileClear) (int x, int y, int w, int h, char *name);
- void (*DrawFill) (int x, int y, int w, int h, int c);
- void (*DrawFadeScreen) (void);
-
- // Draw images for cinematic rendering (which can have a different palette). Note that calls
- void (*DrawStretchRaw) (int x, int y, int w, int h, int cols, int rows, byte *data);
-
- /*
- ** video mode and refresh state management entry points
- */
- void (*CinematicSetPalette)( const unsigned char *palette); // NULL = game palette
- void (*BeginFrame)( float camera_separation );
- void (*EndFrame) (void);
-
- void (*AppActivate)( qboolean activate );
-
-} refexport_t;
-
-//
-// these are the functions imported by the refresh module
-//
-typedef struct
-{
- void (*Sys_Error) (int err_level, char *str, ...);
-
- void (*Cmd_AddCommand) (char *name, void(*cmd)(void));
- void (*Cmd_RemoveCommand) (char *name);
- int (*Cmd_Argc) (void);
- char *(*Cmd_Argv) (int i);
- void (*Cmd_ExecuteText) (int exec_when, char *text);
-
- void (*Con_Printf) (int print_level, char *str, ...);
-
- // files will be memory mapped read only
- // the returned buffer may be part of a larger pak file,
- // or a discrete file from anywhere in the quake search path
- // a -1 return means the file does not exist
- // NULL can be passed for buf to just determine existance
- int (*FS_LoadFile) (char *name, void **buf);
- void (*FS_FreeFile) (void *buf);
-
- // gamedir will be the current directory that generated
- // files should be stored to, ie: "f:\quake\id1"
- char *(*FS_Gamedir) (void);
-
- cvar_t *(*Cvar_Get) (char *name, char *value, int flags);
- cvar_t *(*Cvar_Set)( char *name, char *value );
- void (*Cvar_SetValue)( char *name, float value );
-
- qboolean (*Vid_GetModeInfo)( int *width, int *height, int mode );
- void (*Vid_MenuInit)( void );
- void (*Vid_NewWindow)( int width, int height );
-} refimport_t;
-
-
-// this is the only function actually exported at the linker level
-typedef refexport_t (*GetRefAPI_t) (refimport_t);
-
-extern cvar_t *vid_fullscreen;
-extern cvar_t *vid_gamma;
--- a/client/screen.h
+++ /dev/null
@@ -1,41 +1,0 @@
-void SCR_Init (void);
-
-void SCR_UpdateScreen (void);
-
-void SCR_SizeUp (void);
-void SCR_SizeDown (void);
-void SCR_CenterPrint (char *str);
-void SCR_BeginLoadingPlaque (void);
-void SCR_EndLoadingPlaque (void);
-
-void SCR_DebugGraph (float value, int color);
-
-void SCR_TouchPics (void);
-
-void SCR_RunConsole (void);
-
-extern float scr_con_current;
-extern float scr_conlines; // lines of console to display
-
-extern int sb_lines;
-
-extern cvar_t *scr_viewsize;
-extern cvar_t *crosshair;
-
-extern vrect_t scr_vrect; // position of render window
-
-extern char crosshair_pic[MAX_QPATH];
-extern int crosshair_width, crosshair_height;
-
-void SCR_AddDirtyPoint (int x, int y);
-void SCR_DirtyScreen (void);
-
-//
-// scr_cin.c
-//
-void SCR_PlayCinematic (char *name);
-qboolean SCR_DrawCinematic (void);
-void SCR_RunCinematic (void);
-void SCR_StopCinematic (void);
-void SCR_FinishCinematic (void);
-
--- a/client/snd_dma.c
+++ /dev/null
@@ -1,1194 +1,0 @@
-// snd_dma.c -- main control for any streaming sound output device
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-void S_Play(void);
-void S_SoundList(void);
-void S_Update_(void);
-void S_StopAllSounds(void);
-
-
-// =======================================================================
-// Internal sound data & structures
-// =======================================================================
-
-// only begin attenuating sound volumes when outside the FULLVOLUME range
-#define SOUND_FULLVOLUME 80
-
-#define SOUND_LOOPATTENUATE 0.003
-
-int s_registration_sequence;
-
-channel_t channels[MAX_CHANNELS];
-
-qboolean snd_initialized = false;
-int sound_started=0;
-
-dma_t dma;
-
-vec3_t listener_origin;
-vec3_t listener_forward;
-vec3_t listener_right;
-vec3_t listener_up;
-
-qboolean s_registering;
-
-int soundtime; // sample PAIRS
-int paintedtime; // sample PAIRS
-
-// during registration it is possible to have more sounds
-// than could actually be referenced during gameplay,
-// because we don't want to free anything until we are
-// sure we won't need it.
-#define MAX_SFX (MAX_SOUNDS*2)
-sfx_t known_sfx[MAX_SFX];
-int num_sfx;
-
-#define MAX_PLAYSOUNDS 128
-playsound_t s_playsounds[MAX_PLAYSOUNDS];
-playsound_t s_freeplays;
-playsound_t s_pendingplays;
-
-int s_beginofs;
-
-cvar_t *s_volume;
-cvar_t *s_testsound;
-cvar_t *s_loadas8bit;
-cvar_t *s_khz;
-cvar_t *s_show;
-cvar_t *s_mixahead;
-cvar_t *s_primary;
-
-
-int s_rawend;
-portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
-
-
-// ====================================================================
-// User-setable variables
-// ====================================================================
-
-
-void S_SoundInfo_f(void)
-{
- if (!sound_started)
- {
- Com_Printf ("sound system not started\n");
- return;
- }
-
- Com_Printf("%5d stereo\n", dma.channels - 1);
- Com_Printf("%5d samples\n", dma.samples);
- Com_Printf("%5d samplepos\n", dma.samplepos);
- Com_Printf("%5d samplebits\n", dma.samplebits);
- Com_Printf("%5d submission_chunk\n", dma.submission_chunk);
- Com_Printf("%5d speed\n", dma.speed);
- Com_Printf("0x%x dma buffer\n", dma.buffer);
-}
-
-
-
-/*
-================
-S_Init
-================
-*/
-void S_Init (void)
-{
- cvar_t *cv;
-
- Com_Printf("\n------- sound initialization -------\n");
-
- cv = Cvar_Get ("s_initsound", "1", 0);
- if (!cv->value)
- Com_Printf ("not initializing.\n");
- else
- {
- s_volume = Cvar_Get ("s_volume", "0.7", CVAR_ARCHIVE);
- s_khz = Cvar_Get ("s_khz", "11", CVAR_ARCHIVE);
- s_loadas8bit = Cvar_Get ("s_loadas8bit", "1", CVAR_ARCHIVE);
- s_mixahead = Cvar_Get ("s_mixahead", "0.2", CVAR_ARCHIVE);
- s_show = Cvar_Get ("s_show", "0", 0);
- s_testsound = Cvar_Get ("s_testsound", "0", 0);
- s_primary = Cvar_Get ("s_primary", "0", CVAR_ARCHIVE); // win32 specific
-
- Cmd_AddCommand("play", S_Play);
- Cmd_AddCommand("stopsound", S_StopAllSounds);
- Cmd_AddCommand("soundlist", S_SoundList);
- Cmd_AddCommand("soundinfo", S_SoundInfo_f);
-
- if (!SNDDMA_Init())
- return;
-
- S_InitScaletable ();
-
- sound_started = 1;
- num_sfx = 0;
-
- soundtime = 0;
- paintedtime = 0;
-
- Com_Printf ("sound sampling rate: %i\n", dma.speed);
-
- S_StopAllSounds ();
- }
-
- Com_Printf("------------------------------------\n");
-}
-
-
-// =======================================================================
-// Shutdown sound engine
-// =======================================================================
-
-void S_Shutdown(void)
-{
- int i;
- sfx_t *sfx;
-
- if (!sound_started)
- return;
-
- SNDDMA_Shutdown();
-
- sound_started = 0;
-
- Cmd_RemoveCommand("play");
- Cmd_RemoveCommand("stopsound");
- Cmd_RemoveCommand("soundlist");
- Cmd_RemoveCommand("soundinfo");
-
- // free all sounds
- for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
- {
- if (!sfx->name[0])
- continue;
- if (sfx->cache)
- Z_Free (sfx->cache);
- memset (sfx, 0, sizeof(*sfx));
- }
-
- num_sfx = 0;
-}
-
-
-// =======================================================================
-// Load a sound
-// =======================================================================
-
-/*
-==================
-S_FindName
-
-==================
-*/
-sfx_t *S_FindName (char *name, qboolean create)
-{
- int i;
- sfx_t *sfx;
-
- if (!name)
- Com_Error (ERR_FATAL, "S_FindName: NULL\n");
- if (!name[0])
- Com_Error (ERR_FATAL, "S_FindName: empty name\n");
-
- if (strlen(name) >= MAX_QPATH)
- Com_Error (ERR_FATAL, "Sound name too long: %s", name);
-
- // see if already loaded
- for (i=0 ; i < num_sfx ; i++)
- if (!strcmp(known_sfx[i].name, name))
- {
- return &known_sfx[i];
- }
-
- if (!create)
- return NULL;
-
- // find a free sfx
- for (i=0 ; i < num_sfx ; i++)
- if (!known_sfx[i].name[0])
-// registration_sequence < s_registration_sequence)
- break;
-
- if (i == num_sfx)
- {
- if (num_sfx == MAX_SFX)
- Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
- num_sfx++;
- }
-
- sfx = &known_sfx[i];
- memset (sfx, 0, sizeof(*sfx));
- strcpy (sfx->name, name);
- sfx->registration_sequence = s_registration_sequence;
-
- return sfx;
-}
-
-
-/*
-==================
-S_AliasName
-
-==================
-*/
-sfx_t *S_AliasName (char *aliasname, char *truename)
-{
- sfx_t *sfx;
- char *s;
- int i;
-
- s = Z_Malloc (MAX_QPATH);
- strcpy (s, truename);
-
- // find a free sfx
- for (i=0 ; i < num_sfx ; i++)
- if (!known_sfx[i].name[0])
- break;
-
- if (i == num_sfx)
- {
- if (num_sfx == MAX_SFX)
- Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
- num_sfx++;
- }
-
- sfx = &known_sfx[i];
- memset (sfx, 0, sizeof(*sfx));
- strcpy (sfx->name, aliasname);
- sfx->registration_sequence = s_registration_sequence;
- sfx->truename = s;
-
- return sfx;
-}
-
-
-/*
-=====================
-S_BeginRegistration
-
-=====================
-*/
-void S_BeginRegistration (void)
-{
- s_registration_sequence++;
- s_registering = true;
-}
-
-/*
-==================
-S_RegisterSound
-
-==================
-*/
-sfx_t *S_RegisterSound (char *name)
-{
- sfx_t *sfx;
-
- if (!sound_started)
- return NULL;
-
- sfx = S_FindName (name, true);
- sfx->registration_sequence = s_registration_sequence;
-
- if (!s_registering)
- S_LoadSound (sfx);
-
- return sfx;
-}
-
-
-/*
-=====================
-S_EndRegistration
-
-=====================
-*/
-void S_EndRegistration (void)
-{
- int i;
- sfx_t *sfx;
- int size;
-
- // free any sounds not from this registration sequence
- for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
- {
- if (!sfx->name[0])
- continue;
- if (sfx->registration_sequence != s_registration_sequence)
- { // don't need this sound
- if (sfx->cache) // it is possible to have a leftover
- Z_Free (sfx->cache); // from a server that didn't finish loading
- memset (sfx, 0, sizeof(*sfx));
- }
- else
- { // make sure it is paged in
- if (sfx->cache)
- {
- size = sfx->cache->length*sfx->cache->width;
- Com_PageInMemory ((byte *)sfx->cache, size);
- }
- }
-
- }
-
- // load everything in
- for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
- {
- if (!sfx->name[0])
- continue;
- S_LoadSound (sfx);
- }
-
- s_registering = false;
-}
-
-
-//=============================================================================
-
-/*
-=================
-S_PickChannel
-=================
-*/
-channel_t *S_PickChannel(int entnum, int entchannel)
-{
- int ch_idx;
- int first_to_die;
- int life_left;
- channel_t *ch;
-
- if (entchannel<0)
- Com_Error (ERR_DROP, "S_PickChannel: entchannel<0");
-
-// Check for replacement sound, or find the best one to replace
- first_to_die = -1;
- life_left = 0x7fffffff;
- for (ch_idx=0 ; ch_idx < MAX_CHANNELS ; ch_idx++)
- {
- if (entchannel != 0 // channel 0 never overrides
- && channels[ch_idx].entnum == entnum
- && channels[ch_idx].entchannel == entchannel)
- { // always override sound from same entity
- first_to_die = ch_idx;
- break;
- }
-
- // don't let monster sounds override player sounds
- if (channels[ch_idx].entnum == cl.playernum+1 && entnum != cl.playernum+1 && channels[ch_idx].sfx)
- continue;
-
- if (channels[ch_idx].end - paintedtime < life_left)
- {
- life_left = channels[ch_idx].end - paintedtime;
- first_to_die = ch_idx;
- }
- }
-
- if (first_to_die == -1)
- return NULL;
-
- ch = &channels[first_to_die];
- memset (ch, 0, sizeof(*ch));
-
- return ch;
-}
-
-/*
-=================
-S_SpatializeOrigin
-
-Used for spatializing channels and autosounds
-=================
-*/
-void S_SpatializeOrigin (vec3_t origin, float master_vol, float dist_mult, int *left_vol, int *right_vol)
-{
- vec_t dot;
- vec_t dist;
- vec_t lscale, rscale, scale;
- vec3_t source_vec;
-
- if (cls.state != ca_active)
- {
- *left_vol = *right_vol = 255;
- return;
- }
-
-// calculate stereo seperation and distance attenuation
- VectorSubtract(origin, listener_origin, source_vec);
-
- dist = VectorNormalize(source_vec);
- dist -= SOUND_FULLVOLUME;
- if (dist < 0)
- dist = 0; // close enough to be at full volume
- dist *= dist_mult; // different attenuation levels
-
- dot = DotProduct(listener_right, source_vec);
-
- if (dma.channels == 1 || !dist_mult)
- { // no attenuation = no spatialization
- rscale = 1.0;
- lscale = 1.0;
- }
- else
- {
- rscale = 0.5 * (1.0 + dot);
- lscale = 0.5*(1.0 - dot);
- }
-
- // add in distance effect
- scale = (1.0 - dist) * rscale;
- *right_vol = (int) (master_vol * scale);
- if (*right_vol < 0)
- *right_vol = 0;
-
- scale = (1.0 - dist) * lscale;
- *left_vol = (int) (master_vol * scale);
- if (*left_vol < 0)
- *left_vol = 0;
-}
-
-/*
-=================
-S_Spatialize
-=================
-*/
-void S_Spatialize(channel_t *ch)
-{
- vec3_t origin;
-
- // anything coming from the view entity will always be full volume
- if (ch->entnum == cl.playernum+1)
- {
- ch->leftvol = ch->master_vol;
- ch->rightvol = ch->master_vol;
- return;
- }
-
- if (ch->fixed_origin)
- {
- VectorCopy (ch->origin, origin);
- }
- else
- CL_GetEntitySoundOrigin (ch->entnum, origin);
-
- S_SpatializeOrigin (origin, ch->master_vol, ch->dist_mult, &ch->leftvol, &ch->rightvol);
-}
-
-
-/*
-=================
-S_AllocPlaysound
-=================
-*/
-playsound_t *S_AllocPlaysound (void)
-{
- playsound_t *ps;
-
- ps = s_freeplays.next;
- if (ps == &s_freeplays)
- return NULL; // no free playsounds
-
- // unlink from freelist
- ps->prev->next = ps->next;
- ps->next->prev = ps->prev;
-
- return ps;
-}
-
-
-/*
-=================
-S_FreePlaysound
-=================
-*/
-void S_FreePlaysound (playsound_t *ps)
-{
- // unlink from channel
- ps->prev->next = ps->next;
- ps->next->prev = ps->prev;
-
- // add to free list
- ps->next = s_freeplays.next;
- s_freeplays.next->prev = ps;
- ps->prev = &s_freeplays;
- s_freeplays.next = ps;
-}
-
-
-
-/*
-===============
-S_IssuePlaysound
-
-Take the next playsound and begin it on the channel
-This is never called directly by S_Play*, but only
-by the update loop.
-===============
-*/
-void S_IssuePlaysound (playsound_t *ps)
-{
- channel_t *ch;
- sfxcache_t *sc;
-
- if (s_show->value)
- Com_Printf ("Issue %i\n", ps->begin);
- // pick a channel to play on
- ch = S_PickChannel(ps->entnum, ps->entchannel);
- if (!ch)
- {
- S_FreePlaysound (ps);
- return;
- }
-
- // spatialize
- if (ps->attenuation == ATTN_STATIC)
- ch->dist_mult = ps->attenuation * 0.001;
- else
- ch->dist_mult = ps->attenuation * 0.0005;
- ch->master_vol = ps->volume;
- ch->entnum = ps->entnum;
- ch->entchannel = ps->entchannel;
- ch->sfx = ps->sfx;
- VectorCopy (ps->origin, ch->origin);
- ch->fixed_origin = ps->fixed_origin;
-
- S_Spatialize(ch);
-
- ch->pos = 0;
- sc = S_LoadSound (ch->sfx);
- ch->end = paintedtime + sc->length;
-
- // free the playsound
- S_FreePlaysound (ps);
-}
-
-struct sfx_s *S_RegisterSexedSound (entity_state_t *ent, char *base)
-{
- int n;
- char *p;
- struct sfx_s *sfx;
- FILE *f;
- char model[MAX_QPATH];
- char sexedFilename[MAX_QPATH];
- char maleFilename[MAX_QPATH];
-
- // determine what model the client is using
- model[0] = 0;
- n = CS_PLAYERSKINS + ent->number - 1;
- if (cl.configstrings[n][0])
- {
- p = strchr(cl.configstrings[n], '\\');
- if (p)
- {
- p += 1;
- strcpy(model, p);
- p = strchr(model, '/');
- if (p)
- *p = 0;
- }
- }
- // if we can't figure it out, they're male
- if (!model[0])
- strcpy(model, "male");
-
- // see if we already know of the model specific sound
- Com_sprintf (sexedFilename, sizeof(sexedFilename), "#players/%s/%s", model, base+1);
- sfx = S_FindName (sexedFilename, false);
-
- if (!sfx)
- {
- // no, so see if it exists
- FS_FOpenFile (&sexedFilename[1], &f);
- if (f)
- {
- // yes, close the file and register it
- FS_FCloseFile (f);
- sfx = S_RegisterSound (sexedFilename);
- }
- else
- {
- // no, revert to the male sound in the pak0.pak
- Com_sprintf (maleFilename, sizeof(maleFilename), "player/%s/%s", "male", base+1);
- sfx = S_AliasName (sexedFilename, maleFilename);
- }
- }
-
- return sfx;
-}
-
-
-// =======================================================================
-// Start a sound effect
-// =======================================================================
-
-/*
-====================
-S_StartSound
-
-Validates the parms and ques the sound up
-if pos is NULL, the sound will be dynamically sourced from the entity
-Entchannel 0 will never override a playing sound
-====================
-*/
-void S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float timeofs)
-{
- sfxcache_t *sc;
- int vol;
- playsound_t *ps, *sort;
- int start;
-
- if (!sound_started)
- return;
-
- if (!sfx)
- return;
-
- if (sfx->name[0] == '*')
- sfx = S_RegisterSexedSound(&cl_entities[entnum].current, sfx->name);
-
- // make sure the sound is loaded
- sc = S_LoadSound (sfx);
- if (!sc)
- return; // couldn't load the sound's data
-
- vol = fvol*255;
-
- // make the playsound_t
- ps = S_AllocPlaysound ();
- if (!ps)
- return;
-
- if (origin)
- {
- VectorCopy (origin, ps->origin);
- ps->fixed_origin = true;
- }
- else
- ps->fixed_origin = false;
-
- ps->entnum = entnum;
- ps->entchannel = entchannel;
- ps->attenuation = attenuation;
- ps->volume = vol;
- ps->sfx = sfx;
-
- // drift s_beginofs
- start = cl.frame.servertime * 0.001 * dma.speed + s_beginofs;
- if (start < paintedtime)
- {
- start = paintedtime;
- s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed);
- }
- else if (start > paintedtime + 0.3 * dma.speed)
- {
- start = paintedtime + 0.1 * dma.speed;
- s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed);
- }
- else
- {
- s_beginofs-=10;
- }
-
- if (!timeofs)
- ps->begin = paintedtime;
- else
- ps->begin = start + timeofs * dma.speed;
-
- // sort into the pending sound list
- for (sort = s_pendingplays.next ;
- sort != &s_pendingplays && sort->begin < ps->begin ;
- sort = sort->next)
- ;
-
- ps->next = sort;
- ps->prev = sort->prev;
-
- ps->next->prev = ps;
- ps->prev->next = ps;
-}
-
-
-/*
-==================
-S_StartLocalSound
-==================
-*/
-void S_StartLocalSound (char *sound)
-{
- sfx_t *sfx;
-
- if (!sound_started)
- return;
-
- sfx = S_RegisterSound (sound);
- if (!sfx)
- {
- Com_Printf ("S_StartLocalSound: can't cache %s\n", sound);
- return;
- }
- S_StartSound (NULL, cl.playernum+1, 0, sfx, 1, 1, 0);
-}
-
-
-/*
-==================
-S_ClearBuffer
-==================
-*/
-void S_ClearBuffer (void)
-{
- int clear;
-
- if (!sound_started)
- return;
-
- s_rawend = 0;
-
- if (dma.samplebits == 8)
- clear = 0x80;
- else
- clear = 0;
-
- SNDDMA_BeginPainting ();
- if (dma.buffer)
- memset(dma.buffer, clear, dma.samples * dma.samplebits/8);
- SNDDMA_Submit ();
-}
-
-/*
-==================
-S_StopAllSounds
-==================
-*/
-void S_StopAllSounds(void)
-{
- int i;
-
- if (!sound_started)
- return;
-
- // clear all the playsounds
- memset(s_playsounds, 0, sizeof(s_playsounds));
- s_freeplays.next = s_freeplays.prev = &s_freeplays;
- s_pendingplays.next = s_pendingplays.prev = &s_pendingplays;
-
- for (i=0 ; i<MAX_PLAYSOUNDS ; i++)
- {
- s_playsounds[i].prev = &s_freeplays;
- s_playsounds[i].next = s_freeplays.next;
- s_playsounds[i].prev->next = &s_playsounds[i];
- s_playsounds[i].next->prev = &s_playsounds[i];
- }
-
- // clear all the channels
- memset(channels, 0, sizeof(channels));
-
- S_ClearBuffer ();
-}
-
-/*
-==================
-S_AddLoopSounds
-
-Entities with a ->sound field will generated looped sounds
-that are automatically started, stopped, and merged together
-as the entities are sent to the client
-==================
-*/
-void S_AddLoopSounds (void)
-{
- int i, j;
- int sounds[MAX_EDICTS];
- int left, right, left_total, right_total;
- channel_t *ch;
- sfx_t *sfx;
- sfxcache_t *sc;
- int num;
- entity_state_t *ent;
-
- if (cl_paused->value)
- return;
-
- if (cls.state != ca_active)
- return;
-
- if (!cl.sound_prepped)
- return;
-
- for (i=0 ; i<cl.frame.num_entities ; i++)
- {
- num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
- ent = &cl_parse_entities[num];
- sounds[i] = ent->sound;
- }
-
- for (i=0 ; i<cl.frame.num_entities ; i++)
- {
- if (!sounds[i])
- continue;
-
- sfx = cl.sound_precache[sounds[i]];
- if (!sfx)
- continue; // bad sound effect
- sc = sfx->cache;
- if (!sc)
- continue;
-
- num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
- ent = &cl_parse_entities[num];
-
- // find the total contribution of all sounds of this type
- S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE,
- &left_total, &right_total);
- for (j=i+1 ; j<cl.frame.num_entities ; j++)
- {
- if (sounds[j] != sounds[i])
- continue;
- sounds[j] = 0; // don't check this again later
-
- num = (cl.frame.parse_entities + j)&(MAX_PARSE_ENTITIES-1);
- ent = &cl_parse_entities[num];
-
- S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE,
- &left, &right);
- left_total += left;
- right_total += right;
- }
-
- if (left_total == 0 && right_total == 0)
- continue; // not audible
-
- // allocate a channel
- ch = S_PickChannel(0, 0);
- if (!ch)
- return;
-
- if (left_total > 255)
- left_total = 255;
- if (right_total > 255)
- right_total = 255;
- ch->leftvol = left_total;
- ch->rightvol = right_total;
- ch->autosound = true; // remove next frame
- ch->sfx = sfx;
- ch->pos = paintedtime % sc->length;
- ch->end = paintedtime + sc->length - ch->pos;
- }
-}
-
-//=============================================================================
-
-/*
-============
-S_RawSamples
-
-Cinematic streaming and voice over network
-============
-*/
-void S_RawSamples (int samples, int rate, int width, int channels, byte *data)
-{
- int i;
- int src, dst;
- float scale;
-
- if (!sound_started)
- return;
-
- if (s_rawend < paintedtime)
- s_rawend = paintedtime;
- scale = (float)rate / dma.speed;
-
-//Com_Printf ("%i < %i < %i\n", soundtime, paintedtime, s_rawend);
- if (channels == 2 && width == 2)
- {
- if (scale == 1.0)
- { // optimized case
- for (i=0 ; i<samples ; i++)
- {
- dst = s_rawend&(MAX_RAW_SAMPLES-1);
- s_rawend++;
- s_rawsamples[dst].left =
- LittleShort(((short *)data)[i*2]) << 8;
- s_rawsamples[dst].right =
- LittleShort(((short *)data)[i*2+1]) << 8;
- }
- }
- else
- {
- for (i=0 ; ; i++)
- {
- src = i*scale;
- if (src >= samples)
- break;
- dst = s_rawend&(MAX_RAW_SAMPLES-1);
- s_rawend++;
- s_rawsamples[dst].left =
- LittleShort(((short *)data)[src*2]) << 8;
- s_rawsamples[dst].right =
- LittleShort(((short *)data)[src*2+1]) << 8;
- }
- }
- }
- else if (channels == 1 && width == 2)
- {
- for (i=0 ; ; i++)
- {
- src = i*scale;
- if (src >= samples)
- break;
- dst = s_rawend&(MAX_RAW_SAMPLES-1);
- s_rawend++;
- s_rawsamples[dst].left =
- LittleShort(((short *)data)[src]) << 8;
- s_rawsamples[dst].right =
- LittleShort(((short *)data)[src]) << 8;
- }
- }
- else if (channels == 2 && width == 1)
- {
- for (i=0 ; ; i++)
- {
- src = i*scale;
- if (src >= samples)
- break;
- dst = s_rawend&(MAX_RAW_SAMPLES-1);
- s_rawend++;
- s_rawsamples[dst].left =
- ((char *)data)[src*2] << 16;
- s_rawsamples[dst].right =
- ((char *)data)[src*2+1] << 16;
- }
- }
- else if (channels == 1 && width == 1)
- {
- for (i=0 ; ; i++)
- {
- src = i*scale;
- if (src >= samples)
- break;
- dst = s_rawend&(MAX_RAW_SAMPLES-1);
- s_rawend++;
- s_rawsamples[dst].left =
- (((byte *)data)[src]-128) << 16;
- s_rawsamples[dst].right = (((byte *)data)[src]-128) << 16;
- }
- }
-}
-
-//=============================================================================
-
-/*
-============
-S_Update
-
-Called once each time through the main loop
-============
-*/
-void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
-{
- int i;
- int total;
- channel_t *ch;
-
- if (!sound_started)
- return;
-
- // if the laoding plaque is up, clear everything
- // out to make sure we aren't looping a dirty
- // dma buffer while loading
- if (cls.disable_screen)
- {
- S_ClearBuffer ();
- return;
- }
-
- // rebuild scale tables if volume is modified
- if (s_volume->modified)
- S_InitScaletable ();
-
- VectorCopy(origin, listener_origin);
- VectorCopy(forward, listener_forward);
- VectorCopy(right, listener_right);
- VectorCopy(up, listener_up);
-
- // update spatialization for dynamic sounds
- ch = channels;
- for (i=0 ; i<MAX_CHANNELS; i++, ch++)
- {
- if (!ch->sfx)
- continue;
- if (ch->autosound)
- { // autosounds are regenerated fresh each frame
- memset (ch, 0, sizeof(*ch));
- continue;
- }
- S_Spatialize(ch); // respatialize channel
- if (!ch->leftvol && !ch->rightvol)
- {
- memset (ch, 0, sizeof(*ch));
- continue;
- }
- }
-
- // add loopsounds
- S_AddLoopSounds ();
-
- //
- // debugging output
- //
- if (s_show->value)
- {
- total = 0;
- ch = channels;
- for (i=0 ; i<MAX_CHANNELS; i++, ch++)
- if (ch->sfx && (ch->leftvol || ch->rightvol) )
- {
- Com_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);
- total++;
- }
-
- Com_Printf ("----(%i)---- painted: %i\n", total, paintedtime);
- }
-
-// mix some sound
- S_Update_();
-}
-
-void GetSoundtime(void)
-{
- int samplepos;
- static int buffers;
- static int oldsamplepos;
- int fullsamples;
-
- fullsamples = dma.samples / dma.channels;
-
-// it is possible to miscount buffers if it has wrapped twice between
-// calls to S_Update. Oh well.
- samplepos = SNDDMA_GetDMAPos();
-
- if (samplepos < oldsamplepos)
- {
- buffers++; // buffer wrapped
-
- if (paintedtime > 0x40000000)
- { // time to chop things off to avoid 32 bit limits
- buffers = 0;
- paintedtime = fullsamples;
- S_StopAllSounds ();
- }
- }
- oldsamplepos = samplepos;
-
- soundtime = buffers*fullsamples + samplepos/dma.channels;
-}
-
-
-void S_Update_(void)
-{
- unsigned endtime;
- int samps;
-
- if (!sound_started)
- return;
-
- SNDDMA_BeginPainting ();
-
- if (!dma.buffer)
- return;
-
-// Updates DMA time
- GetSoundtime();
-
-// check to make sure that we haven't overshot
- if (paintedtime < soundtime)
- {
- Com_DPrintf ("S_Update_ : overflow\n");
- paintedtime = soundtime;
- }
-
-// mix ahead of current position
- endtime = soundtime + s_mixahead->value * dma.speed;
-//endtime = (soundtime + 4096) & ~4095;
-
- // mix to an even submission block size
- endtime = (endtime + dma.submission_chunk-1)
- & ~(dma.submission_chunk-1);
- samps = dma.samples >> (dma.channels-1);
- if (endtime - soundtime > samps)
- endtime = soundtime + samps;
-
- S_PaintChannels (endtime);
-
- SNDDMA_Submit ();
-}
-
-/*
-===============================================================================
-
-console functions
-
-===============================================================================
-*/
-
-void S_Play(void)
-{
- int i;
- char name[256];
- sfx_t *sfx;
-
- i = 1;
- while (i<Cmd_Argc())
- {
- if (!strrchr(Cmd_Argv(i), '.'))
- {
- strcpy(name, Cmd_Argv(i));
- strcat(name, ".wav");
- }
- else
- strcpy(name, Cmd_Argv(i));
- sfx = S_RegisterSound(name);
- S_StartSound(NULL, cl.playernum+1, 0, sfx, 1.0, 1.0, 0);
- i++;
- }
-}
-
-void S_SoundList(void)
-{
- int i;
- sfx_t *sfx;
- sfxcache_t *sc;
- int size, total;
-
- total = 0;
- for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)
- {
- if (!sfx->registration_sequence)
- continue;
- sc = sfx->cache;
- if (sc)
- {
- size = sc->length*sc->width*(sc->stereo+1);
- total += size;
- if (sc->loopstart >= 0)
- Com_Printf ("L");
- else
- Com_Printf (" ");
- Com_Printf("(%2db) %6i : %s\n",sc->width*8, size, sfx->name);
- }
- else
- {
- if (sfx->name[0] == '*')
- Com_Printf(" placeholder : %s\n", sfx->name);
- else
- Com_Printf(" not loaded : %s\n", sfx->name);
- }
- }
- Com_Printf ("Total resident: %i\n", total);
-}
-
--- a/client/snd_loc.h
+++ /dev/null
@@ -1,144 +1,0 @@
-// snd_loc.h -- private sound functions
-
-// !!! if this is changed, the asm code must change !!!
-typedef struct
-{
- int left;
- int right;
-} portable_samplepair_t;
-
-typedef struct
-{
- int length;
- int loopstart;
- int speed; // not needed, because converted on load?
- int width;
- int stereo;
- byte data[1]; // variable sized
-} sfxcache_t;
-
-typedef struct sfx_s
-{
- char name[MAX_QPATH];
- int registration_sequence;
- sfxcache_t *cache;
- char *truename;
-} sfx_t;
-
-// a playsound_t will be generated by each call to S_StartSound,
-// when the mixer reaches playsound->begin, the playsound will
-// be assigned to a channel
-typedef struct playsound_s
-{
- struct playsound_s *prev, *next;
- sfx_t *sfx;
- float volume;
- float attenuation;
- int entnum;
- int entchannel;
- qboolean fixed_origin; // use origin field instead of entnum's origin
- vec3_t origin;
- unsigned begin; // begin on this sample
-} playsound_t;
-
-typedef struct
-{
- int channels;
- int samples; // mono samples in buffer
- int submission_chunk; // don't mix less than this #
- int samplepos; // in mono samples
- int samplebits;
- int speed;
- byte *buffer;
-} dma_t;
-
-// !!! if this is changed, the asm code must change !!!
-typedef struct
-{
- sfx_t *sfx; // sfx number
- int leftvol; // 0-255 volume
- int rightvol; // 0-255 volume
- int end; // end time in global paintsamples
- int pos; // sample position in sfx
- int looping; // where to loop, -1 = no looping OBSOLETE?
- int entnum; // to allow overriding a specific sound
- int entchannel; //
- vec3_t origin; // only use if fixed_origin is set
- vec_t dist_mult; // distance multiplier (attenuation/clipK)
- int master_vol; // 0-255 master volume
- qboolean fixed_origin; // use origin instead of fetching entnum's origin
- qboolean autosound; // from an entity->sound, cleared each frame
-} channel_t;
-
-typedef struct
-{
- int rate;
- int width;
- int channels;
- int loopstart;
- int samples;
- int dataofs; // chunk starts this many bytes from file start
-} wavinfo_t;
-
-
-/*
-====================================================================
-
- SYSTEM SPECIFIC FUNCTIONS
-
-====================================================================
-*/
-
-// initializes cycling through a DMA buffer and returns information on it
-qboolean SNDDMA_Init(void);
-
-// gets the current DMA position
-int SNDDMA_GetDMAPos(void);
-
-// shutdown the DMA xfer.
-void SNDDMA_Shutdown(void);
-
-void SNDDMA_BeginPainting (void);
-
-void SNDDMA_Submit(void);
-
-//====================================================================
-
-#define MAX_CHANNELS 32
-extern channel_t channels[MAX_CHANNELS];
-
-extern int paintedtime;
-extern int s_rawend;
-extern vec3_t listener_origin;
-extern vec3_t listener_forward;
-extern vec3_t listener_right;
-extern vec3_t listener_up;
-extern dma_t dma;
-extern playsound_t s_pendingplays;
-
-#define MAX_RAW_SAMPLES 8192
-extern portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
-
-extern cvar_t *s_volume;
-extern cvar_t *s_loadas8bit;
-extern cvar_t *s_khz;
-extern cvar_t *s_show;
-extern cvar_t *s_mixahead;
-extern cvar_t *s_testsound;
-extern cvar_t *s_primary;
-
-wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength);
-
-void S_InitScaletable (void);
-
-sfxcache_t *S_LoadSound (sfx_t *s);
-
-void S_IssuePlaysound (playsound_t *ps);
-
-void S_PaintChannels(int endtime);
-
-// picks a channel based on priorities, empty slots, number of channels
-channel_t *S_PickChannel(int entnum, int entchannel);
-
-// spatializes a channel
-void S_Spatialize(channel_t *ch);
--- a/client/snd_mem.c
+++ /dev/null
@@ -1,341 +1,0 @@
-// snd_mem.c: sound caching
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-int cache_full_cycle;
-
-byte *S_Alloc (int size);
-
-/*
-================
-ResampleSfx
-================
-*/
-void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data)
-{
- int outcount;
- int srcsample;
- float stepscale;
- int i;
- int sample, samplefrac, fracstep;
- sfxcache_t *sc;
-
- sc = sfx->cache;
- if (!sc)
- return;
-
- stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
-
- outcount = sc->length / stepscale;
- sc->length = outcount;
- if (sc->loopstart != -1)
- sc->loopstart = sc->loopstart / stepscale;
-
- sc->speed = dma.speed;
- if (s_loadas8bit->value)
- sc->width = 1;
- else
- sc->width = inwidth;
- sc->stereo = 0;
-
-// resample / decimate to the current source rate
-
- if (stepscale == 1 && inwidth == 1 && sc->width == 1)
- {
-// fast special case
- for (i=0 ; i<outcount ; i++)
- ((signed char *)sc->data)[i]
- = (int)( (unsigned char)(data[i]) - 128);
- }
- else
- {
-// general case
- samplefrac = 0;
- fracstep = stepscale*256;
- for (i=0 ; i<outcount ; i++)
- {
- srcsample = samplefrac >> 8;
- samplefrac += fracstep;
- if (inwidth == 2)
- sample = LittleShort ( ((short *)data)[srcsample] );
- else
- sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
- if (sc->width == 2)
- ((short *)sc->data)[i] = sample;
- else
- ((signed char *)sc->data)[i] = sample >> 8;
- }
- }
-}
-
-//=============================================================================
-
-/*
-==============
-S_LoadSound
-==============
-*/
-sfxcache_t *S_LoadSound (sfx_t *s)
-{
- char namebuffer[MAX_QPATH];
- byte *data;
- wavinfo_t info;
- int len;
- float stepscale;
- sfxcache_t *sc;
- int size;
- char *name;
-
- if (s->name[0] == '*')
- return NULL;
-
-// see if still in memory
- sc = s->cache;
- if (sc)
- return sc;
-
-//Com_Printf ("S_LoadSound: %x\n", (int)stackbuf);
-// load it in
- if (s->truename)
- name = s->truename;
- else
- name = s->name;
-
- if (name[0] == '#')
- strcpy(namebuffer, &name[1]);
- else
- Com_sprintf (namebuffer, sizeof(namebuffer), "sound/%s", name);
-
-// Com_Printf ("loading %s\n",namebuffer);
-
- size = FS_LoadFile (namebuffer, (void **)&data);
-
- if (!data)
- {
- Com_DPrintf ("Couldn't load %s\n", namebuffer);
- return NULL;
- }
-
- info = GetWavinfo (s->name, data, size);
- if (info.channels != 1)
- {
- Com_Printf ("%s is a stereo sample\n",s->name);
- FS_FreeFile (data);
- return NULL;
- }
-
- stepscale = (float)info.rate / dma.speed;
- len = info.samples / stepscale;
-
- len = len * info.width * info.channels;
-
- sc = s->cache = Z_Malloc (len + sizeof(sfxcache_t));
- if (!sc)
- {
- FS_FreeFile (data);
- return NULL;
- }
-
- sc->length = info.samples;
- sc->loopstart = info.loopstart;
- sc->speed = info.rate;
- sc->width = info.width;
- sc->stereo = info.channels;
-
- ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);
-
- FS_FreeFile (data);
-
- return sc;
-}
-
-
-
-/*
-===============================================================================
-
-WAV loading
-
-===============================================================================
-*/
-
-
-byte *data_p;
-byte *iff_end;
-byte *last_chunk;
-byte *iff_data;
-int iff_chunk_len;
-
-
-short GetLittleShort(void)
-{
- short val;
- val = *data_p;
- val = val + (*(data_p+1)<<8);
- data_p += 2;
- return val;
-}
-
-int GetLittleLong(void)
-{
- int val;
- val = *data_p;
- val = val + (*(data_p+1)<<8);
- val = val + (*(data_p+2)<<16);
- val = val + (*(data_p+3)<<24);
- data_p += 4;
- return val;
-}
-
-void FindNextChunk(char *name)
-{
- while (1)
- {
- data_p=last_chunk;
-
- if (data_p >= iff_end)
- { // didn't find the chunk
- data_p = NULL;
- return;
- }
-
- data_p += 4;
- iff_chunk_len = GetLittleLong();
- if (iff_chunk_len < 0)
- {
- data_p = NULL;
- return;
- }
-// if (iff_chunk_len > 1024*1024)
-// Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
- data_p -= 8;
- last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
- if (!strncmp((char *)data_p, name, 4))
- return;
- }
-}
-
-void FindChunk(char *name)
-{
- last_chunk = iff_data;
- FindNextChunk (name);
-}
-
-
-void DumpChunks(void)
-{
- char str[5];
-
- str[4] = 0;
- data_p=iff_data;
- do
- {
- memcpy (str, data_p, 4);
- data_p += 4;
- iff_chunk_len = GetLittleLong();
- Com_Printf ("0x%x : %s (%p)\n", (uintptr)(data_p - 4), str, iff_chunk_len);
- data_p += (iff_chunk_len + 1) & ~1;
- } while (data_p < iff_end);
-}
-
-/*
-============
-GetWavinfo
-============
-*/
-wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
-{
- wavinfo_t info;
- int i;
- int format;
- int samples;
-
- memset (&info, 0, sizeof(info));
-
- if (!wav)
- return info;
-
- iff_data = wav;
- iff_end = wav + wavlength;
-
-// find "RIFF" chunk
- FindChunk("RIFF");
- if (!(data_p && !strncmp((char *)data_p+8, "WAVE", 4)))
- {
- Com_Printf("Missing RIFF/WAVE chunks\n");
- return info;
- }
-
-// get "fmt " chunk
- iff_data = data_p + 12;
-// DumpChunks ();
-
- FindChunk("fmt ");
- if (!data_p)
- {
- Com_Printf("Missing fmt chunk\n");
- return info;
- }
- data_p += 8;
- format = GetLittleShort();
- if (format != 1)
- {
- Com_Printf("Microsoft PCM format only\n");
- return info;
- }
-
- info.channels = GetLittleShort();
- info.rate = GetLittleLong();
- data_p += 4+2;
- info.width = GetLittleShort() / 8;
-
-// get cue chunk
- FindChunk("cue ");
- if (data_p)
- {
- data_p += 32;
- info.loopstart = GetLittleLong();
-// Com_Printf("loopstart=%d\n", sfx->loopstart);
-
- // if the next chunk is a LIST chunk, look for a cue length marker
- FindNextChunk ("LIST");
- if (data_p)
- {
- if (!strncmp ((char *)data_p + 28, "mark", 4))
- { // this is not a proper parse, but it works with cooledit...
- data_p += 24;
- i = GetLittleLong (); // samples in loop
- info.samples = info.loopstart + i;
-// Com_Printf("looped length: %i\n", i);
- }
- }
- }
- else
- info.loopstart = -1;
-
-// find data chunk
- FindChunk("data");
- if (!data_p)
- {
- Com_Printf("Missing data chunk\n");
- return info;
- }
-
- data_p += 4;
- samples = GetLittleLong () / info.width;
-
- if (info.samples)
- {
- if (samples < info.samples)
- Com_Error (ERR_DROP, "Sound %s has a bad loop length", name);
- }
- else
- info.samples = samples;
-
- info.dataofs = data_p - wav;
-
- return info;
-}
-
--- a/client/snd_mix.c
+++ /dev/null
@@ -1,349 +1,0 @@
-// snd_mix.c -- portable code to mix sounds for snd_dma.c
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-#define PAINTBUFFER_SIZE 2048
-portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
-int snd_scaletable[32][256];
-int *snd_p, snd_linear_count, snd_vol;
-short *snd_out;
-
-
-void S_WriteLinearBlastStereo16 (void)
-{
- int i;
- int val;
-
- for (i=0 ; i<snd_linear_count ; i+=2)
- {
- val = snd_p[i]>>8;
- if (val > 0x7fff)
- snd_out[i] = 0x7fff;
- else if (val < (short)0x8000)
- snd_out[i] = (short)0x8000;
- else
- snd_out[i] = val;
-
- val = snd_p[i+1]>>8;
- if (val > 0x7fff)
- snd_out[i+1] = 0x7fff;
- else if (val < (short)0x8000)
- snd_out[i+1] = (short)0x8000;
- else
- snd_out[i+1] = val;
- }
-}
-
-void S_TransferStereo16 (unsigned long *pbuf, int endtime)
-{
- int lpos;
- int lpaintedtime;
-
- snd_p = (int *) paintbuffer;
- lpaintedtime = paintedtime;
-
- while (lpaintedtime < endtime)
- {
- // handle recirculating buffer issues
- lpos = lpaintedtime & ((dma.samples>>1)-1);
-
- snd_out = (short *) pbuf + (lpos<<1);
-
- snd_linear_count = (dma.samples>>1) - lpos;
- if (lpaintedtime + snd_linear_count > endtime)
- snd_linear_count = endtime - lpaintedtime;
-
- snd_linear_count <<= 1;
-
- // write a linear blast of samples
- S_WriteLinearBlastStereo16 ();
-
- snd_p += snd_linear_count;
- lpaintedtime += (snd_linear_count>>1);
- }
-}
-
-/*
-===================
-S_TransferPaintBuffer
-
-===================
-*/
-void S_TransferPaintBuffer(int endtime)
-{
- int out_idx;
- int count;
- int out_mask;
- int *p;
- int step;
- int val;
- unsigned long *pbuf;
-
- pbuf = (unsigned long *)dma.buffer;
-
- if (s_testsound->value)
- {
- int i;
- int count;
-
- // write a fixed sine wave
- count = (endtime - paintedtime);
- for (i=0 ; i<count ; i++)
- paintbuffer[i].left = paintbuffer[i].right = sin((paintedtime+i)*0.1)*20000*256;
- }
-
-
- if (dma.samplebits == 16 && dma.channels == 2)
- { // optimized case
- S_TransferStereo16 (pbuf, endtime);
- }
- else
- { // general case
- p = (int *) paintbuffer;
- count = (endtime - paintedtime) * dma.channels;
- out_mask = dma.samples - 1;
- out_idx = paintedtime * dma.channels & out_mask;
- step = 3 - dma.channels;
-
- if (dma.samplebits == 16)
- {
- short *out = (short *) pbuf;
- while (count--)
- {
- val = *p >> 8;
- p+= step;
- if (val > 0x7fff)
- val = 0x7fff;
- else if (val < (short)0x8000)
- val = (short)0x8000;
- out[out_idx] = val;
- out_idx = (out_idx + 1) & out_mask;
- }
- }
- else if (dma.samplebits == 8)
- {
- unsigned char *out = (unsigned char *) pbuf;
- while (count--)
- {
- val = *p >> 8;
- p+= step;
- if (val > 0x7fff)
- val = 0x7fff;
- else if (val < (short)0x8000)
- val = (short)0x8000;
- out[out_idx] = (val>>8) + 128;
- out_idx = (out_idx + 1) & out_mask;
- }
- }
- }
-}
-
-
-/*
-===============================================================================
-
-CHANNEL MIXING
-
-===============================================================================
-*/
-
-void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime, int offset);
-void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime, int offset);
-
-void S_PaintChannels(int endtime)
-{
- int i;
- int end;
- channel_t *ch;
- sfxcache_t *sc;
- int ltime, count;
- playsound_t *ps;
-
- snd_vol = s_volume->value*256;
-
-//Com_Printf ("%i to %i\n", paintedtime, endtime);
- while (paintedtime < endtime)
- {
- // if paintbuffer is smaller than DMA buffer
- end = endtime;
- if (endtime - paintedtime > PAINTBUFFER_SIZE)
- end = paintedtime + PAINTBUFFER_SIZE;
-
- // start any playsounds
- while (1)
- {
- ps = s_pendingplays.next;
- if (ps == &s_pendingplays)
- break; // no more pending sounds
- if (ps->begin <= paintedtime)
- {
- S_IssuePlaysound (ps);
- continue;
- }
-
- if (ps->begin < end)
- end = ps->begin; // stop here
- break;
- }
-
- // clear the paint buffer
- if (s_rawend < paintedtime)
- {
-// Com_Printf ("clear\n");
- memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t));
- }
- else
- { // copy from the streaming sound source
- int s;
- int stop;
-
- stop = (end < s_rawend) ? end : s_rawend;
-
- for (i=paintedtime ; i<stop ; i++)
- {
- s = i&(MAX_RAW_SAMPLES-1);
- paintbuffer[i-paintedtime] = s_rawsamples[s];
- }
-// if (i != end)
-// Com_Printf ("partial stream\n");
-// else
-// Com_Printf ("full stream\n");
- for ( ; i<end ; i++)
- {
- paintbuffer[i-paintedtime].left =
- paintbuffer[i-paintedtime].right = 0;
- }
- }
-
-
- // paint in the channels.
- ch = channels;
- for (i=0; i<MAX_CHANNELS ; i++, ch++)
- {
- ltime = paintedtime;
-
- while (ltime < end)
- {
- if (!ch->sfx || (!ch->leftvol && !ch->rightvol) )
- break;
-
- // max painting is to the end of the buffer
- count = end - ltime;
-
- // might be stopped by running out of data
- if (ch->end - ltime < count)
- count = ch->end - ltime;
-
- sc = S_LoadSound (ch->sfx);
- if (!sc)
- break;
-
- if (count > 0 && ch->sfx)
- {
- if (sc->width == 1)// FIXME; 8 bit asm is wrong now
- S_PaintChannelFrom8(ch, sc, count, ltime - paintedtime);
- else
- S_PaintChannelFrom16(ch, sc, count, ltime - paintedtime);
-
- ltime += count;
- }
-
- // if at end of loop, restart
- if (ltime >= ch->end)
- {
- if (ch->autosound)
- { // autolooping sounds always go back to start
- ch->pos = 0;
- ch->end = ltime + sc->length;
- }
- else if (sc->loopstart >= 0)
- {
- ch->pos = sc->loopstart;
- ch->end = ltime + sc->length - ch->pos;
- }
- else
- { // channel just stopped
- ch->sfx = NULL;
- }
- }
- }
-
- }
-
- // transfer out according to DMA format
- S_TransferPaintBuffer(end);
- paintedtime = end;
- }
-}
-
-void S_InitScaletable (void)
-{
- int i, j;
- int scale;
-
- s_volume->modified = false;
- for (i=0 ; i<32 ; i++)
- {
- scale = i * 8 * 256 * s_volume->value;
- for (j=0 ; j<256 ; j++)
- snd_scaletable[i][j] = ((signed char)j) * scale;
- }
-}
-
-void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count, int offset)
-{
- int data;
- int *lscale, *rscale;
- unsigned char *sfx;
- int i;
- portable_samplepair_t *samp;
-
- if (ch->leftvol > 255)
- ch->leftvol = 255;
- if (ch->rightvol > 255)
- ch->rightvol = 255;
-
- lscale = snd_scaletable[ ch->leftvol >> 11];
- rscale = snd_scaletable[ ch->rightvol >> 11];
- sfx = (uchar *)sc->data + ch->pos;
-
- samp = &paintbuffer[offset];
-
- for (i=0 ; i<count ; i++, samp++)
- {
- data = sfx[i];
- samp->left += lscale[data];
- samp->right += rscale[data];
- }
-
- ch->pos += count;
-}
-
-void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count, int offset)
-{
- int data;
- int left, right;
- int leftvol, rightvol;
- signed short *sfx;
- int i;
- portable_samplepair_t *samp;
-
- leftvol = ch->leftvol*snd_vol;
- rightvol = ch->rightvol*snd_vol;
- sfx = (signed short *)sc->data + ch->pos;
-
- samp = &paintbuffer[offset];
- for (i=0 ; i<count ; i++, samp++)
- {
- data = sfx[i];
- left = (data * leftvol)>>8;
- right = (data * rightvol)>>8;
- samp->left += left;
- samp->right += right;
- }
-
- ch->pos += count;
-}
--- a/client/sound.h
+++ /dev/null
@@ -1,21 +1,0 @@
-void S_Init (void);
-void S_Shutdown (void);
-
-// if origin is NULL, the sound will be dynamically sourced from the entity
-void S_StartSound (vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float timeofs);
-void S_StartLocalSound (char *s);
-
-void S_RawSamples (int samples, int rate, int width, int channels, byte *data);
-
-void S_StopAllSounds(void);
-void S_Update (vec3_t origin, vec3_t v_forward, vec3_t v_right, vec3_t v_up);
-
-void S_Activate (qboolean active);
-
-void S_BeginRegistration (void);
-sfx_t *S_RegisterSound (char *sample);
-void S_EndRegistration (void);
-
-// the sound code makes callbacks to the client for entitiy position
-// information, so entities can be dynamically re-spatialized
-void CL_GetEntitySoundOrigin (int ent, vec3_t org);
--- a/client/vid.h
+++ /dev/null
@@ -1,33 +1,0 @@
-// vid.h -- video driver defs
-
-typedef uchar pixel_t;
-
-typedef struct vrect_t vrect_t;
-typedef struct viddef_t viddef_t;
-
-struct vrect_t
-{
- int x, y, width, height;
- vrect_t *pnext;
-};
-
-struct viddef_t
-{
- int width;
- int height;
- pixel_t *buffer; // invisible buffer
- pixel_t *colormap; // 256 * VID_GRADES size
- pixel_t *alphamap; // 256 * 256 translucency map
- int rowbytes; // may be > width if displayed in a window
- // can be negative for stupid dibs
-};
-extern viddef_t vid;
-
-// Video module initialisation etc
-void VID_Init (void);
-void VID_Shutdown (void);
-void VID_CheckChanges (void);
-
-void VID_MenuInit( void );
-void VID_MenuDraw( void );
-const char *VID_MenuKey( int );
--- /dev/null
+++ b/cmd.c
@@ -1,0 +1,633 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/* Command text buffering and command execution
+ *
+ * Any number of commands can be added in a frame, from several different
+ * sources. Most commands come from either keybindings or console line input,
+ * but remote servers can also send across commands and entire text files can
+ * be execed. The '+' command line options are also added to the command buffer.
+ * The game starts with a Cbuf_AddText("exec quake.rc\n"); Cbuf_Execute();.
+ * Command execution takes a null terminated string, breaks it into tokens,
+ * then searches for a command or variable that matches the first token. */
+
+typedef struct cmdalias_t cmdalias_t;
+typedef struct cmd_function_t cmd_function_t;
+
+enum{
+ MAX_ALIAS_NAME = 32,
+ ALIAS_LOOP_COUNT = 16
+};
+struct cmdalias_t{
+ cmdalias_t *next;
+ char name[MAX_ALIAS_NAME];
+ char *value;
+};
+cmdalias_t *cmd_alias;
+int alias_count; // for detecting runaway loops
+
+qboolean cmd_wait;
+
+sizebuf_t cmd_text;
+uchar cmd_text_buf[8192];
+uchar defer_text_buf[8192];
+
+static int cmd_argc;
+static char *cmd_argv[MAX_STRING_TOKENS];
+static char *cmd_null_string = "";
+static char cmd_args[MAX_STRING_CHARS];
+
+struct cmd_function_t{
+ cmd_function_t *next;
+ char *name;
+ xcommand_t function;
+};
+static cmd_function_t *cmd_functions; // possible commands to execute
+
+
+/* Causes execution of the remainder of the command buffer to be delayed until
+ * next frame. This allows commands like:
+ * bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2" */
+void
+Cmd_Wait_f(void)
+{
+ cmd_wait = true;
+}
+
+/* allocates an initial text buffer that will grow as needed */
+void
+Cbuf_Init(void)
+{
+ SZ_Init(&cmd_text, cmd_text_buf, sizeof cmd_text_buf);
+}
+
+/* adds command text at the end of the buffer */
+void
+Cbuf_AddText(char *text)
+{
+ int l;
+
+ l = strlen(text);
+
+ if(cmd_text.cursize + l >= cmd_text.maxsize){
+ Com_Printf("Cbuf_AddText: overflow\n");
+ return;
+ }
+ SZ_Write(&cmd_text, text, l);
+}
+
+// FIXME: actually change the command buffer to do less copying
+/* Adds command text immediately after the current command and '\n' to the text */
+void
+Cbuf_InsertText(char *text)
+{
+ char *temp = nil;
+ int templen;
+
+ /* copy off any commands still remaining in the exec buffer */
+ templen = cmd_text.cursize;
+ if(templen){
+ temp = Z_Malloc(templen);
+ memcpy(temp, cmd_text.data, templen);
+ SZ_Clear(&cmd_text);
+ }
+
+ Cbuf_AddText(text);
+ if(templen){
+ SZ_Write(&cmd_text, temp, templen);
+ Z_Free(temp);
+ }
+}
+
+void
+Cbuf_CopyToDefer(void)
+{
+ memcpy(defer_text_buf, cmd_text_buf, cmd_text.cursize);
+ defer_text_buf[cmd_text.cursize] = 0;
+ cmd_text.cursize = 0;
+}
+
+void
+Cbuf_InsertFromDefer(void)
+{
+ Cbuf_InsertText((char *)defer_text_buf);
+ defer_text_buf[0] = 0;
+}
+
+void
+Cbuf_ExecuteText(int exec_when, char *text)
+{
+ switch(exec_when){
+ case EXEC_NOW:
+ Cmd_ExecuteString(text);
+ break;
+ case EXEC_INSERT:
+ Cbuf_InsertText(text);
+ break;
+ case EXEC_APPEND:
+ Cbuf_AddText(text);
+ break;
+ default:
+ Com_Error(ERR_FATAL, "Cbuf_ExecuteText: bad exec_when");
+ }
+}
+
+/* normally called once per frame, but may be explicitly invoked.
+ * do not call inside a command function! */
+void
+Cbuf_Execute(void)
+{
+ int i, quotes;
+ char *text, line[1024];
+
+ alias_count = 0; // don't allow infinite alias loops
+
+ while(cmd_text.cursize){
+ text = (char *)cmd_text.data;
+
+ /* find a \n or ; line break */
+ quotes = 0;
+ for(i=0; i<cmd_text.cursize; i++){
+ if(text[i] == '"')
+ quotes++;
+ if(~quotes & 1 && text[i] == ';')
+ break; // don't break if inside a quoted string
+ if(text[i] == '\n')
+ break;
+ }
+ memcpy(line, text, i);
+ line[i] = 0;
+
+ /* delete the text from the command buffer and move remaining
+ * commands down. this is necessary because commands (exec,
+ * alias) can insert data at the beginning of the text buffer */
+ if(i == cmd_text.cursize)
+ cmd_text.cursize = 0;
+ else{
+ i++;
+ cmd_text.cursize -= i;
+ memmove(text, text+i, cmd_text.cursize);
+ }
+
+ Cmd_ExecuteString(line);
+
+ /* skip out while text still remains in buffer, leaving it for
+ * next frame */
+ if(cmd_wait){
+ cmd_wait = false;
+ break;
+ }
+ }
+}
+
+/* Adds command line parameters as script statements. Commands lead with a '+',
+ * and continue until another '+'. Set commands are added early, so they are
+ * guaranteed to be set before the client and server initialize for the first
+ * time. Other commands are added late, after all initialization is complete. */
+void
+Cbuf_AddEarlyCommands(qboolean clear)
+{
+ int i;
+ char *s;
+
+ for(i=0; i<COM_Argc(); i++){
+ s = COM_Argv(i);
+ if(strcmp(s, "+set"))
+ continue;
+ Cbuf_AddText(va("set %s %s\n", COM_Argv(i+1), COM_Argv(i+2)));
+ if(clear){
+ COM_ClearArgv(i);
+ COM_ClearArgv(i+1);
+ COM_ClearArgv(i+2);
+ }
+ i += 2;
+ }
+}
+
+/* Adds command line parameters as script statements. Commands lead with a '+'
+ * and continue until another '+' or '-'. Returns true if any late commands
+ * were added, which will keep the demoloop from immediately starting. */
+qboolean
+Cbuf_AddLateCommands(void)
+{
+ int i, j, s, argc;
+ char *text, *build, c;
+ qboolean ret;
+
+ /* build the combined string to parse from */
+ s = 0;
+ argc = COM_Argc();
+ for(i=1; i<argc; i++)
+ s += strlen(COM_Argv(i)) + 1;
+ if(!s)
+ return false;
+
+ text = Z_Malloc(s+1);
+ text[0] = 0;
+ for(i=1; i<argc; i++){
+ strcat(text, COM_Argv(i));
+ if(i != argc-1)
+ strcat(text, " ");
+ }
+
+ /* pull out the commands */
+ build = Z_Malloc(s+1);
+ build[0] = 0;
+ for(i=0; i<s-1; i++)
+ if(text[i] == '+'){
+ i++;
+ for(j=i; text[j] != '+' && text[j] != '-' && text[j] != 0 ; j++)
+ ;
+ c = text[j];
+ text[j] = 0;
+ strcat(build, text+i);
+ strcat(build, "\n");
+ text[j] = c;
+ i = j-1;
+ }
+
+ ret = build[0] != 0;
+ if(ret)
+ Cbuf_AddText(build);
+ Z_Free(text);
+ Z_Free(build);
+ return ret;
+}
+
+void
+Cmd_Exec_f(void)
+{
+ char *f, *f2;
+ int len;
+
+ if(Cmd_Argc() != 2){
+ Com_Printf("exec <filename> : execute a script file\n");
+ return;
+ }
+
+ len = FS_LoadFile(Cmd_Argv(1), (void **)&f);
+ if(!f){
+ Com_Printf("couldn't exec %s\n", Cmd_Argv(1));
+ return;
+ }
+ Com_Printf("execing %s\n", Cmd_Argv(1));
+
+ /* the file doesn't have a trailing 0, so we need to copy it off */
+ f2 = Z_Malloc(len+1);
+ memcpy(f2, f, len);
+ f2[len] = 0;
+ Cbuf_InsertText(f2);
+ Z_Free(f2);
+ FS_FreeFile(f);
+}
+
+/* just prints the rest of the line to the console */
+void
+Cmd_Echo_f(void)
+{
+ int i;
+
+ for(i=1; i<Cmd_Argc(); i++)
+ Com_Printf("%s ", Cmd_Argv(i));
+ Com_Printf("\n");
+}
+
+/* Creates a new command that executes a command string (possibly ; seperated) */
+void
+Cmd_Alias_f(void)
+{
+ int i, c;
+ char cmd[1024], *s;
+ cmdalias_t *p;
+
+ if(Cmd_Argc() == 1){
+ Com_Printf("Current alias commands:\n");
+ for(p = cmd_alias; p != nil; p = p->next)
+ Com_Printf("%s : %s\n", p->name, p->value);
+ return;
+ }
+
+ s = Cmd_Argv(1);
+ if(strlen(s) >= MAX_ALIAS_NAME){
+ Com_Printf("Alias name is too long\n");
+ return;
+ }
+
+ /* if the alias already exists, reuse it */
+ for(p = cmd_alias; p != nil; p = p->next)
+ if(!strcmp(s, p->name)){
+ Z_Free(p->value);
+ break;
+ }
+
+ if(p == nil){
+ p = Z_Malloc(sizeof *p);
+ p->next = cmd_alias;
+ cmd_alias = p;
+ }
+ strcpy(p->name, s);
+
+ /* copy the rest of the command line */
+ cmd[0] = 0; // start out with a null string
+ c = Cmd_Argc();
+ for(i=2; i<c; i++){
+ strcat(cmd, Cmd_Argv(i));
+ if(i != c-1)
+ strcat(cmd, " ");
+ }
+ strcat(cmd, "\n");
+ p->value = CopyString(cmd);
+}
+
+int
+Cmd_Argc(void)
+{
+ return cmd_argc;
+}
+
+char *
+Cmd_Argv(int arg)
+{
+ if((unsigned)arg >= cmd_argc)
+ return cmd_null_string;
+ return cmd_argv[arg];
+}
+
+/* returns a single string containing argv(1) to argv(argc()-1) */
+char *
+Cmd_Args(void)
+{
+ return cmd_args;
+}
+
+char *
+Cmd_MacroExpandString(char *text)
+{
+ int i, j, count, len;
+ qboolean inquote;
+ char *scan, *token, *start;
+ char temporary[MAX_STRING_CHARS];
+ static char expanded[MAX_STRING_CHARS];
+
+ inquote = false;
+ scan = text;
+ len = strlen (scan);
+ if(len >= MAX_STRING_CHARS){
+ Com_Printf("Line exceeded %d chars, discarded.\n", MAX_STRING_CHARS);
+ return nil;
+ }
+
+ count = 0;
+ for(i=0; i<len ; i++){
+ if(scan[i] == '"')
+ inquote ^= 1;
+ if(inquote)
+ continue; // don't expand inside quotes
+ if(scan[i] != '$')
+ continue;
+
+ /* scan out the complete macro */
+ start = scan+i+1;
+ token = COM_Parse(&start);
+ if(!start)
+ continue;
+
+ token = Cvar_VariableString(token);
+ j = strlen(token);
+ len += j;
+ if(len >= MAX_STRING_CHARS){
+ Com_Printf("Expanded line exceeded %d chars, discarded.\n", MAX_STRING_CHARS);
+ return nil;
+ }
+
+ strncpy(temporary, scan, i);
+ strcpy(temporary+i, token);
+ strcpy(temporary+i+j, start);
+ strcpy(expanded, temporary);
+ scan = expanded;
+ i--;
+
+ if(++count == 100){
+ Com_Printf("Macro expansion loop, discarded.\n");
+ return nil;
+ }
+ }
+
+ if(inquote){
+ Com_Printf("Line has unmatched quote, discarded.\n");
+ return nil;
+ }
+ return scan;
+}
+
+/* Parses the given string into command line tokens. $Cvars will be expanded
+ * unless they are in a quoted token */
+void
+Cmd_TokenizeString(char *text, qboolean macroExpand)
+{
+ int i, l;
+ char *com_token;
+
+ /* clear the args from the last string */
+ for(i=0; i<cmd_argc; i++)
+ Z_Free(cmd_argv[i]);
+ cmd_argc = 0;
+ cmd_args[0] = 0;
+
+ /* macro expand the text */
+ if(macroExpand)
+ text = Cmd_MacroExpandString(text);
+ if(text == nil)
+ return;
+
+ for(;;){
+ while(*text && *text <= ' ' && *text != '\n')
+ text++;
+
+ /* a newline separates commands in the buffer */
+ if(*text == '\n'){
+ text++;
+ break;
+ }
+
+ if(!*text)
+ return;
+
+ // set cmd_args to everything after the first arg
+ if(cmd_argc == 1){
+ strcpy(cmd_args, text);
+ /* strip off any trailing whitespace */
+ for(l = strlen(cmd_args) - 1; l >= 0 ; l--)
+ if(cmd_args[l] <= ' ')
+ cmd_args[l] = 0;
+ else
+ break;
+ }
+
+ com_token = COM_Parse(&text);
+ if(text == nil)
+ return;
+
+ if(cmd_argc < MAX_STRING_TOKENS){
+ cmd_argv[cmd_argc] = Z_Malloc(strlen(com_token)+1);
+ strcpy(cmd_argv[cmd_argc], com_token);
+ cmd_argc++;
+ }
+ }
+}
+
+/* called by the init functions of other parts of the program to register
+ * commands and functions to call for them. rhe cmd_name is referenced later,
+ * so it should not be in temp memory if function is nil, the command will be
+ * forwarded to the server as a clc_stringcmd instead of executed locally */
+void
+Cmd_AddCommand(char *name, xcommand_t function)
+{
+ cmd_function_t *p;
+
+ /* fail if the command is a variable name */
+ if(Cvar_VariableString(name)[0]){
+ Com_Printf("Cmd_AddCommand: %s already defined as a var\n", name);
+ return;
+ }
+
+ /* fail if the command already exists */
+ for(p = cmd_functions; p != nil; p = p->next)
+ if(!strcmp(name, p->name)){
+ Com_Printf("Cmd_AddCommand: %s already defined\n", name);
+ return;
+ }
+
+ p = Z_Malloc(sizeof *p);
+ p->name = name;
+ p->function = function;
+ p->next = cmd_functions;
+ cmd_functions = p;
+}
+
+void
+Cmd_RemoveCommand(char *name)
+{
+ cmd_function_t *p, **back;
+
+ back = &cmd_functions;
+ for(;;){
+ p = *back;
+ if(p == nil){
+ Com_Printf("Cmd_RemoveCommand: %s not added\n", name);
+ return;
+ }
+ if(!strcmp(name, p->name)){
+ *back = p->next;
+ Z_Free(p);
+ return;
+ }
+ back = &p->next;
+ }
+}
+
+/* used by the cvar code to check for cvar / command name overlap */
+qboolean
+Cmd_Exists(char *name)
+{
+ cmd_function_t *p;
+
+ for(p = cmd_functions; p != nil; p = p->next)
+ if(!strcmp(name, p->name))
+ return true;
+ return false;
+}
+
+/* attempts to match a partial command for automatic command line completion */
+char *
+Cmd_CompleteCommand(char *partial)
+{
+ cmd_function_t *p;
+ int len;
+ cmdalias_t *a;
+
+ len = strlen(partial);
+ if(!len)
+ return nil;
+
+ /* check for exact match */
+ for(p = cmd_functions; p != nil; p = p->next)
+ if(!strcmp(partial, p->name))
+ return p->name;
+ for(a = cmd_alias; a != nil; a = a->next)
+ if(!strcmp(partial, a->name))
+ return a->name;
+
+ /* check for partial match */
+ for(p = cmd_functions; p != nil; p = p->next)
+ if(!strncmp(partial, p->name, len))
+ return p->name;
+ for(a = cmd_alias; a != nil; a = a->next)
+ if(!strncmp(partial, a->name, len))
+ return a->name;
+ return nil;
+}
+
+// FIXME: lookupnoadd the token to speed search?
+/* Parses a single line of text into arguments and tries to execute it as if it
+ * was typed at the console */
+void
+Cmd_ExecuteString(char *text)
+{
+ cmd_function_t *p;
+ cmdalias_t *a;
+
+ Cmd_TokenizeString(text, true);
+ if(!Cmd_Argc())
+ return; // no tokens
+
+ /* check functions */
+ for(p = cmd_functions; p != nil; p = p->next)
+ if(!cistrcmp(cmd_argv[0], p->name)){
+ if(!p->function) // forward to server command
+ Cmd_ExecuteString(va("cmd %s", text));
+ else
+ p->function();
+ return;
+ }
+ /* check alias */
+ for(a = cmd_alias; a != nil; a = a->next)
+ if(!cistrcmp(cmd_argv[0], a->name)){
+ if(++alias_count == ALIAS_LOOP_COUNT){
+ Com_Printf("ALIAS_LOOP_COUNT\n");
+ return;
+ }
+ Cbuf_InsertText(a->value);
+ return;
+ }
+ /* check cvars */
+ if(Cvar_Command())
+ return;
+
+ /* send it as a server command if we are connected */
+ Cmd_ForwardToServer();
+}
+
+void
+Cmd_List_f(void)
+{
+ cmd_function_t *p;
+ int i;
+
+ for(p = cmd_functions, i = 0; p != nil; p = p->next, i++)
+ Com_Printf("%s\n", p->name);
+ Com_Printf("%d commands\n", i);
+}
+
+void
+Cmd_Init(void)
+{
+ Cmd_AddCommand("cmdlist", Cmd_List_f);
+ Cmd_AddCommand("exec", Cmd_Exec_f);
+ Cmd_AddCommand("echo", Cmd_Echo_f);
+ Cmd_AddCommand("alias", Cmd_Alias_f);
+ Cmd_AddCommand("wait", Cmd_Wait_f);
+}
--- /dev/null
+++ b/cmodel.c
@@ -1,0 +1,1750 @@
+// cmodel.c -- model loading
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+typedef struct
+{
+ cplane_t *plane;
+ int children[2]; // negative numbers are leafs
+} cnode_t;
+
+typedef struct
+{
+ cplane_t *plane;
+ mapsurface_t *surface;
+} cbrushside_t;
+
+typedef struct
+{
+ int contents;
+ int cluster;
+ int area;
+ unsigned short firstleafbrush;
+ unsigned short numleafbrushes;
+} cleaf_t;
+
+typedef struct
+{
+ int contents;
+ int numsides;
+ int firstbrushside;
+ int checkcount; // to avoid repeated testings
+} cbrush_t;
+
+typedef struct
+{
+ int numareaportals;
+ int firstareaportal;
+ int floodnum; // if two areas have equal floodnums, they are connected
+ int floodvalid;
+} carea_t;
+
+int checkcount;
+
+char map_name[MAX_QPATH];
+
+int numbrushsides;
+cbrushside_t map_brushsides[MAX_MAP_BRUSHSIDES];
+
+int numtexinfo;
+mapsurface_t map_surfaces[MAX_MAP_TEXINFO];
+
+int numplanes;
+cplane_t map_planes[MAX_MAP_PLANES+6]; // extra for box hull
+
+int numnodes;
+cnode_t map_nodes[MAX_MAP_NODES+6]; // extra for box hull
+
+int numleafs = 1; // allow leaf funcs to be called without a map
+cleaf_t map_leafs[MAX_MAP_LEAFS];
+int emptyleaf, solidleaf;
+
+int numleafbrushes;
+unsigned short map_leafbrushes[MAX_MAP_LEAFBRUSHES];
+
+int numcmodels;
+cmodel_t map_cmodels[MAX_MAP_MODELS];
+
+int numbrushes;
+cbrush_t map_brushes[MAX_MAP_BRUSHES];
+
+int numvisibility;
+byte map_visibility[MAX_MAP_VISIBILITY];
+dvis_t *map_vis = (dvis_t *)map_visibility;
+
+int numentitychars;
+char map_entitystring[MAX_MAP_ENTSTRING];
+
+int numareas = 1;
+carea_t map_areas[MAX_MAP_AREAS];
+
+int numareaportals;
+dareaportal_t map_areaportals[MAX_MAP_AREAPORTALS];
+
+int numclusters = 1;
+
+mapsurface_t nullsurface;
+
+int floodvalid;
+
+qboolean portalopen[MAX_MAP_AREAPORTALS];
+
+
+cvar_t *map_noareas;
+
+void CM_InitBoxHull (void);
+void FloodAreaConnections (void);
+
+
+int c_pointcontents;
+int c_traces, c_brush_traces;
+
+
+/*
+===============================================================================
+
+ MAP LOADING
+
+===============================================================================
+*/
+
+byte *cmod_base;
+
+/*
+=================
+CMod_LoadSubmodels
+=================
+*/
+void CMod_LoadSubmodels (lump_t *l)
+{
+ dmodel_t *in;
+ cmodel_t *out;
+ int i, j, count;
+
+ in = (void *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ if (count < 1)
+ Com_Error (ERR_DROP, "Map with no models");
+ if (count > MAX_MAP_MODELS)
+ Com_Error (ERR_DROP, "Map has too many models");
+
+ numcmodels = count;
+
+ for ( i=0 ; i<count ; i++, in++)
+ {
+ out = &map_cmodels[i];
+
+ for (j=0 ; j<3 ; j++)
+ { // spread the mins / maxs by a pixel
+ out->mins[j] = LittleFloat (in->mins[j]) - 1;
+ out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
+ out->origin[j] = LittleFloat (in->origin[j]);
+ }
+ out->headnode = LittleLong (in->headnode);
+ }
+}
+
+
+/*
+=================
+CMod_LoadSurfaces
+=================
+*/
+void CMod_LoadSurfaces (lump_t *l)
+{
+ texinfo_t *in;
+ mapsurface_t *out;
+ int i, count;
+
+ in = (void *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+ if (count < 1)
+ Com_Error (ERR_DROP, "Map with no surfaces");
+ if (count > MAX_MAP_TEXINFO)
+ Com_Error (ERR_DROP, "Map has too many surfaces");
+
+ numtexinfo = count;
+ out = map_surfaces;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ strncpy (out->c.name, in->texture, sizeof(out->c.name)-1);
+ strncpy (out->rname, in->texture, sizeof(out->rname)-1);
+ out->c.flags = LittleLong (in->flags);
+ out->c.value = LittleLong (in->value);
+ }
+}
+
+
+/*
+=================
+CMod_LoadNodes
+
+=================
+*/
+void CMod_LoadNodes (lump_t *l)
+{
+ dnode_t *in;
+ int child;
+ cnode_t *out;
+ int i, j, count;
+
+ in = (void *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ if (count < 1)
+ Com_Error (ERR_DROP, "Map has no nodes");
+ if (count > MAX_MAP_NODES)
+ Com_Error (ERR_DROP, "Map has too many nodes");
+
+ out = map_nodes;
+
+ numnodes = count;
+
+ for (i=0 ; i<count ; i++, out++, in++)
+ {
+ out->plane = map_planes + LittleLong(in->planenum);
+ for (j=0 ; j<2 ; j++)
+ {
+ child = LittleLong (in->children[j]);
+ out->children[j] = child;
+ }
+ }
+
+}
+
+/*
+=================
+CMod_LoadBrushes
+
+=================
+*/
+void CMod_LoadBrushes (lump_t *l)
+{
+ dbrush_t *in;
+ cbrush_t *out;
+ int i, count;
+
+ in = (void *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ if (count > MAX_MAP_BRUSHES)
+ Com_Error (ERR_DROP, "Map has too many brushes");
+
+ out = map_brushes;
+
+ numbrushes = count;
+
+ for (i=0 ; i<count ; i++, out++, in++)
+ {
+ out->firstbrushside = LittleLong(in->firstside);
+ out->numsides = LittleLong(in->numsides);
+ out->contents = LittleLong(in->contents);
+ }
+
+}
+
+/*
+=================
+CMod_LoadLeafs
+=================
+*/
+void CMod_LoadLeafs (lump_t *l)
+{
+ int i;
+ cleaf_t *out;
+ dleaf_t *in;
+ int count;
+
+ in = (void *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ if (count < 1)
+ Com_Error (ERR_DROP, "Map with no leafs");
+ // need to save space for box planes
+ if (count > MAX_MAP_PLANES)
+ Com_Error (ERR_DROP, "Map has too many planes");
+
+ out = map_leafs;
+ numleafs = count;
+ numclusters = 0;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ out->contents = LittleLong (in->contents);
+ out->cluster = LittleShort (in->cluster);
+ out->area = LittleShort (in->area);
+ out->firstleafbrush = LittleShort (in->firstleafbrush);
+ out->numleafbrushes = LittleShort (in->numleafbrushes);
+
+ if (out->cluster >= numclusters)
+ numclusters = out->cluster + 1;
+ }
+
+ if (map_leafs[0].contents != CONTENTS_SOLID)
+ Com_Error (ERR_DROP, "Map leaf 0 is not CONTENTS_SOLID");
+ solidleaf = 0;
+ emptyleaf = -1;
+ for (i=1 ; i<numleafs ; i++)
+ {
+ if (!map_leafs[i].contents)
+ {
+ emptyleaf = i;
+ break;
+ }
+ }
+ if (emptyleaf == -1)
+ Com_Error (ERR_DROP, "Map does not have an empty leaf");
+}
+
+/*
+=================
+CMod_LoadPlanes
+=================
+*/
+void CMod_LoadPlanes (lump_t *l)
+{
+ int i, j;
+ cplane_t *out;
+ dplane_t *in;
+ int count;
+ int bits;
+
+ in = (void *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ if (count < 1)
+ Com_Error (ERR_DROP, "Map with no planes");
+ // need to save space for box planes
+ if (count > MAX_MAP_PLANES)
+ Com_Error (ERR_DROP, "Map has too many planes");
+
+ out = map_planes;
+ numplanes = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ bits = 0;
+ for (j=0 ; j<3 ; j++)
+ {
+ out->normal[j] = LittleFloat (in->normal[j]);
+ if (out->normal[j] < 0)
+ bits |= 1<<j;
+ }
+
+ out->dist = LittleFloat (in->dist);
+ out->type = LittleLong (in->type);
+ out->signbits = bits;
+ }
+}
+
+/*
+=================
+CMod_LoadLeafBrushes
+=================
+*/
+void CMod_LoadLeafBrushes (lump_t *l)
+{
+ int i;
+ unsigned short *out;
+ unsigned short *in;
+ int count;
+
+ in = (void *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ if (count < 1)
+ Com_Error (ERR_DROP, "Map with no planes");
+ // need to save space for box planes
+ if (count > MAX_MAP_LEAFBRUSHES)
+ Com_Error (ERR_DROP, "Map has too many leafbrushes");
+
+ out = map_leafbrushes;
+ numleafbrushes = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ *out = LittleShort (*in);
+}
+
+/*
+=================
+CMod_LoadBrushSides
+=================
+*/
+void CMod_LoadBrushSides (lump_t *l)
+{
+ int i, j;
+ cbrushside_t *out;
+ dbrushside_t *in;
+ int count;
+ int num;
+
+ in = (void *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ // need to save space for box planes
+ if (count > MAX_MAP_BRUSHSIDES)
+ Com_Error (ERR_DROP, "Map has too many planes");
+
+ out = map_brushsides;
+ numbrushsides = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ num = LittleShort (in->planenum);
+ out->plane = &map_planes[num];
+ j = LittleShort (in->texinfo);
+ if (j >= numtexinfo)
+ Com_Error (ERR_DROP, "Bad brushside texinfo");
+ out->surface = &map_surfaces[j];
+ }
+}
+
+/*
+=================
+CMod_LoadAreas
+=================
+*/
+void CMod_LoadAreas (lump_t *l)
+{
+ int i;
+ carea_t *out;
+ darea_t *in;
+ int count;
+
+ in = (void *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ if (count > MAX_MAP_AREAS)
+ Com_Error (ERR_DROP, "Map has too many areas");
+
+ out = map_areas;
+ numareas = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ out->numareaportals = LittleLong (in->numareaportals);
+ out->firstareaportal = LittleLong (in->firstareaportal);
+ out->floodvalid = 0;
+ out->floodnum = 0;
+ }
+}
+
+/*
+=================
+CMod_LoadAreaPortals
+=================
+*/
+void CMod_LoadAreaPortals (lump_t *l)
+{
+ int i;
+ dareaportal_t *out;
+ dareaportal_t *in;
+ int count;
+
+ in = (void *)(cmod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l->filelen / sizeof(*in);
+
+ if (count > MAX_MAP_AREAS)
+ Com_Error (ERR_DROP, "Map has too many areas");
+
+ out = map_areaportals;
+ numareaportals = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ out->portalnum = LittleLong (in->portalnum);
+ out->otherarea = LittleLong (in->otherarea);
+ }
+}
+
+/*
+=================
+CMod_LoadVisibility
+=================
+*/
+void CMod_LoadVisibility (lump_t *l)
+{
+ int i;
+
+ numvisibility = l->filelen;
+ if (l->filelen > MAX_MAP_VISIBILITY)
+ Com_Error (ERR_DROP, "Map has too large visibility lump");
+
+ memcpy (map_visibility, cmod_base + l->fileofs, l->filelen);
+
+ map_vis->numclusters = LittleLong (map_vis->numclusters);
+ for (i=0 ; i<map_vis->numclusters ; i++)
+ {
+ map_vis->bitofs[i][0] = LittleLong (map_vis->bitofs[i][0]);
+ map_vis->bitofs[i][1] = LittleLong (map_vis->bitofs[i][1]);
+ }
+}
+
+
+/*
+=================
+CMod_LoadEntityString
+=================
+*/
+void CMod_LoadEntityString (lump_t *l)
+{
+ numentitychars = l->filelen;
+ if (l->filelen > MAX_MAP_ENTSTRING)
+ Com_Error (ERR_DROP, "Map has too large entity lump");
+
+ memcpy (map_entitystring, cmod_base + l->fileofs, l->filelen);
+}
+
+
+
+/*
+==================
+CM_LoadMap
+
+Loads in the map and all submodels
+==================
+*/
+cmodel_t *CM_LoadMap (char *name, qboolean clientload, unsigned *checksum)
+{
+ unsigned *buf;
+ int i;
+ dheader_t header;
+ int length;
+ static unsigned last_checksum;
+
+ map_noareas = Cvar_Get ("map_noareas", "0", 0);
+
+ if ( !strcmp (map_name, name) && (clientload || !Cvar_VariableValue ("flushmap")) )
+ {
+ *checksum = last_checksum;
+ if (!clientload)
+ {
+ memset (portalopen, 0, sizeof(portalopen));
+ FloodAreaConnections ();
+ }
+ return &map_cmodels[0]; // still have the right version
+ }
+
+ // free old stuff
+ numplanes = 0;
+ numnodes = 0;
+ numleafs = 0;
+ numcmodels = 0;
+ numvisibility = 0;
+ numentitychars = 0;
+ map_entitystring[0] = 0;
+ map_name[0] = 0;
+
+ if (!name || !name[0])
+ {
+ numleafs = 1;
+ numclusters = 1;
+ numareas = 1;
+ *checksum = 0;
+ return &map_cmodels[0]; // cinematic servers won't have anything at all
+ }
+
+ //
+ // load the file
+ //
+ length = FS_LoadFile (name, (void **)&buf);
+ if (!buf)
+ Com_Error (ERR_DROP, "Couldn't load %s", name);
+
+ last_checksum = LittleLong (Com_BlockChecksum (buf, length));
+ *checksum = last_checksum;
+
+ header = *(dheader_t *)buf;
+ for (i=0 ; i<sizeof(dheader_t)/sizeof(int) ; i++)
+ ((int *)&header)[i] = LittleLong ( ((int *)&header)[i]);
+
+ if (header.version != BSPVERSION)
+ Com_Error (ERR_DROP, "CMod_LoadBrushModel: %s has wrong version number (%i should be %i)"
+ , name, header.version, BSPVERSION);
+
+ cmod_base = (byte *)buf;
+
+ // load into heap
+ CMod_LoadSurfaces (&header.lumps[LUMP_TEXINFO]);
+ CMod_LoadLeafs (&header.lumps[LUMP_LEAFS]);
+ CMod_LoadLeafBrushes (&header.lumps[LUMP_LEAFBRUSHES]);
+ CMod_LoadPlanes (&header.lumps[LUMP_PLANES]);
+ CMod_LoadBrushes (&header.lumps[LUMP_BRUSHES]);
+ CMod_LoadBrushSides (&header.lumps[LUMP_BRUSHSIDES]);
+ CMod_LoadSubmodels (&header.lumps[LUMP_MODELS]);
+ CMod_LoadNodes (&header.lumps[LUMP_NODES]);
+ CMod_LoadAreas (&header.lumps[LUMP_AREAS]);
+ CMod_LoadAreaPortals (&header.lumps[LUMP_AREAPORTALS]);
+ CMod_LoadVisibility (&header.lumps[LUMP_VISIBILITY]);
+ CMod_LoadEntityString (&header.lumps[LUMP_ENTITIES]);
+
+ FS_FreeFile (buf);
+
+ CM_InitBoxHull ();
+
+ memset (portalopen, 0, sizeof(portalopen));
+ FloodAreaConnections ();
+
+ strcpy (map_name, name);
+
+ return &map_cmodels[0];
+}
+
+/*
+==================
+CM_InlineModel
+==================
+*/
+cmodel_t *CM_InlineModel (char *name)
+{
+ int num;
+
+ if (!name || name[0] != '*')
+ Com_Error (ERR_DROP, "CM_InlineModel: bad name");
+ num = atoi (name+1);
+ if (num < 1 || num >= numcmodels)
+ Com_Error (ERR_DROP, "CM_InlineModel: bad number");
+
+ return &map_cmodels[num];
+}
+
+int CM_NumClusters (void)
+{
+ return numclusters;
+}
+
+int CM_NumInlineModels (void)
+{
+ return numcmodels;
+}
+
+char *CM_EntityString (void)
+{
+ return map_entitystring;
+}
+
+int CM_LeafContents (int leafnum)
+{
+ if (leafnum < 0 || leafnum >= numleafs)
+ Com_Error (ERR_DROP, "CM_LeafContents: bad number");
+ return map_leafs[leafnum].contents;
+}
+
+int CM_LeafCluster (int leafnum)
+{
+ if (leafnum < 0 || leafnum >= numleafs)
+ Com_Error (ERR_DROP, "CM_LeafCluster: bad number");
+ return map_leafs[leafnum].cluster;
+}
+
+int CM_LeafArea (int leafnum)
+{
+ if (leafnum < 0 || leafnum >= numleafs)
+ Com_Error (ERR_DROP, "CM_LeafArea: bad number");
+ return map_leafs[leafnum].area;
+}
+
+//=======================================================================
+
+
+cplane_t *box_planes;
+int box_headnode;
+cbrush_t *box_brush;
+cleaf_t *box_leaf;
+
+/*
+===================
+CM_InitBoxHull
+
+Set up the planes and nodes so that the six floats of a bounding box
+can just be stored out and get a proper clipping hull structure.
+===================
+*/
+void CM_InitBoxHull (void)
+{
+ int i;
+ int side;
+ cnode_t *c;
+ cplane_t *p;
+ cbrushside_t *s;
+
+ box_headnode = numnodes;
+ box_planes = &map_planes[numplanes];
+ if (numnodes+6 > MAX_MAP_NODES
+ || numbrushes+1 > MAX_MAP_BRUSHES
+ || numleafbrushes+1 > MAX_MAP_LEAFBRUSHES
+ || numbrushsides+6 > MAX_MAP_BRUSHSIDES
+ || numplanes+12 > MAX_MAP_PLANES)
+ Com_Error (ERR_DROP, "Not enough room for box tree");
+
+ box_brush = &map_brushes[numbrushes];
+ box_brush->numsides = 6;
+ box_brush->firstbrushside = numbrushsides;
+ box_brush->contents = CONTENTS_MONSTER;
+
+ box_leaf = &map_leafs[numleafs];
+ box_leaf->contents = CONTENTS_MONSTER;
+ box_leaf->firstleafbrush = numleafbrushes;
+ box_leaf->numleafbrushes = 1;
+
+ map_leafbrushes[numleafbrushes] = numbrushes;
+
+ for (i=0 ; i<6 ; i++)
+ {
+ side = i&1;
+
+ // brush sides
+ s = &map_brushsides[numbrushsides+i];
+ s->plane = map_planes + (numplanes+i*2+side);
+ s->surface = &nullsurface;
+
+ // nodes
+ c = &map_nodes[box_headnode+i];
+ c->plane = map_planes + (numplanes+i*2);
+ c->children[side] = -1 - emptyleaf;
+ if (i != 5)
+ c->children[side^1] = box_headnode+i + 1;
+ else
+ c->children[side^1] = -1 - numleafs;
+
+ // planes
+ p = &box_planes[i*2];
+ p->type = i>>1;
+ p->signbits = 0;
+ VectorClear (p->normal);
+ p->normal[i>>1] = 1;
+
+ p = &box_planes[i*2+1];
+ p->type = 3 + (i>>1);
+ p->signbits = 0;
+ VectorClear (p->normal);
+ p->normal[i>>1] = -1;
+ }
+}
+
+
+/*
+===================
+CM_HeadnodeForBox
+
+Creates a clipping hull for an arbitrary box
+
+To keep everything totally uniform, bounding boxes are turned into small
+BSP trees instead of being compared directly.
+===================
+*/
+int CM_HeadnodeForBox (vec3_t mins, vec3_t maxs)
+{
+ box_planes[0].dist = maxs[0];
+ box_planes[1].dist = -maxs[0];
+ box_planes[2].dist = mins[0];
+ box_planes[3].dist = -mins[0];
+ box_planes[4].dist = maxs[1];
+ box_planes[5].dist = -maxs[1];
+ box_planes[6].dist = mins[1];
+ box_planes[7].dist = -mins[1];
+ box_planes[8].dist = maxs[2];
+ box_planes[9].dist = -maxs[2];
+ box_planes[10].dist = mins[2];
+ box_planes[11].dist = -mins[2];
+
+ return box_headnode;
+}
+
+
+/*
+==================
+CM_PointLeafnum_r
+
+==================
+*/
+int CM_PointLeafnum_r (vec3_t p, int num)
+{
+ float d;
+ cnode_t *node;
+ cplane_t *plane;
+
+ while (num >= 0)
+ {
+ node = map_nodes + num;
+ plane = node->plane;
+
+ if (plane->type < 3)
+ d = p[plane->type] - plane->dist;
+ else
+ d = DotProduct (plane->normal, p) - plane->dist;
+ if (d < 0)
+ num = node->children[1];
+ else
+ num = node->children[0];
+ }
+
+ c_pointcontents++; // optimize counter
+
+ return -1 - num;
+}
+
+/* call with topnode set to the headnode, returns with topnode set to the first
+ * node that splits the box */
+int CM_PointLeafnum (vec3_t p)
+{
+ if (!numplanes)
+ return 0; // sound may call this without map loaded
+ return CM_PointLeafnum_r (p, 0);
+}
+
+
+
+/*
+=============
+CM_BoxLeafnums
+
+Fills in a list of all the leafs touched
+=============
+*/
+int leaf_count, leaf_maxcount;
+int *leaf_list;
+float *leaf_mins, *leaf_maxs;
+int leaf_topnode;
+
+void CM_BoxLeafnums_r (int nodenum)
+{
+ cplane_t *plane;
+ cnode_t *node;
+ int s;
+
+ while (1)
+ {
+ if (nodenum < 0)
+ {
+ if (leaf_count >= leaf_maxcount)
+ {
+// Com_Printf ("CM_BoxLeafnums_r: overflow\n");
+ return;
+ }
+ leaf_list[leaf_count++] = -1 - nodenum;
+ return;
+ }
+
+ node = &map_nodes[nodenum];
+ plane = node->plane;
+// s = BoxOnPlaneSide (leaf_mins, leaf_maxs, plane);
+ s = BOX_ON_PLANE_SIDE(leaf_mins, leaf_maxs, plane);
+ if (s == 1)
+ nodenum = node->children[0];
+ else if (s == 2)
+ nodenum = node->children[1];
+ else
+ { // go down both
+ if (leaf_topnode == -1)
+ leaf_topnode = nodenum;
+ CM_BoxLeafnums_r (node->children[0]);
+ nodenum = node->children[1];
+ }
+
+ }
+}
+
+int CM_BoxLeafnums_headnode (vec3_t mins, vec3_t maxs, int *list, int listsize, int headnode, int *topnode)
+{
+ leaf_list = list;
+ leaf_count = 0;
+ leaf_maxcount = listsize;
+ leaf_mins = mins;
+ leaf_maxs = maxs;
+
+ leaf_topnode = -1;
+
+ CM_BoxLeafnums_r (headnode);
+
+ if (topnode)
+ *topnode = leaf_topnode;
+
+ return leaf_count;
+}
+
+int CM_BoxLeafnums (vec3_t mins, vec3_t maxs, int *list, int listsize, int *topnode)
+{
+ return CM_BoxLeafnums_headnode (mins, maxs, list,
+ listsize, map_cmodels[0].headnode, topnode);
+}
+
+
+
+/*
+==================
+CM_PointContents
+
+==================
+*/
+int CM_PointContents (vec3_t p, int headnode)
+{
+ int l;
+
+ if (!numnodes) // map not loaded
+ return 0;
+
+ l = CM_PointLeafnum_r (p, headnode);
+
+ return map_leafs[l].contents;
+}
+
+/*
+==================
+CM_TransformedPointContents
+
+Handles offseting and rotation of the end points for moving and
+rotating entities
+==================
+*/
+int CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t angles)
+{
+ vec3_t p_l;
+ vec3_t temp;
+ vec3_t forward, right, up;
+ int l;
+
+ // subtract origin offset
+ VectorSubtract (p, origin, p_l);
+
+ // rotate start and end into the models frame of reference
+ if (headnode != box_headnode &&
+ (angles[0] || angles[1] || angles[2]) )
+ {
+ AngleVectors (angles, forward, right, up);
+
+ VectorCopy (p_l, temp);
+ p_l[0] = DotProduct (temp, forward);
+ p_l[1] = -DotProduct (temp, right);
+ p_l[2] = DotProduct (temp, up);
+ }
+
+ l = CM_PointLeafnum_r (p_l, headnode);
+
+ return map_leafs[l].contents;
+}
+
+
+/*
+===============================================================================
+
+BOX TRACING
+
+===============================================================================
+*/
+
+// 1/32 epsilon to keep floating point happy
+#define DIST_EPSILON (0.03125)
+
+vec3_t trace_start, trace_end;
+vec3_t trace_mins, trace_maxs;
+vec3_t trace_extents;
+
+trace_t trace_trace;
+int trace_contents;
+qboolean trace_ispoint; // optimized case
+
+/*
+================
+CM_ClipBoxToBrush
+================
+*/
+void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2,
+ trace_t *trace, cbrush_t *brush)
+{
+ int i, j;
+ cplane_t *plane, *clipplane;
+ float dist;
+ float enterfrac, leavefrac;
+ vec3_t ofs;
+ float d1, d2;
+ qboolean getout, startout;
+ float f;
+ cbrushside_t *side, *leadside;
+
+ enterfrac = -1;
+ leavefrac = 1;
+ clipplane = NULL;
+
+ if (!brush->numsides)
+ return;
+
+ c_brush_traces++;
+
+ getout = false;
+ startout = false;
+ leadside = NULL;
+
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ side = &map_brushsides[brush->firstbrushside+i];
+ plane = side->plane;
+
+ // FIXME: special case for axial
+
+ if (!trace_ispoint)
+ { // general box case
+
+ // push the plane out apropriately for mins/maxs
+
+ // FIXME: use signbits into 8 way lookup for each mins/maxs
+ for (j=0 ; j<3 ; j++)
+ {
+ if (plane->normal[j] < 0)
+ ofs[j] = maxs[j];
+ else
+ ofs[j] = mins[j];
+ }
+ dist = DotProduct (ofs, plane->normal);
+ dist = plane->dist - dist;
+ }
+ else
+ { // special point case
+ dist = plane->dist;
+ }
+
+ d1 = DotProduct (p1, plane->normal) - dist;
+ d2 = DotProduct (p2, plane->normal) - dist;
+
+ if (d2 > 0)
+ getout = true; // endpoint is not in solid
+ if (d1 > 0)
+ startout = true;
+
+ // if completely in front of face, no intersection
+ if (d1 > 0 && d2 >= d1)
+ return;
+
+ if (d1 <= 0 && d2 <= 0)
+ continue;
+
+ // crosses face
+ if (d1 > d2)
+ { // enter
+ f = (d1-DIST_EPSILON) / (d1-d2);
+ if (f > enterfrac)
+ {
+ enterfrac = f;
+ clipplane = plane;
+ leadside = side;
+ }
+ }
+ else
+ { // leave
+ f = (d1+DIST_EPSILON) / (d1-d2);
+ if (f < leavefrac)
+ leavefrac = f;
+ }
+ }
+
+ if (!startout)
+ { // original point was inside brush
+ trace->startsolid = true;
+ if (!getout)
+ trace->allsolid = true;
+ return;
+ }
+ if (enterfrac < leavefrac)
+ {
+ if (enterfrac > -1 && enterfrac < trace->fraction)
+ {
+ if (enterfrac < 0)
+ enterfrac = 0;
+ trace->fraction = enterfrac;
+ trace->plane = *clipplane;
+ trace->surface = &(leadside->surface->c);
+ trace->contents = brush->contents;
+ }
+ }
+}
+
+/*
+================
+CM_TestBoxInBrush
+================
+*/
+void CM_TestBoxInBrush (vec3_t mins, vec3_t maxs, vec3_t p1,
+ trace_t *trace, cbrush_t *brush)
+{
+ int i, j;
+ cplane_t *plane;
+ float dist;
+ vec3_t ofs;
+ float d1;
+ cbrushside_t *side;
+
+ if (!brush->numsides)
+ return;
+
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ side = &map_brushsides[brush->firstbrushside+i];
+ plane = side->plane;
+
+ // FIXME: special case for axial
+
+ // general box case
+
+ // push the plane out apropriately for mins/maxs
+
+ // FIXME: use signbits into 8 way lookup for each mins/maxs
+ for (j=0 ; j<3 ; j++)
+ {
+ if (plane->normal[j] < 0)
+ ofs[j] = maxs[j];
+ else
+ ofs[j] = mins[j];
+ }
+ dist = DotProduct (ofs, plane->normal);
+ dist = plane->dist - dist;
+
+ d1 = DotProduct (p1, plane->normal) - dist;
+
+ // if completely in front of face, no intersection
+ if (d1 > 0)
+ return;
+
+ }
+
+ // inside this brush
+ trace->startsolid = trace->allsolid = true;
+ trace->fraction = 0;
+ trace->contents = brush->contents;
+}
+
+
+/*
+================
+CM_TraceToLeaf
+================
+*/
+void CM_TraceToLeaf (int leafnum)
+{
+ int k;
+ int brushnum;
+ cleaf_t *leaf;
+ cbrush_t *b;
+
+ leaf = &map_leafs[leafnum];
+ if ( !(leaf->contents & trace_contents))
+ return;
+ // trace line against all brushes in the leaf
+ for (k=0 ; k<leaf->numleafbrushes ; k++)
+ {
+ brushnum = map_leafbrushes[leaf->firstleafbrush+k];
+ b = &map_brushes[brushnum];
+ if (b->checkcount == checkcount)
+ continue; // already checked this brush in another leaf
+ b->checkcount = checkcount;
+
+ if ( !(b->contents & trace_contents))
+ continue;
+ CM_ClipBoxToBrush (trace_mins, trace_maxs, trace_start, trace_end, &trace_trace, b);
+ if (!trace_trace.fraction)
+ return;
+ }
+
+}
+
+
+/*
+================
+CM_TestInLeaf
+================
+*/
+void CM_TestInLeaf (int leafnum)
+{
+ int k;
+ int brushnum;
+ cleaf_t *leaf;
+ cbrush_t *b;
+
+ leaf = &map_leafs[leafnum];
+ if ( !(leaf->contents & trace_contents))
+ return;
+ // trace line against all brushes in the leaf
+ for (k=0 ; k<leaf->numleafbrushes ; k++)
+ {
+ brushnum = map_leafbrushes[leaf->firstleafbrush+k];
+ b = &map_brushes[brushnum];
+ if (b->checkcount == checkcount)
+ continue; // already checked this brush in another leaf
+ b->checkcount = checkcount;
+
+ if ( !(b->contents & trace_contents))
+ continue;
+ CM_TestBoxInBrush (trace_mins, trace_maxs, trace_start, &trace_trace, b);
+ if (!trace_trace.fraction)
+ return;
+ }
+
+}
+
+
+/*
+==================
+CM_RecursiveHullCheck
+
+==================
+*/
+void CM_RecursiveHullCheck (int num, float p1f, float p2f, vec3_t p1, vec3_t p2)
+{
+ cnode_t *node;
+ cplane_t *plane;
+ float t1, t2, offset;
+ float frac, frac2;
+ float idist;
+ int i;
+ vec3_t mid;
+ int side;
+ float midf;
+
+ if (trace_trace.fraction <= p1f)
+ return; // already hit something nearer
+
+ // if < 0, we are in a leaf node
+ if (num < 0)
+ {
+ CM_TraceToLeaf (-1-num);
+ return;
+ }
+
+ //
+ // find the point distances to the seperating plane
+ // and the offset for the size of the box
+ //
+ node = map_nodes + num;
+ plane = node->plane;
+
+ if (plane->type < 3)
+ {
+ t1 = p1[plane->type] - plane->dist;
+ t2 = p2[plane->type] - plane->dist;
+ offset = trace_extents[plane->type];
+ }
+ else
+ {
+ t1 = DotProduct (plane->normal, p1) - plane->dist;
+ t2 = DotProduct (plane->normal, p2) - plane->dist;
+ if (trace_ispoint)
+ offset = 0;
+ else
+ offset = fabs(trace_extents[0]*plane->normal[0]) +
+ fabs(trace_extents[1]*plane->normal[1]) +
+ fabs(trace_extents[2]*plane->normal[2]);
+ }
+
+
+ /*
+ CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2);
+ CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2);
+ return;
+ */
+
+ // see which sides we need to consider
+ if (t1 >= offset && t2 >= offset)
+ {
+ CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2);
+ return;
+ }
+ if (t1 < -offset && t2 < -offset)
+ {
+ CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2);
+ return;
+ }
+
+ // put the crosspoint DIST_EPSILON pixels on the near side
+ if (t1 < t2)
+ {
+ idist = 1.0/(t1-t2);
+ side = 1;
+ frac2 = (t1 + offset + DIST_EPSILON)*idist;
+ frac = (t1 - offset + DIST_EPSILON)*idist;
+ }
+ else if (t1 > t2)
+ {
+ idist = 1.0/(t1-t2);
+ side = 0;
+ frac2 = (t1 - offset - DIST_EPSILON)*idist;
+ frac = (t1 + offset + DIST_EPSILON)*idist;
+ }
+ else
+ {
+ side = 0;
+ frac = 1;
+ frac2 = 0;
+ }
+
+ // move up to the node
+ if (frac < 0)
+ frac = 0;
+ if (frac > 1)
+ frac = 1;
+
+ midf = p1f + (p2f - p1f)*frac;
+ for (i=0 ; i<3 ; i++)
+ mid[i] = p1[i] + frac*(p2[i] - p1[i]);
+
+ CM_RecursiveHullCheck (node->children[side], p1f, midf, p1, mid);
+
+
+ // go past the node
+ if (frac2 < 0)
+ frac2 = 0;
+ if (frac2 > 1)
+ frac2 = 1;
+
+ midf = p1f + (p2f - p1f)*frac2;
+ for (i=0 ; i<3 ; i++)
+ mid[i] = p1[i] + frac2*(p2[i] - p1[i]);
+
+ CM_RecursiveHullCheck (node->children[side^1], midf, p2f, mid, p2);
+}
+
+
+
+//======================================================================
+
+/*
+==================
+CM_BoxTrace
+==================
+*/
+trace_t CM_BoxTrace (vec3_t start, vec3_t end,
+ vec3_t mins, vec3_t maxs,
+ int headnode, int brushmask)
+{
+ int i;
+
+ checkcount++; // for multi-check avoidance
+
+ c_traces++; // for statistics, may be zeroed
+
+ // fill in a default trace
+ memset (&trace_trace, 0, sizeof(trace_trace));
+ trace_trace.fraction = 1;
+ trace_trace.surface = &(nullsurface.c);
+
+ if (!numnodes) // map not loaded
+ return trace_trace;
+
+ trace_contents = brushmask;
+ VectorCopy (start, trace_start);
+ VectorCopy (end, trace_end);
+ VectorCopy (mins, trace_mins);
+ VectorCopy (maxs, trace_maxs);
+
+ //
+ // check for position test special case
+ //
+ if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2])
+ {
+ int leafs[1024];
+ int i, numleafs;
+ vec3_t c1, c2;
+ int topnode;
+
+ VectorAdd (start, mins, c1);
+ VectorAdd (start, maxs, c2);
+ for (i=0 ; i<3 ; i++)
+ {
+ c1[i] -= 1;
+ c2[i] += 1;
+ }
+
+ numleafs = CM_BoxLeafnums_headnode (c1, c2, leafs, 1024, headnode, &topnode);
+ for (i=0 ; i<numleafs ; i++)
+ {
+ CM_TestInLeaf (leafs[i]);
+ if (trace_trace.allsolid)
+ break;
+ }
+ VectorCopy (start, trace_trace.endpos);
+ return trace_trace;
+ }
+
+ //
+ // check for point special case
+ //
+ if (mins[0] == 0 && mins[1] == 0 && mins[2] == 0
+ && maxs[0] == 0 && maxs[1] == 0 && maxs[2] == 0)
+ {
+ trace_ispoint = true;
+ VectorClear (trace_extents);
+ }
+ else
+ {
+ trace_ispoint = false;
+ trace_extents[0] = -mins[0] > maxs[0] ? -mins[0] : maxs[0];
+ trace_extents[1] = -mins[1] > maxs[1] ? -mins[1] : maxs[1];
+ trace_extents[2] = -mins[2] > maxs[2] ? -mins[2] : maxs[2];
+ }
+
+ //
+ // general sweeping through world
+ //
+ CM_RecursiveHullCheck (headnode, 0, 1, start, end);
+
+ if (trace_trace.fraction == 1)
+ {
+ VectorCopy (end, trace_trace.endpos);
+ }
+ else
+ {
+ for (i=0 ; i<3 ; i++)
+ trace_trace.endpos[i] = start[i] + trace_trace.fraction * (end[i] - start[i]);
+ }
+ return trace_trace;
+}
+
+
+/*
+==================
+CM_TransformedBoxTrace
+
+Handles offseting and rotation of the end points for moving and
+rotating entities
+==================
+*/
+
+
+trace_t CM_TransformedBoxTrace (vec3_t start, vec3_t end,
+ vec3_t mins, vec3_t maxs,
+ int headnode, int brushmask,
+ vec3_t origin, vec3_t angles)
+{
+ trace_t trace;
+ vec3_t start_l, end_l;
+ vec3_t a;
+ vec3_t forward, right, up;
+ vec3_t temp;
+ qboolean rotated;
+
+ // subtract origin offset
+ VectorSubtract (start, origin, start_l);
+ VectorSubtract (end, origin, end_l);
+
+ // rotate start and end into the models frame of reference
+ if (headnode != box_headnode &&
+ (angles[0] || angles[1] || angles[2]) )
+ rotated = true;
+ else
+ rotated = false;
+
+ if (rotated)
+ {
+ AngleVectors (angles, forward, right, up);
+
+ VectorCopy (start_l, temp);
+ start_l[0] = DotProduct (temp, forward);
+ start_l[1] = -DotProduct (temp, right);
+ start_l[2] = DotProduct (temp, up);
+
+ VectorCopy (end_l, temp);
+ end_l[0] = DotProduct (temp, forward);
+ end_l[1] = -DotProduct (temp, right);
+ end_l[2] = DotProduct (temp, up);
+ }
+
+ // sweep the box through the model
+ trace = CM_BoxTrace (start_l, end_l, mins, maxs, headnode, brushmask);
+
+ if (rotated && trace.fraction != 1.0)
+ {
+ // FIXME: figure out how to do this with existing angles
+ VectorNegate (angles, a);
+ AngleVectors (a, forward, right, up);
+
+ VectorCopy (trace.plane.normal, temp);
+ trace.plane.normal[0] = DotProduct (temp, forward);
+ trace.plane.normal[1] = -DotProduct (temp, right);
+ trace.plane.normal[2] = DotProduct (temp, up);
+ }
+
+ trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]);
+ trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]);
+ trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]);
+
+ return trace;
+}
+
+/*
+===============================================================================
+
+PVS / PHS
+
+===============================================================================
+*/
+
+/*
+===================
+CM_DecompressVis
+===================
+*/
+void CM_DecompressVis (byte *in, byte *out)
+{
+ int c;
+ byte *out_p;
+ int row;
+
+ row = (numclusters+7)>>3;
+ out_p = out;
+
+ if (!in || !numvisibility)
+ { // no vis info, so make all visible
+ while (row)
+ {
+ *out_p++ = 0xff;
+ row--;
+ }
+ return;
+ }
+
+ do
+ {
+ if (*in)
+ {
+ *out_p++ = *in++;
+ continue;
+ }
+
+ c = in[1];
+ in += 2;
+ if ((out_p - out) + c > row)
+ {
+ c = row - (out_p - out);
+ Com_DPrintf ("warning: Vis decompression overrun\n");
+ }
+ while (c)
+ {
+ *out_p++ = 0;
+ c--;
+ }
+ } while (out_p - out < row);
+}
+
+byte pvsrow[MAX_MAP_LEAFS/8];
+byte phsrow[MAX_MAP_LEAFS/8];
+
+byte *CM_ClusterPVS (int cluster)
+{
+ if (cluster == -1)
+ memset (pvsrow, 0, (numclusters+7)>>3);
+ else
+ CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PVS], pvsrow);
+ return pvsrow;
+}
+
+byte *CM_ClusterPHS (int cluster)
+{
+ if (cluster == -1)
+ memset (phsrow, 0, (numclusters+7)>>3);
+ else
+ CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PHS], phsrow);
+ return phsrow;
+}
+
+
+/*
+===============================================================================
+
+AREAPORTALS
+
+===============================================================================
+*/
+
+void FloodArea_r (carea_t *area, int floodnum)
+{
+ int i;
+ dareaportal_t *p;
+
+ if (area->floodvalid == floodvalid)
+ {
+ if (area->floodnum == floodnum)
+ return;
+ Com_Error (ERR_DROP, "FloodArea_r: reflooded");
+ }
+
+ area->floodnum = floodnum;
+ area->floodvalid = floodvalid;
+ p = &map_areaportals[area->firstareaportal];
+ for (i=0 ; i<area->numareaportals ; i++, p++)
+ {
+ if (portalopen[p->portalnum])
+ FloodArea_r (&map_areas[p->otherarea], floodnum);
+ }
+}
+
+/*
+====================
+FloodAreaConnections
+
+
+====================
+*/
+void FloodAreaConnections (void)
+{
+ int i;
+ carea_t *area;
+ int floodnum;
+
+ // all current floods are now invalid
+ floodvalid++;
+ floodnum = 0;
+
+ // area 0 is not used
+ for (i=1 ; i<numareas ; i++)
+ {
+ area = &map_areas[i];
+ if (area->floodvalid == floodvalid)
+ continue; // already flooded into
+ floodnum++;
+ FloodArea_r (area, floodnum);
+ }
+
+}
+
+void CM_SetAreaPortalState (int portalnum, qboolean open)
+{
+ if (portalnum > numareaportals)
+ Com_Error (ERR_DROP, "areaportal > numareaportals");
+
+ portalopen[portalnum] = open;
+ FloodAreaConnections ();
+}
+
+qboolean CM_AreasConnected (int area1, int area2)
+{
+ if (map_noareas->value)
+ return true;
+
+ if (area1 > numareas || area2 > numareas)
+ Com_Error (ERR_DROP, "area > numareas");
+
+ if (map_areas[area1].floodnum == map_areas[area2].floodnum)
+ return true;
+ return false;
+}
+
+
+/*
+=================
+CM_WriteAreaBits
+
+Writes a length byte followed by a bit vector of all the areas
+that area in the same flood as the area parameter
+
+This is used by the client refreshes to cull visibility
+=================
+*/
+int CM_WriteAreaBits (byte *buffer, int area)
+{
+ int i;
+ int floodnum;
+ int bytes;
+
+ bytes = (numareas+7)>>3;
+
+ if (map_noareas->value)
+ { // for debugging, send everything
+ memset (buffer, 255, bytes);
+ }
+ else
+ {
+ memset (buffer, 0, bytes);
+
+ floodnum = map_areas[area].floodnum;
+ for (i=0 ; i<numareas ; i++)
+ {
+ if (map_areas[i].floodnum == floodnum || !area)
+ buffer[i>>3] |= 1<<(i&7);
+ }
+ }
+
+ return bytes;
+}
+
+
+/*
+===================
+CM_WritePortalState
+
+Writes the portal state to a savegame file
+===================
+*/
+void CM_WritePortalState (FILE *f)
+{
+ fwrite (portalopen, sizeof(portalopen), 1, f);
+}
+
+/*
+===================
+CM_ReadPortalState
+
+Reads the portal state from a savegame file
+and recalculates the area connections
+===================
+*/
+void CM_ReadPortalState (FILE *f)
+{
+ FS_Read (portalopen, sizeof(portalopen), f);
+ FloodAreaConnections ();
+}
+
+/*
+=============
+CM_HeadnodeVisible
+
+Returns true if any leaf under headnode has a cluster that
+is potentially visible
+=============
+*/
+qboolean CM_HeadnodeVisible (int nodenum, byte *visbits)
+{
+ int leafnum;
+ int cluster;
+ cnode_t *node;
+
+ if (nodenum < 0)
+ {
+ leafnum = -1-nodenum;
+ cluster = map_leafs[leafnum].cluster;
+ if (cluster == -1)
+ return false;
+ if (visbits[cluster>>3] & (1<<(cluster&7)))
+ return true;
+ return false;
+ }
+
+ node = &map_nodes[nodenum];
+ if (CM_HeadnodeVisible(node->children[0], visbits))
+ return true;
+ return CM_HeadnodeVisible(node->children[1], visbits);
+}
+
--- /dev/null
+++ b/common.c
@@ -1,0 +1,1570 @@
+// common.c -- misc functions used in client and server
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+#define MAXPRINTMSG 4096
+
+#define MAX_NUM_ARGVS 50
+
+
+int com_argc;
+char *com_argv[MAX_NUM_ARGVS+1];
+
+int realtime;
+
+jmp_buf abortframe; // an ERR_DROP occured, exit the entire frame
+
+
+FILE *log_stats_file;
+
+cvar_t *host_speeds;
+cvar_t *log_stats;
+cvar_t *developer;
+cvar_t *timescale;
+cvar_t *fixedtime;
+cvar_t *logfile_active; // 1 = buffer log, 2 = flush after each print
+cvar_t *showtrace;
+cvar_t *dedicated;
+
+FILE *logfile;
+
+int server_state;
+
+// host_speeds times
+int time_before_game;
+int time_after_game;
+int time_before_ref;
+int time_after_ref;
+
+
+
+/*
+============================================================================
+
+CLIENT / SERVER interactions
+
+============================================================================
+*/
+
+static int rd_target;
+static char *rd_buffer;
+static int rd_buffersize;
+static void (*rd_flush)(int target, char *buffer);
+
+void Com_BeginRedirect (int target, char *buffer, int buffersize, void (*flush))
+{
+ if (!target || !buffer || !buffersize || !flush)
+ return;
+ rd_target = target;
+ rd_buffer = buffer;
+ rd_buffersize = buffersize;
+ rd_flush = flush;
+
+ *rd_buffer = 0;
+}
+
+void Com_EndRedirect (void)
+{
+ rd_flush(rd_target, rd_buffer);
+
+ rd_target = 0;
+ rd_buffer = NULL;
+ rd_buffersize = 0;
+ rd_flush = NULL;
+}
+
+/*
+=============
+Com_Printf
+
+Both client and server can use this, and it will output
+to the apropriate place.
+=============
+*/
+void Com_Printf (char *fmt, ...)
+{
+ va_list argptr;
+ char msg[MAXPRINTMSG];
+
+ va_start (argptr,fmt);
+ vsprintf (msg,fmt,argptr);
+ va_end (argptr);
+
+ if (rd_target)
+ {
+ if ((strlen (msg) + strlen(rd_buffer)) > (rd_buffersize - 1))
+ {
+ rd_flush(rd_target, rd_buffer);
+ *rd_buffer = 0;
+ }
+ strcat (rd_buffer, msg);
+ return;
+ }
+
+ Con_Print (msg);
+
+ // also echo to debugging console
+ Sys_ConsoleOutput (msg);
+
+ // logfile
+ if (logfile_active && logfile_active->value)
+ {
+ char name[MAX_QPATH];
+
+ if (!logfile)
+ {
+ Com_sprintf (name, sizeof(name), "%s/qconsole.log", FS_Gamedir ());
+ logfile = fopen (name, "w");
+ }
+ if (logfile)
+ fprintf (logfile, "%s", msg);
+ if (logfile_active->value > 1)
+ fflush (logfile); // force it to save every time
+ }
+}
+
+
+/*
+================
+Com_DPrintf
+
+A Com_Printf that only shows up if the "developer" cvar is set
+================
+*/
+void Com_DPrintf (char *fmt, ...)
+{
+ va_list argptr;
+ char msg[MAXPRINTMSG];
+
+ if (!developer || !developer->value)
+ return; // don't confuse non-developers with techie stuff...
+
+ va_start (argptr,fmt);
+ vsprintf (msg,fmt,argptr);
+ va_end (argptr);
+
+ Com_Printf ("%s", msg);
+}
+
+
+/*
+=============
+Com_Error
+
+Both client and server can use this, and it will
+do the apropriate things.
+=============
+*/
+void Com_Error (int code, char *fmt, ...)
+{
+ va_list argptr;
+ static char msg[MAXPRINTMSG];
+ static qboolean recursive;
+
+ if (recursive)
+ Sys_Error ("recursive error after: %s", msg);
+ recursive = true;
+
+ va_start (argptr,fmt);
+ vsprintf (msg,fmt,argptr);
+ va_end (argptr);
+
+ if (code == ERR_DISCONNECT)
+ {
+ CL_Drop ();
+ recursive = false;
+ longjmp (abortframe, -1);
+ }
+ else if (code == ERR_DROP)
+ {
+ Com_Printf ("********************\nERROR: %s\n********************\n", msg);
+ SV_Shutdown (va("Server crashed: %s\n", msg), false);
+ CL_Drop ();
+ recursive = false;
+ longjmp (abortframe, -1);
+ }
+ else
+ {
+ SV_Shutdown (va("Server fatal crashed: %s\n", msg), false);
+ CL_Shutdown ();
+ }
+
+ if (logfile)
+ {
+ fclose (logfile);
+ logfile = NULL;
+ }
+
+ Sys_Error ("%s", msg);
+}
+
+
+/*
+=============
+Com_Quit
+
+Both client and server can use this, and it will
+do the apropriate things.
+=============
+*/
+void Com_Quit (void)
+{
+ SV_Shutdown ("Server quit\n", false);
+ CL_Shutdown ();
+
+ if (logfile)
+ {
+ fclose (logfile);
+ logfile = NULL;
+ }
+
+ Sys_Quit ();
+}
+
+
+/*
+==================
+Com_ServerState
+==================
+*/
+// this should've just been a cvar...
+int Com_ServerState (void)
+{
+ return server_state;
+}
+
+/*
+==================
+Com_SetServerState
+==================
+*/
+void Com_SetServerState (int state)
+{
+ server_state = state;
+}
+
+
+/*
+==============================================================================
+
+ MESSAGE IO FUNCTIONS
+
+Handles byte ordering and avoids alignment errors
+==============================================================================
+*/
+
+vec3_t bytedirs[NUMVERTEXNORMALS] =
+{
+#include "anorms.h"
+};
+
+//
+// writing functions
+//
+
+void MSG_WriteChar (sizebuf_t *sb, int c)
+{
+ byte *buf;
+
+#ifdef PARANOID
+ if (c < -128 || c > 127)
+ Com_Error (ERR_FATAL, "MSG_WriteChar: range error");
+#endif
+
+ buf = SZ_GetSpace (sb, 1);
+ buf[0] = c;
+}
+
+void MSG_WriteByte (sizebuf_t *sb, int c)
+{
+ byte *buf;
+
+#ifdef PARANOID
+ if (c < 0 || c > 255)
+ Com_Error (ERR_FATAL, "MSG_WriteByte: range error");
+#endif
+
+ buf = SZ_GetSpace (sb, 1);
+ buf[0] = c;
+}
+
+void MSG_WriteShort (sizebuf_t *sb, int c)
+{
+ byte *buf;
+
+#ifdef PARANOID
+ if (c < ((short)0x8000) || c > (short)0x7fff)
+ Com_Error (ERR_FATAL, "MSG_WriteShort: range error");
+#endif
+
+ buf = SZ_GetSpace (sb, 2);
+ buf[0] = c&0xff;
+ buf[1] = c>>8;
+}
+
+void MSG_WriteLong (sizebuf_t *sb, int c)
+{
+ byte *buf;
+
+ buf = SZ_GetSpace (sb, 4);
+ buf[0] = c&0xff;
+ buf[1] = (c>>8)&0xff;
+ buf[2] = (c>>16)&0xff;
+ buf[3] = c>>24;
+}
+
+void MSG_WriteFloat (sizebuf_t *sb, float f)
+{
+ union
+ {
+ float f;
+ int l;
+ } dat;
+
+
+ dat.f = f;
+ dat.l = LittleLong (dat.l);
+
+ SZ_Write (sb, &dat.l, 4);
+}
+
+void MSG_WriteString (sizebuf_t *sb, char *s)
+{
+ if (!s)
+ SZ_Write (sb, "", 1);
+ else
+ SZ_Write (sb, s, strlen(s)+1);
+}
+
+void MSG_WriteCoord (sizebuf_t *sb, float f)
+{
+ MSG_WriteShort (sb, (int)(f*8));
+}
+
+void MSG_WritePos (sizebuf_t *sb, vec3_t pos)
+{
+ MSG_WriteShort (sb, (int)(pos[0]*8));
+ MSG_WriteShort (sb, (int)(pos[1]*8));
+ MSG_WriteShort (sb, (int)(pos[2]*8));
+}
+
+void MSG_WriteAngle (sizebuf_t *sb, float f)
+{
+ MSG_WriteByte (sb, (int)(f*256/360) & 255);
+}
+
+void MSG_WriteAngle16 (sizebuf_t *sb, float f)
+{
+ MSG_WriteShort (sb, ANGLE2SHORT(f));
+}
+
+
+void MSG_WriteDeltaUsercmd (sizebuf_t *buf, usercmd_t *from, usercmd_t *cmd)
+{
+ int bits;
+
+//
+// send the movement message
+//
+ bits = 0;
+ if (cmd->angles[0] != from->angles[0])
+ bits |= CM_ANGLE1;
+ if (cmd->angles[1] != from->angles[1])
+ bits |= CM_ANGLE2;
+ if (cmd->angles[2] != from->angles[2])
+ bits |= CM_ANGLE3;
+ if (cmd->forwardmove != from->forwardmove)
+ bits |= CM_FORWARD;
+ if (cmd->sidemove != from->sidemove)
+ bits |= CM_SIDE;
+ if (cmd->upmove != from->upmove)
+ bits |= CM_UP;
+ if (cmd->buttons != from->buttons)
+ bits |= CM_BUTTONS;
+ if (cmd->impulse != from->impulse)
+ bits |= CM_IMPULSE;
+
+ MSG_WriteByte (buf, bits);
+
+ if (bits & CM_ANGLE1)
+ MSG_WriteShort (buf, cmd->angles[0]);
+ if (bits & CM_ANGLE2)
+ MSG_WriteShort (buf, cmd->angles[1]);
+ if (bits & CM_ANGLE3)
+ MSG_WriteShort (buf, cmd->angles[2]);
+
+ if (bits & CM_FORWARD)
+ MSG_WriteShort (buf, cmd->forwardmove);
+ if (bits & CM_SIDE)
+ MSG_WriteShort (buf, cmd->sidemove);
+ if (bits & CM_UP)
+ MSG_WriteShort (buf, cmd->upmove);
+
+ if (bits & CM_BUTTONS)
+ MSG_WriteByte (buf, cmd->buttons);
+ if (bits & CM_IMPULSE)
+ MSG_WriteByte (buf, cmd->impulse);
+
+ MSG_WriteByte (buf, cmd->msec);
+ MSG_WriteByte (buf, cmd->lightlevel);
+}
+
+
+void MSG_WriteDir (sizebuf_t *sb, vec3_t dir)
+{
+ int i, best;
+ float d, bestd;
+
+ if (!dir)
+ {
+ MSG_WriteByte (sb, 0);
+ return;
+ }
+
+ bestd = 0;
+ best = 0;
+ for (i=0 ; i<NUMVERTEXNORMALS ; i++)
+ {
+ d = DotProduct (dir, bytedirs[i]);
+ if (d > bestd)
+ {
+ bestd = d;
+ best = i;
+ }
+ }
+ MSG_WriteByte (sb, best);
+}
+
+
+void MSG_ReadDir (sizebuf_t *sb, vec3_t dir)
+{
+ int b;
+
+ b = MSG_ReadByte (sb);
+ if (b >= NUMVERTEXNORMALS)
+ Com_Error (ERR_DROP, "MSF_ReadDir: out of range");
+ VectorCopy (bytedirs[b], dir);
+}
+
+
+/*
+==================
+MSG_WriteDeltaEntity
+
+Writes part of a packetentities message.
+Can delta from either a baseline or a previous packet_entity
+==================
+*/
+void MSG_WriteDeltaEntity (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, qboolean newentity)
+{
+ int bits;
+
+ if (!to->number)
+ Com_Error (ERR_FATAL, "Unset entity number");
+ if (to->number >= MAX_EDICTS)
+ Com_Error (ERR_FATAL, "Entity number >= MAX_EDICTS");
+
+// send an update
+ bits = 0;
+
+ if (to->number >= 256)
+ bits |= U_NUMBER16; // number8 is implicit otherwise
+
+ if (to->origin[0] != from->origin[0])
+ bits |= U_ORIGIN1;
+ if (to->origin[1] != from->origin[1])
+ bits |= U_ORIGIN2;
+ if (to->origin[2] != from->origin[2])
+ bits |= U_ORIGIN3;
+
+ if ( to->angles[0] != from->angles[0] )
+ bits |= U_ANGLE1;
+ if ( to->angles[1] != from->angles[1] )
+ bits |= U_ANGLE2;
+ if ( to->angles[2] != from->angles[2] )
+ bits |= U_ANGLE3;
+
+ if ( to->skinnum != from->skinnum )
+ {
+ if ((unsigned)to->skinnum < 256)
+ bits |= U_SKIN8;
+ else if ((unsigned)to->skinnum < 0x10000)
+ bits |= U_SKIN16;
+ else
+ bits |= (U_SKIN8|U_SKIN16);
+ }
+
+ if ( to->frame != from->frame )
+ {
+ if (to->frame < 256)
+ bits |= U_FRAME8;
+ else
+ bits |= U_FRAME16;
+ }
+
+ if ( to->effects != from->effects )
+ {
+ if (to->effects < 256)
+ bits |= U_EFFECTS8;
+ else if (to->effects < 0x8000)
+ bits |= U_EFFECTS16;
+ else
+ bits |= U_EFFECTS8|U_EFFECTS16;
+ }
+
+ if ( to->renderfx != from->renderfx )
+ {
+ if (to->renderfx < 256)
+ bits |= U_RENDERFX8;
+ else if (to->renderfx < 0x8000)
+ bits |= U_RENDERFX16;
+ else
+ bits |= U_RENDERFX8|U_RENDERFX16;
+ }
+
+ if ( to->solid != from->solid )
+ bits |= U_SOLID;
+
+ // event is not delta compressed, just 0 compressed
+ if ( to->event )
+ bits |= U_EVENT;
+
+ if ( to->modelindex != from->modelindex )
+ bits |= U_MODEL;
+ if ( to->modelindex2 != from->modelindex2 )
+ bits |= U_MODEL2;
+ if ( to->modelindex3 != from->modelindex3 )
+ bits |= U_MODEL3;
+ if ( to->modelindex4 != from->modelindex4 )
+ bits |= U_MODEL4;
+
+ if ( to->sound != from->sound )
+ bits |= U_SOUND;
+
+ if (newentity || (to->renderfx & RF_BEAM))
+ bits |= U_OLDORIGIN;
+
+ //
+ // write the message
+ //
+ if (!bits && !force)
+ return; // nothing to send!
+
+ //----------
+
+ if (bits & 0xff000000)
+ bits |= U_MOREBITS3 | U_MOREBITS2 | U_MOREBITS1;
+ else if (bits & 0x00ff0000)
+ bits |= U_MOREBITS2 | U_MOREBITS1;
+ else if (bits & 0x0000ff00)
+ bits |= U_MOREBITS1;
+
+ MSG_WriteByte (msg, bits&255 );
+
+ if (bits & 0xff000000)
+ {
+ MSG_WriteByte (msg, (bits>>8)&255 );
+ MSG_WriteByte (msg, (bits>>16)&255 );
+ MSG_WriteByte (msg, (bits>>24)&255 );
+ }
+ else if (bits & 0x00ff0000)
+ {
+ MSG_WriteByte (msg, (bits>>8)&255 );
+ MSG_WriteByte (msg, (bits>>16)&255 );
+ }
+ else if (bits & 0x0000ff00)
+ {
+ MSG_WriteByte (msg, (bits>>8)&255 );
+ }
+
+ //----------
+
+ if (bits & U_NUMBER16)
+ MSG_WriteShort (msg, to->number);
+ else
+ MSG_WriteByte (msg, to->number);
+
+ if (bits & U_MODEL)
+ MSG_WriteByte (msg, to->modelindex);
+ if (bits & U_MODEL2)
+ MSG_WriteByte (msg, to->modelindex2);
+ if (bits & U_MODEL3)
+ MSG_WriteByte (msg, to->modelindex3);
+ if (bits & U_MODEL4)
+ MSG_WriteByte (msg, to->modelindex4);
+
+ if (bits & U_FRAME8)
+ MSG_WriteByte (msg, to->frame);
+ if (bits & U_FRAME16)
+ MSG_WriteShort (msg, to->frame);
+
+ if ((bits & U_SKIN8) && (bits & U_SKIN16)) //used for laser colors
+ MSG_WriteLong (msg, to->skinnum);
+ else if (bits & U_SKIN8)
+ MSG_WriteByte (msg, to->skinnum);
+ else if (bits & U_SKIN16)
+ MSG_WriteShort (msg, to->skinnum);
+
+
+ if ( (bits & (U_EFFECTS8|U_EFFECTS16)) == (U_EFFECTS8|U_EFFECTS16) )
+ MSG_WriteLong (msg, to->effects);
+ else if (bits & U_EFFECTS8)
+ MSG_WriteByte (msg, to->effects);
+ else if (bits & U_EFFECTS16)
+ MSG_WriteShort (msg, to->effects);
+
+ if ( (bits & (U_RENDERFX8|U_RENDERFX16)) == (U_RENDERFX8|U_RENDERFX16) )
+ MSG_WriteLong (msg, to->renderfx);
+ else if (bits & U_RENDERFX8)
+ MSG_WriteByte (msg, to->renderfx);
+ else if (bits & U_RENDERFX16)
+ MSG_WriteShort (msg, to->renderfx);
+
+ if (bits & U_ORIGIN1)
+ MSG_WriteCoord (msg, to->origin[0]);
+ if (bits & U_ORIGIN2)
+ MSG_WriteCoord (msg, to->origin[1]);
+ if (bits & U_ORIGIN3)
+ MSG_WriteCoord (msg, to->origin[2]);
+
+ if (bits & U_ANGLE1)
+ MSG_WriteAngle(msg, to->angles[0]);
+ if (bits & U_ANGLE2)
+ MSG_WriteAngle(msg, to->angles[1]);
+ if (bits & U_ANGLE3)
+ MSG_WriteAngle(msg, to->angles[2]);
+
+ if (bits & U_OLDORIGIN)
+ {
+ MSG_WriteCoord (msg, to->old_origin[0]);
+ MSG_WriteCoord (msg, to->old_origin[1]);
+ MSG_WriteCoord (msg, to->old_origin[2]);
+ }
+
+ if (bits & U_SOUND)
+ MSG_WriteByte (msg, to->sound);
+ if (bits & U_EVENT)
+ MSG_WriteByte (msg, to->event);
+ if (bits & U_SOLID)
+ MSG_WriteShort (msg, to->solid);
+}
+
+
+//============================================================
+
+//
+// reading functions
+//
+
+void MSG_BeginReading (sizebuf_t *msg)
+{
+ msg->readcount = 0;
+}
+
+// returns -1 if no more characters are available
+int MSG_ReadChar (sizebuf_t *msg_read)
+{
+ int c;
+
+ if (msg_read->readcount+1 > msg_read->cursize)
+ c = -1;
+ else
+ c = (signed char)msg_read->data[msg_read->readcount];
+ msg_read->readcount++;
+
+ return c;
+}
+
+int MSG_ReadByte (sizebuf_t *msg_read)
+{
+ int c;
+
+ if (msg_read->readcount+1 > msg_read->cursize)
+ c = -1;
+ else
+ c = (unsigned char)msg_read->data[msg_read->readcount];
+ msg_read->readcount++;
+
+ return c;
+}
+
+int MSG_ReadShort (sizebuf_t *msg_read)
+{
+ int c;
+
+ if (msg_read->readcount+2 > msg_read->cursize)
+ c = -1;
+ else
+ c = (short)(msg_read->data[msg_read->readcount]
+ + (msg_read->data[msg_read->readcount+1]<<8));
+
+ msg_read->readcount += 2;
+
+ return c;
+}
+
+int MSG_ReadLong (sizebuf_t *msg_read)
+{
+ int c;
+
+ if (msg_read->readcount+4 > msg_read->cursize)
+ c = -1;
+ else
+ c = msg_read->data[msg_read->readcount]
+ + (msg_read->data[msg_read->readcount+1]<<8)
+ + (msg_read->data[msg_read->readcount+2]<<16)
+ + (msg_read->data[msg_read->readcount+3]<<24);
+
+ msg_read->readcount += 4;
+
+ return c;
+}
+
+float MSG_ReadFloat (sizebuf_t *msg_read)
+{
+ union
+ {
+ byte b[4];
+ float f;
+ int l;
+ } dat;
+
+ if (msg_read->readcount+4 > msg_read->cursize)
+ dat.f = -1;
+ else
+ {
+ dat.b[0] = msg_read->data[msg_read->readcount];
+ dat.b[1] = msg_read->data[msg_read->readcount+1];
+ dat.b[2] = msg_read->data[msg_read->readcount+2];
+ dat.b[3] = msg_read->data[msg_read->readcount+3];
+ }
+ msg_read->readcount += 4;
+
+ dat.l = LittleLong (dat.l);
+
+ return dat.f;
+}
+
+char *MSG_ReadString (sizebuf_t *msg_read)
+{
+ static char string[2048];
+ int l,c;
+
+ l = 0;
+ do
+ {
+ c = MSG_ReadChar (msg_read);
+ if (c == -1 || c == 0)
+ break;
+ string[l] = c;
+ l++;
+ } while (l < sizeof(string)-1);
+
+ string[l] = 0;
+
+ return string;
+}
+
+char *MSG_ReadStringLine (sizebuf_t *msg_read)
+{
+ static char string[2048];
+ int l,c;
+
+ l = 0;
+ do
+ {
+ c = MSG_ReadChar (msg_read);
+ if (c == -1 || c == 0 || c == '\n')
+ break;
+ string[l] = c;
+ l++;
+ } while (l < sizeof(string)-1);
+
+ string[l] = 0;
+
+ return string;
+}
+
+float MSG_ReadCoord (sizebuf_t *msg_read)
+{
+ return MSG_ReadShort(msg_read) * (1.0/8);
+}
+
+void MSG_ReadPos (sizebuf_t *msg_read, vec3_t pos)
+{
+ pos[0] = MSG_ReadShort(msg_read) * (1.0/8);
+ pos[1] = MSG_ReadShort(msg_read) * (1.0/8);
+ pos[2] = MSG_ReadShort(msg_read) * (1.0/8);
+}
+
+float MSG_ReadAngle (sizebuf_t *msg_read)
+{
+ return MSG_ReadChar(msg_read) * (360.0/256);
+}
+
+float MSG_ReadAngle16 (sizebuf_t *msg_read)
+{
+ return SHORT2ANGLE(MSG_ReadShort(msg_read));
+}
+
+void MSG_ReadDeltaUsercmd (sizebuf_t *msg_read, usercmd_t *from, usercmd_t *move)
+{
+ int bits;
+
+ memcpy (move, from, sizeof(*move));
+
+ bits = MSG_ReadByte (msg_read);
+
+// read current angles
+ if (bits & CM_ANGLE1)
+ move->angles[0] = MSG_ReadShort (msg_read);
+ if (bits & CM_ANGLE2)
+ move->angles[1] = MSG_ReadShort (msg_read);
+ if (bits & CM_ANGLE3)
+ move->angles[2] = MSG_ReadShort (msg_read);
+
+// read movement
+ if (bits & CM_FORWARD)
+ move->forwardmove = MSG_ReadShort (msg_read);
+ if (bits & CM_SIDE)
+ move->sidemove = MSG_ReadShort (msg_read);
+ if (bits & CM_UP)
+ move->upmove = MSG_ReadShort (msg_read);
+
+// read buttons
+ if (bits & CM_BUTTONS)
+ move->buttons = MSG_ReadByte (msg_read);
+
+ if (bits & CM_IMPULSE)
+ move->impulse = MSG_ReadByte (msg_read);
+
+// read time to run command
+ move->msec = MSG_ReadByte (msg_read);
+
+// read the light level
+ move->lightlevel = MSG_ReadByte (msg_read);
+}
+
+
+void MSG_ReadData (sizebuf_t *msg_read, void *data, int len)
+{
+ int i;
+
+ for (i=0 ; i<len ; i++)
+ ((byte *)data)[i] = MSG_ReadByte (msg_read);
+}
+
+
+//===========================================================================
+
+void SZ_Init (sizebuf_t *buf, byte *data, int length)
+{
+ memset (buf, 0, sizeof(*buf));
+ buf->data = data;
+ buf->maxsize = length;
+}
+
+void SZ_Clear (sizebuf_t *buf)
+{
+ buf->cursize = 0;
+ buf->overflowed = false;
+}
+
+void *SZ_GetSpace (sizebuf_t *buf, int length)
+{
+ void *data;
+
+ if (buf->cursize + length > buf->maxsize)
+ {
+ if (!buf->allowoverflow)
+ Com_Error (ERR_FATAL, "SZ_GetSpace: overflow without allowoverflow set");
+
+ if (length > buf->maxsize)
+ Com_Error (ERR_FATAL, "SZ_GetSpace: %i is > full buffer size", length);
+
+ Com_Printf ("SZ_GetSpace: overflow\n");
+ SZ_Clear (buf);
+ buf->overflowed = true;
+ }
+
+ data = buf->data + buf->cursize;
+ buf->cursize += length;
+
+ return data;
+}
+
+void SZ_Write (sizebuf_t *buf, void *data, int length)
+{
+ memcpy (SZ_GetSpace(buf,length),data,length);
+}
+
+void SZ_Print (sizebuf_t *buf, char *data)
+{
+ int len;
+
+ len = strlen(data)+1;
+
+ if (buf->cursize)
+ {
+ if (buf->data[buf->cursize-1])
+ memcpy ((byte *)SZ_GetSpace(buf, len),data,len); // no trailing 0
+ else
+ memcpy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0
+ }
+ else
+ memcpy ((byte *)SZ_GetSpace(buf, len),data,len);
+}
+
+
+//============================================================================
+
+
+/*
+================
+COM_CheckParm
+
+Returns the position (1 to argc-1) in the program's argument list
+where the given parameter apears, or 0 if not present
+================
+*/
+int COM_CheckParm (char *parm)
+{
+ int i;
+
+ for (i=1 ; i<com_argc ; i++)
+ {
+ if (!strcmp (parm,com_argv[i]))
+ return i;
+ }
+
+ return 0;
+}
+
+int COM_Argc (void)
+{
+ return com_argc;
+}
+
+char *COM_Argv (int arg)
+{
+ if (arg < 0 || arg >= com_argc || !com_argv[arg])
+ return "";
+ return com_argv[arg];
+}
+
+void COM_ClearArgv (int arg)
+{
+ if (arg < 0 || arg >= com_argc || !com_argv[arg])
+ return;
+ com_argv[arg] = "";
+}
+
+
+/*
+================
+COM_InitArgv
+================
+*/
+void COM_InitArgv (int argc, char **argv)
+{
+ int i;
+
+ if (argc > MAX_NUM_ARGVS)
+ Com_Error (ERR_FATAL, "argc > MAX_NUM_ARGVS");
+ com_argc = argc;
+ for (i=0 ; i<argc ; i++)
+ {
+ if (!argv[i] || strlen(argv[i]) >= MAX_TOKEN_CHARS )
+ com_argv[i] = "";
+ else
+ com_argv[i] = argv[i];
+ }
+}
+
+/*
+================
+COM_AddParm
+
+Adds the given string at the end of the current argument list
+================
+*/
+void COM_AddParm (char *parm)
+{
+ if (com_argc == MAX_NUM_ARGVS)
+ Com_Error (ERR_FATAL, "COM_AddParm: MAX_NUM)ARGS");
+ com_argv[com_argc++] = parm;
+}
+
+
+
+
+/// just for debugging
+int memsearch (byte *start, int count, int search)
+{
+ int i;
+
+ for (i=0 ; i<count ; i++)
+ if (start[i] == search)
+ return i;
+ return -1;
+}
+
+
+char *CopyString (char *in)
+{
+ char *out;
+
+ out = Z_Malloc (strlen(in)+1);
+ strcpy (out, in);
+ return out;
+}
+
+
+
+void Info_Print (char *s)
+{
+ char key[512];
+ char value[512];
+ char *o;
+ int l;
+
+ if (*s == '\\')
+ s++;
+ while (*s)
+ {
+ o = key;
+ while (*s && *s != '\\')
+ *o++ = *s++;
+
+ l = o - key;
+ if (l < 20)
+ {
+ memset (o, ' ', 20-l);
+ key[20] = 0;
+ }
+ else
+ *o = 0;
+ Com_Printf ("%s", key);
+
+ if (!*s)
+ {
+ Com_Printf ("MISSING VALUE\n");
+ return;
+ }
+
+ o = value;
+ s++;
+ while (*s && *s != '\\')
+ *o++ = *s++;
+ *o = 0;
+
+ if (*s)
+ s++;
+ Com_Printf ("%s\n", value);
+ }
+}
+
+
+/*
+==============================================================================
+
+ ZONE MEMORY ALLOCATION
+
+just cleared malloc with counters now...
+
+==============================================================================
+*/
+
+#define Z_MAGIC 0x1d1d
+
+typedef struct zhead_t zhead_t;
+struct zhead_t{
+ zhead_t *prev;
+ zhead_t *next;
+ short magic;
+ short tag; // for group free
+ int size;
+};
+zhead_t z_chain;
+int z_count;
+int z_bytes;
+
+
+/*
+========================
+Z_Free
+========================
+*/
+void Z_Free (void *ptr)
+{
+ zhead_t *z;
+
+ z = ((zhead_t *)ptr) - 1;
+
+ if (z->magic != Z_MAGIC)
+ Com_Error (ERR_FATAL, "Z_Free: bad magic");
+
+ z->prev->next = z->next;
+ z->next->prev = z->prev;
+
+ z_count--;
+ z_bytes -= z->size;
+ free (z);
+}
+
+
+/*
+========================
+Z_Stats_f
+========================
+*/
+void Z_Stats_f (void)
+{
+ Com_Printf ("%i bytes in %i blocks\n", z_bytes, z_count);
+}
+
+/*
+========================
+Z_FreeTags
+========================
+*/
+void Z_FreeTags (int tag)
+{
+ zhead_t *z, *next;
+
+ for (z=z_chain.next ; z != &z_chain ; z=next)
+ {
+ next = z->next;
+ if (z->tag == tag)
+ Z_Free ((void *)(z+1));
+ }
+}
+
+/*
+========================
+Z_TagMalloc
+========================
+*/
+void *Z_TagMalloc (int size, int tag)
+{
+ zhead_t *z;
+
+ size = size + sizeof(*z);
+ z = malloc(size);
+ if (!z)
+ Com_Error (ERR_FATAL, "Z_Malloc: failed on allocation of %i bytes",size);
+ memset (z, 0, size);
+ z_count++;
+ z_bytes += size;
+ z->magic = Z_MAGIC;
+ z->tag = tag;
+ z->size = size;
+
+ z->next = z_chain.next;
+ z->prev = &z_chain;
+ z_chain.next->prev = z;
+ z_chain.next = z;
+
+ return (void *)(z+1);
+}
+
+/*
+========================
+Z_Malloc
+========================
+*/
+void *Z_Malloc (int size)
+{
+ return Z_TagMalloc (size, 0);
+}
+
+
+//============================================================================
+
+
+/*
+====================
+COM_BlockSequenceCheckByte
+
+For proxy protecting
+
+// THIS IS MASSIVELY BROKEN! CHALLENGE MAY BE NEGATIVE
+// DON'T USE THIS FUNCTION!!!!!
+
+====================
+*/
+byte COM_BlockSequenceCheckByte (byte */*base*/, int /*length*/, int /*sequence*/, int /*challenge*/)
+{
+ Sys_Error("COM_BlockSequenceCheckByte called\n");
+
+/*
+ int checksum;
+ byte buf[68];
+ byte *p;
+ float temp;
+ byte c;
+
+ temp = bytedirs[(sequence/3) % NUMVERTEXNORMALS][sequence % 3];
+ temp = LittleFloat(temp);
+ p = ((byte *)&temp);
+
+ if (length > 60)
+ length = 60;
+ memcpy (buf, base, length);
+
+ buf[length] = (sequence & 0xff) ^ p[0];
+ buf[length+1] = p[1];
+ buf[length+2] = ((sequence>>8) & 0xff) ^ p[2];
+ buf[length+3] = p[3];
+
+ temp = bytedirs[((sequence+challenge)/3) % NUMVERTEXNORMALS][(sequence+challenge) % 3];
+ temp = LittleFloat(temp);
+ p = ((byte *)&temp);
+
+ buf[length+4] = (sequence & 0xff) ^ p[3];
+ buf[length+5] = (challenge & 0xff) ^ p[2];
+ buf[length+6] = ((sequence>>8) & 0xff) ^ p[1];
+ buf[length+7] = ((challenge >> 7) & 0xff) ^ p[0];
+
+ length += 8;
+
+ checksum = LittleLong(Com_BlockChecksum (buf, length));
+
+ checksum &= 0xff;
+
+ return checksum;
+*/
+ return 0;
+}
+
+static byte chktbl[1024] = {
+0x84, 0x47, 0x51, 0xc1, 0x93, 0x22, 0x21, 0x24, 0x2f, 0x66, 0x60, 0x4d, 0xb0, 0x7c, 0xda,
+0x88, 0x54, 0x15, 0x2b, 0xc6, 0x6c, 0x89, 0xc5, 0x9d, 0x48, 0xee, 0xe6, 0x8a, 0xb5, 0xf4,
+0xcb, 0xfb, 0xf1, 0x0c, 0x2e, 0xa0, 0xd7, 0xc9, 0x1f, 0xd6, 0x06, 0x9a, 0x09, 0x41, 0x54,
+0x67, 0x46, 0xc7, 0x74, 0xe3, 0xc8, 0xb6, 0x5d, 0xa6, 0x36, 0xc4, 0xab, 0x2c, 0x7e, 0x85,
+0xa8, 0xa4, 0xa6, 0x4d, 0x96, 0x19, 0x19, 0x9a, 0xcc, 0xd8, 0xac, 0x39, 0x5e, 0x3c, 0xf2,
+0xf5, 0x5a, 0x72, 0xe5, 0xa9, 0xd1, 0xb3, 0x23, 0x82, 0x6f, 0x29, 0xcb, 0xd1, 0xcc, 0x71,
+0xfb, 0xea, 0x92, 0xeb, 0x1c, 0xca, 0x4c, 0x70, 0xfe, 0x4d, 0xc9, 0x67, 0x43, 0x47, 0x94,
+0xb9, 0x47, 0xbc, 0x3f, 0x01, 0xab, 0x7b, 0xa6, 0xe2, 0x76, 0xef, 0x5a, 0x7a, 0x29, 0x0b,
+0x51, 0x54, 0x67, 0xd8, 0x1c, 0x14, 0x3e, 0x29, 0xec, 0xe9, 0x2d, 0x48, 0x67, 0xff, 0xed,
+0x54, 0x4f, 0x48, 0xc0, 0xaa, 0x61, 0xf7, 0x78, 0x12, 0x03, 0x7a, 0x9e, 0x8b, 0xcf, 0x83,
+0x7b, 0xae, 0xca, 0x7b, 0xd9, 0xe9, 0x53, 0x2a, 0xeb, 0xd2, 0xd8, 0xcd, 0xa3, 0x10, 0x25,
+0x78, 0x5a, 0xb5, 0x23, 0x06, 0x93, 0xb7, 0x84, 0xd2, 0xbd, 0x96, 0x75, 0xa5, 0x5e, 0xcf,
+0x4e, 0xe9, 0x50, 0xa1, 0xe6, 0x9d, 0xb1, 0xe3, 0x85, 0x66, 0x28, 0x4e, 0x43, 0xdc, 0x6e,
+0xbb, 0x33, 0x9e, 0xf3, 0x0d, 0x00, 0xc1, 0xcf, 0x67, 0x34, 0x06, 0x7c, 0x71, 0xe3, 0x63,
+0xb7, 0xb7, 0xdf, 0x92, 0xc4, 0xc2, 0x25, 0x5c, 0xff, 0xc3, 0x6e, 0xfc, 0xaa, 0x1e, 0x2a,
+0x48, 0x11, 0x1c, 0x36, 0x68, 0x78, 0x86, 0x79, 0x30, 0xc3, 0xd6, 0xde, 0xbc, 0x3a, 0x2a,
+0x6d, 0x1e, 0x46, 0xdd, 0xe0, 0x80, 0x1e, 0x44, 0x3b, 0x6f, 0xaf, 0x31, 0xda, 0xa2, 0xbd,
+0x77, 0x06, 0x56, 0xc0, 0xb7, 0x92, 0x4b, 0x37, 0xc0, 0xfc, 0xc2, 0xd5, 0xfb, 0xa8, 0xda,
+0xf5, 0x57, 0xa8, 0x18, 0xc0, 0xdf, 0xe7, 0xaa, 0x2a, 0xe0, 0x7c, 0x6f, 0x77, 0xb1, 0x26,
+0xba, 0xf9, 0x2e, 0x1d, 0x16, 0xcb, 0xb8, 0xa2, 0x44, 0xd5, 0x2f, 0x1a, 0x79, 0x74, 0x87,
+0x4b, 0x00, 0xc9, 0x4a, 0x3a, 0x65, 0x8f, 0xe6, 0x5d, 0xe5, 0x0a, 0x77, 0xd8, 0x1a, 0x14,
+0x41, 0x75, 0xb1, 0xe2, 0x50, 0x2c, 0x93, 0x38, 0x2b, 0x6d, 0xf3, 0xf6, 0xdb, 0x1f, 0xcd,
+0xff, 0x14, 0x70, 0xe7, 0x16, 0xe8, 0x3d, 0xf0, 0xe3, 0xbc, 0x5e, 0xb6, 0x3f, 0xcc, 0x81,
+0x24, 0x67, 0xf3, 0x97, 0x3b, 0xfe, 0x3a, 0x96, 0x85, 0xdf, 0xe4, 0x6e, 0x3c, 0x85, 0x05,
+0x0e, 0xa3, 0x2b, 0x07, 0xc8, 0xbf, 0xe5, 0x13, 0x82, 0x62, 0x08, 0x61, 0x69, 0x4b, 0x47,
+0x62, 0x73, 0x44, 0x64, 0x8e, 0xe2, 0x91, 0xa6, 0x9a, 0xb7, 0xe9, 0x04, 0xb6, 0x54, 0x0c,
+0xc5, 0xa9, 0x47, 0xa6, 0xc9, 0x08, 0xfe, 0x4e, 0xa6, 0xcc, 0x8a, 0x5b, 0x90, 0x6f, 0x2b,
+0x3f, 0xb6, 0x0a, 0x96, 0xc0, 0x78, 0x58, 0x3c, 0x76, 0x6d, 0x94, 0x1a, 0xe4, 0x4e, 0xb8,
+0x38, 0xbb, 0xf5, 0xeb, 0x29, 0xd8, 0xb0, 0xf3, 0x15, 0x1e, 0x99, 0x96, 0x3c, 0x5d, 0x63,
+0xd5, 0xb1, 0xad, 0x52, 0xb8, 0x55, 0x70, 0x75, 0x3e, 0x1a, 0xd5, 0xda, 0xf6, 0x7a, 0x48,
+0x7d, 0x44, 0x41, 0xf9, 0x11, 0xce, 0xd7, 0xca, 0xa5, 0x3d, 0x7a, 0x79, 0x7e, 0x7d, 0x25,
+0x1b, 0x77, 0xbc, 0xf7, 0xc7, 0x0f, 0x84, 0x95, 0x10, 0x92, 0x67, 0x15, 0x11, 0x5a, 0x5e,
+0x41, 0x66, 0x0f, 0x38, 0x03, 0xb2, 0xf1, 0x5d, 0xf8, 0xab, 0xc0, 0x02, 0x76, 0x84, 0x28,
+0xf4, 0x9d, 0x56, 0x46, 0x60, 0x20, 0xdb, 0x68, 0xa7, 0xbb, 0xee, 0xac, 0x15, 0x01, 0x2f,
+0x20, 0x09, 0xdb, 0xc0, 0x16, 0xa1, 0x89, 0xf9, 0x94, 0x59, 0x00, 0xc1, 0x76, 0xbf, 0xc1,
+0x4d, 0x5d, 0x2d, 0xa9, 0x85, 0x2c, 0xd6, 0xd3, 0x14, 0xcc, 0x02, 0xc3, 0xc2, 0xfa, 0x6b,
+0xb7, 0xa6, 0xef, 0xdd, 0x12, 0x26, 0xa4, 0x63, 0xe3, 0x62, 0xbd, 0x56, 0x8a, 0x52, 0x2b,
+0xb9, 0xdf, 0x09, 0xbc, 0x0e, 0x97, 0xa9, 0xb0, 0x82, 0x46, 0x08, 0xd5, 0x1a, 0x8e, 0x1b,
+0xa7, 0x90, 0x98, 0xb9, 0xbb, 0x3c, 0x17, 0x9a, 0xf2, 0x82, 0xba, 0x64, 0x0a, 0x7f, 0xca,
+0x5a, 0x8c, 0x7c, 0xd3, 0x79, 0x09, 0x5b, 0x26, 0xbb, 0xbd, 0x25, 0xdf, 0x3d, 0x6f, 0x9a,
+0x8f, 0xee, 0x21, 0x66, 0xb0, 0x8d, 0x84, 0x4c, 0x91, 0x45, 0xd4, 0x77, 0x4f, 0xb3, 0x8c,
+0xbc, 0xa8, 0x99, 0xaa, 0x19, 0x53, 0x7c, 0x02, 0x87, 0xbb, 0x0b, 0x7c, 0x1a, 0x2d, 0xdf,
+0x48, 0x44, 0x06, 0xd6, 0x7d, 0x0c, 0x2d, 0x35, 0x76, 0xae, 0xc4, 0x5f, 0x71, 0x85, 0x97,
+0xc4, 0x3d, 0xef, 0x52, 0xbe, 0x00, 0xe4, 0xcd, 0x49, 0xd1, 0xd1, 0x1c, 0x3c, 0xd0, 0x1c,
+0x42, 0xaf, 0xd4, 0xbd, 0x58, 0x34, 0x07, 0x32, 0xee, 0xb9, 0xb5, 0xea, 0xff, 0xd7, 0x8c,
+0x0d, 0x2e, 0x2f, 0xaf, 0x87, 0xbb, 0xe6, 0x52, 0x71, 0x22, 0xf5, 0x25, 0x17, 0xa1, 0x82,
+0x04, 0xc2, 0x4a, 0xbd, 0x57, 0xc6, 0xab, 0xc8, 0x35, 0x0c, 0x3c, 0xd9, 0xc2, 0x43, 0xdb,
+0x27, 0x92, 0xcf, 0xb8, 0x25, 0x60, 0xfa, 0x21, 0x3b, 0x04, 0x52, 0xc8, 0x96, 0xba, 0x74,
+0xe3, 0x67, 0x3e, 0x8e, 0x8d, 0x61, 0x90, 0x92, 0x59, 0xb6, 0x1a, 0x1c, 0x5e, 0x21, 0xc1,
+0x65, 0xe5, 0xa6, 0x34, 0x05, 0x6f, 0xc5, 0x60, 0xb1, 0x83, 0xc1, 0xd5, 0xd5, 0xed, 0xd9,
+0xc7, 0x11, 0x7b, 0x49, 0x7a, 0xf9, 0xf9, 0x84, 0x47, 0x9b, 0xe2, 0xa5, 0x82, 0xe0, 0xc2,
+0x88, 0xd0, 0xb2, 0x58, 0x88, 0x7f, 0x45, 0x09, 0x67, 0x74, 0x61, 0xbf, 0xe6, 0x40, 0xe2,
+0x9d, 0xc2, 0x47, 0x05, 0x89, 0xed, 0xcb, 0xbb, 0xb7, 0x27, 0xe7, 0xdc, 0x7a, 0xfd, 0xbf,
+0xa8, 0xd0, 0xaa, 0x10, 0x39, 0x3c, 0x20, 0xf0, 0xd3, 0x6e, 0xb1, 0x72, 0xf8, 0xe6, 0x0f,
+0xef, 0x37, 0xe5, 0x09, 0x33, 0x5a, 0x83, 0x43, 0x80, 0x4f, 0x65, 0x2f, 0x7c, 0x8c, 0x6a,
+0xa0, 0x82, 0x0c, 0xd4, 0xd4, 0xfa, 0x81, 0x60, 0x3d, 0xdf, 0x06, 0xf1, 0x5f, 0x08, 0x0d,
+0x6d, 0x43, 0xf2, 0xe3, 0x11, 0x7d, 0x80, 0x32, 0xc5, 0xfb, 0xc5, 0xd9, 0x27, 0xec, 0xc6,
+0x4e, 0x65, 0x27, 0x76, 0x87, 0xa6, 0xee, 0xee, 0xd7, 0x8b, 0xd1, 0xa0, 0x5c, 0xb0, 0x42,
+0x13, 0x0e, 0x95, 0x4a, 0xf2, 0x06, 0xc6, 0x43, 0x33, 0xf4, 0xc7, 0xf8, 0xe7, 0x1f, 0xdd,
+0xe4, 0x46, 0x4a, 0x70, 0x39, 0x6c, 0xd0, 0xed, 0xca, 0xbe, 0x60, 0x3b, 0xd1, 0x7b, 0x57,
+0x48, 0xe5, 0x3a, 0x79, 0xc1, 0x69, 0x33, 0x53, 0x1b, 0x80, 0xb8, 0x91, 0x7d, 0xb4, 0xf6,
+0x17, 0x1a, 0x1d, 0x5a, 0x32, 0xd6, 0xcc, 0x71, 0x29, 0x3f, 0x28, 0xbb, 0xf3, 0x5e, 0x71,
+0xb8, 0x43, 0xaf, 0xf8, 0xb9, 0x64, 0xef, 0xc4, 0xa5, 0x6c, 0x08, 0x53, 0xc7, 0x00, 0x10,
+0x39, 0x4f, 0xdd, 0xe4, 0xb6, 0x19, 0x27, 0xfb, 0xb8, 0xf5, 0x32, 0x73, 0xe5, 0xcb, 0x32
+};
+
+/*
+====================
+COM_BlockSequenceCRCByte
+
+For proxy protecting
+====================
+*/
+byte COM_BlockSequenceCRCByte (byte *base, int length, int sequence)
+{
+ int n;
+ byte *p;
+ int x;
+ byte chkb[60 + 4];
+ unsigned short crc;
+
+
+ if (sequence < 0)
+ Sys_Error("sequence < 0, this shouldn't happen\n");
+
+ p = chktbl + (sequence % (sizeof(chktbl) - 4));
+
+ if (length > 60)
+ length = 60;
+ memcpy (chkb, base, length);
+
+ chkb[length] = p[0];
+ chkb[length+1] = p[1];
+ chkb[length+2] = p[2];
+ chkb[length+3] = p[3];
+
+ length += 4;
+
+ crc = CRC_Block(chkb, length);
+
+ for (x=0, n=0; n<length; n++)
+ x += chkb[n];
+
+ crc = (crc ^ x) & 0xff;
+
+ return crc;
+}
+
+//========================================================
+
+/* 0 to 1 */
+float qfrand(void)
+{
+ return (rand()&32767)* (1.0/32767);
+}
+
+/* -1 to 1 */
+float crand(void)
+{
+ return (rand()&32767)* (2.0/32767) - 1;
+}
+
+void Key_Init (void);
+void SCR_EndLoadingPlaque (void);
+
+/*
+=============
+Com_Error_f
+
+Just throw a fatal error to
+test error shutdown procedures
+=============
+*/
+void Com_Error_f (void)
+{
+ Com_Error (ERR_FATAL, "%s", Cmd_Argv(1));
+}
+
+
+/*
+=================
+Qcommon_Init
+=================
+*/
+void Qcommon_Init (int argc, char **argv)
+{
+ char *s;
+
+ if (setjmp (abortframe) )
+ Sys_Error ("Error during initialization");
+
+ z_chain.next = z_chain.prev = &z_chain;
+
+ // prepare enough of the subsystems to handle
+ // cvar and command buffer management
+ COM_InitArgv (argc, argv);
+
+ Swap_Init ();
+ Cbuf_Init ();
+
+ Cmd_Init ();
+ Cvar_Init ();
+
+ Key_Init ();
+
+ // we need to add the early commands twice, because
+ // a basedir or cddir needs to be set before execing
+ // config files, but we want other parms to override
+ // the settings of the config files
+ Cbuf_AddEarlyCommands (false);
+ Cbuf_Execute ();
+
+ FS_InitFilesystem ();
+
+ Cbuf_AddText ("exec default.cfg\n");
+ Cbuf_AddText ("exec config.cfg\n");
+
+ Cbuf_AddEarlyCommands (true);
+ Cbuf_Execute ();
+
+ //
+ // init commands and vars
+ //
+ Cmd_AddCommand ("z_stats", Z_Stats_f);
+ Cmd_AddCommand ("error", Com_Error_f);
+
+ host_speeds = Cvar_Get ("host_speeds", "0", 0);
+ log_stats = Cvar_Get ("log_stats", "0", 0);
+ developer = Cvar_Get ("developer", "0", 0);
+ timescale = Cvar_Get ("timescale", "1", 0);
+ fixedtime = Cvar_Get ("fixedtime", "0", 0);
+ logfile_active = Cvar_Get ("logfile", "0", 0);
+ showtrace = Cvar_Get ("showtrace", "0", 0);
+#ifdef DEDICATED_ONLY
+ dedicated = Cvar_Get ("dedicated", "1", CVAR_NOSET);
+#else
+ dedicated = Cvar_Get ("dedicated", "0", CVAR_NOSET);
+#endif
+
+ s = va("%4.2f 9front Nov 30 1997 9front", VERSION);
+ Cvar_Get ("version", s, CVAR_SERVERINFO|CVAR_NOSET);
+
+
+ if (dedicated->value)
+ Cmd_AddCommand ("quit", Com_Quit);
+
+ Sys_Init ();
+
+ NET_Init ();
+ Netchan_Init ();
+
+ SV_Init ();
+ CL_Init ();
+
+ // add + commands from command line
+ if (!Cbuf_AddLateCommands ())
+ { // if the user didn't give any commands, run default action
+ if (!dedicated->value)
+ Cbuf_AddText ("d1\n");
+ else
+ Cbuf_AddText ("dedicated_start\n");
+ Cbuf_Execute ();
+ }
+ else
+ { // the user asked for something explicit
+ // so drop the loading plaque
+ SCR_EndLoadingPlaque ();
+ }
+
+ Com_Printf ("====== Quake2 Initialized ======\n\n");
+}
+
+/*
+=================
+Qcommon_Frame
+=================
+*/
+void Qcommon_Frame (int msec)
+{
+ char *s;
+ int time_before = 0, time_between = 0, time_after = 0;
+
+ if (setjmp (abortframe) )
+ return; // an ERR_DROP was thrown
+
+ if ( log_stats->modified )
+ {
+ log_stats->modified = false;
+ if ( log_stats->value )
+ {
+ if ( log_stats_file )
+ {
+ fclose( log_stats_file );
+ log_stats_file = 0;
+ }
+ log_stats_file = fopen( "stats.log", "w" );
+ if ( log_stats_file )
+ fprintf( log_stats_file, "entities,dlights,parts,frame time\n" );
+ }
+ else
+ {
+ if ( log_stats_file )
+ {
+ fclose( log_stats_file );
+ log_stats_file = 0;
+ }
+ }
+ }
+
+ if (fixedtime->value)
+ msec = fixedtime->value;
+ else if (timescale->value)
+ {
+ msec *= timescale->value;
+ if (msec < 1)
+ msec = 1;
+ }
+
+ if (showtrace->value)
+ {
+ extern int c_traces, c_brush_traces;
+ extern int c_pointcontents;
+
+ Com_Printf ("%4i traces %4i points\n", c_traces, c_pointcontents);
+ c_traces = 0;
+ c_brush_traces = 0;
+ c_pointcontents = 0;
+ }
+
+ do
+ {
+ s = Sys_ConsoleInput ();
+ if (s)
+ Cbuf_AddText (va("%s\n",s));
+ } while (s);
+ Cbuf_Execute ();
+
+ if (host_speeds->value)
+ time_before = Sys_Milliseconds ();
+
+ SV_Frame (msec);
+
+ if (host_speeds->value)
+ time_between = Sys_Milliseconds ();
+
+ CL_Frame (msec);
+
+ if (host_speeds->value)
+ time_after = Sys_Milliseconds ();
+
+
+ if (host_speeds->value)
+ {
+ int all, sv, gm, cl, rf;
+
+ all = time_after - time_before;
+ sv = time_between - time_before;
+ cl = time_after - time_between;
+ gm = time_after_game - time_before_game;
+ rf = time_after_ref - time_before_ref;
+ sv -= gm;
+ cl -= rf;
+ Com_Printf ("all:%3i sv:%3i gm:%3i cl:%3i rf:%3i\n",
+ all, sv, gm, cl, rf);
+ }
+}
--- /dev/null
+++ b/console.c
@@ -1,0 +1,661 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+console_t con;
+
+cvar_t *con_notifytime;
+
+
+#define MAXCMDLINE 256
+extern char key_lines[32][MAXCMDLINE];
+extern int edit_line;
+extern int key_linepos;
+
+
+void DrawString (int x, int y, char *s)
+{
+ while (*s)
+ {
+ re.DrawChar (x, y, *s);
+ x+=8;
+ s++;
+ }
+}
+
+void DrawAltString (int x, int y, char *s)
+{
+ while (*s)
+ {
+ re.DrawChar (x, y, *s ^ 0x80);
+ x+=8;
+ s++;
+ }
+}
+
+
+void Key_ClearTyping (void)
+{
+ key_lines[edit_line][1] = 0; // clear any typing
+ key_linepos = 1;
+}
+
+/*
+================
+Con_ToggleConsole_f
+================
+*/
+void Con_ToggleConsole_f (void)
+{
+ SCR_EndLoadingPlaque (); // get rid of loading plaque
+
+ if (cl.attractloop)
+ {
+ Cbuf_AddText ("killserver\n");
+ return;
+ }
+
+ if (cls.state == ca_disconnected)
+ { // start the demo loop again
+ Cbuf_AddText ("d1\n");
+ return;
+ }
+
+ Key_ClearTyping ();
+ Con_ClearNotify ();
+
+ if (cls.key_dest == key_console)
+ {
+ M_ForceMenuOff ();
+ Cvar_Set ("paused", "0");
+ IN_Grabm (1);
+ }
+ else
+ {
+ M_ForceMenuOff ();
+ cls.key_dest = key_console;
+
+ if (Cvar_VariableValue ("maxclients") == 1
+ && Com_ServerState ())
+ Cvar_Set ("paused", "1");
+ IN_Grabm (0);
+ }
+}
+
+/*
+================
+Con_ToggleChat_f
+================
+*/
+void Con_ToggleChat_f (void)
+{
+ Key_ClearTyping ();
+
+ if (cls.key_dest == key_console)
+ {
+ if (cls.state == ca_active)
+ {
+ M_ForceMenuOff ();
+ cls.key_dest = key_game;
+ }
+ }
+ else
+ cls.key_dest = key_console;
+
+ Con_ClearNotify ();
+}
+
+/*
+================
+Con_Clear_f
+================
+*/
+void Con_Clear_f (void)
+{
+ memset (con.text, ' ', CON_TEXTSIZE);
+}
+
+
+/*
+================
+Con_Dump_f
+
+Save the console contents out to a file
+================
+*/
+void Con_Dump_f (void)
+{
+ int l, x;
+ char *line;
+ FILE *f;
+ char buffer[1024];
+ char name[MAX_OSPATH];
+
+ if (Cmd_Argc() != 2)
+ {
+ Com_Printf ("usage: condump <filename>\n");
+ return;
+ }
+
+ Com_sprintf (name, sizeof(name), "%s/%s.txt", FS_Gamedir(), Cmd_Argv(1));
+
+ Com_Printf ("Dumped console text to %s.\n", name);
+ FS_CreatePath (name);
+ f = fopen (name, "w");
+ if (!f)
+ {
+ Com_Printf ("ERROR: couldn't open.\n");
+ return;
+ }
+
+ // skip empty lines
+ for (l = con.current - con.totallines + 1 ; l <= con.current ; l++)
+ {
+ line = con.text + (l%con.totallines)*con.linewidth;
+ for (x=0 ; x<con.linewidth ; x++)
+ if (line[x] != ' ')
+ break;
+ if (x != con.linewidth)
+ break;
+ }
+
+ // write the remaining lines
+ buffer[con.linewidth] = 0;
+ for ( ; l <= con.current ; l++)
+ {
+ line = con.text + (l%con.totallines)*con.linewidth;
+ strncpy (buffer, line, con.linewidth);
+ for (x=con.linewidth-1 ; x>=0 ; x--)
+ {
+ if (buffer[x] == ' ')
+ buffer[x] = 0;
+ else
+ break;
+ }
+ for (x=0; buffer[x]; x++)
+ buffer[x] &= 0x7f;
+
+ fprintf (f, "%s\n", buffer);
+ }
+
+ fclose (f);
+}
+
+
+/*
+================
+Con_ClearNotify
+================
+*/
+void Con_ClearNotify (void)
+{
+ int i;
+
+ for (i=0 ; i<NUM_CON_TIMES ; i++)
+ con.times[i] = 0;
+}
+
+
+/*
+================
+Con_MessageMode_f
+================
+*/
+void Con_MessageMode_f (void)
+{
+ chat_team = false;
+ cls.key_dest = key_message;
+}
+
+/*
+================
+Con_MessageMode2_f
+================
+*/
+void Con_MessageMode2_f (void)
+{
+ chat_team = true;
+ cls.key_dest = key_message;
+}
+
+/*
+================
+Con_CheckResize
+
+If the line width has changed, reformat the buffer.
+================
+*/
+void Con_CheckResize (void)
+{
+ int i, j, width, oldwidth, oldtotallines, numlines, numchars;
+ char tbuf[CON_TEXTSIZE];
+
+ width = (vid.width >> 3) - 2;
+
+ if (width == con.linewidth)
+ return;
+
+ if (width < 1) // video hasn't been initialized yet
+ {
+ width = 38;
+ con.linewidth = width;
+ con.totallines = CON_TEXTSIZE / con.linewidth;
+ memset (con.text, ' ', CON_TEXTSIZE);
+ }
+ else
+ {
+ oldwidth = con.linewidth;
+ con.linewidth = width;
+ oldtotallines = con.totallines;
+ con.totallines = CON_TEXTSIZE / con.linewidth;
+ numlines = oldtotallines;
+
+ if (con.totallines < numlines)
+ numlines = con.totallines;
+
+ numchars = oldwidth;
+
+ if (con.linewidth < numchars)
+ numchars = con.linewidth;
+
+ memcpy (tbuf, con.text, CON_TEXTSIZE);
+ memset (con.text, ' ', CON_TEXTSIZE);
+
+ for (i=0 ; i<numlines ; i++)
+ {
+ for (j=0 ; j<numchars ; j++)
+ {
+ con.text[(con.totallines - 1 - i) * con.linewidth + j] =
+ tbuf[((con.current - i + oldtotallines) %
+ oldtotallines) * oldwidth + j];
+ }
+ }
+
+ Con_ClearNotify ();
+ }
+
+ con.current = con.totallines - 1;
+ con.display = con.current;
+}
+
+
+/*
+================
+Con_Init
+================
+*/
+void Con_Init (void)
+{
+ con.linewidth = -1;
+
+ Con_CheckResize ();
+
+ Com_Printf ("Console initialized.\n");
+
+//
+// register our commands
+//
+ con_notifytime = Cvar_Get ("con_notifytime", "3", 0);
+
+ Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
+ Cmd_AddCommand ("togglechat", Con_ToggleChat_f);
+ Cmd_AddCommand ("messagemode", Con_MessageMode_f);
+ Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
+ Cmd_AddCommand ("clear", Con_Clear_f);
+ Cmd_AddCommand ("condump", Con_Dump_f);
+ con.initialized = true;
+}
+
+
+/*
+===============
+Con_Linefeed
+===============
+*/
+void Con_Linefeed (void)
+{
+ con.x = 0;
+ if (con.display == con.current)
+ con.display++;
+ con.current++;
+ memset (&con.text[(con.current%con.totallines)*con.linewidth]
+ , ' ', con.linewidth);
+}
+
+/*
+================
+Con_Print
+
+Handles cursor positioning, line wrapping, etc
+All console printing must go through this in order to be logged to disk
+If no console is visible, the text will appear at the top of the game window
+================
+*/
+void Con_Print (char *txt)
+{
+ int y;
+ int c, l;
+ static int cr;
+ int mask;
+
+ if (!con.initialized)
+ return;
+
+ if (txt[0] == 1 || txt[0] == 2)
+ {
+ mask = 128; // go to colored text
+ txt++;
+ }
+ else
+ mask = 0;
+
+
+ while ( (c = *txt) )
+ {
+ // count word length
+ for (l=0 ; l< con.linewidth ; l++)
+ if ( txt[l] <= ' ')
+ break;
+
+ // word wrap
+ if (l != con.linewidth && (con.x + l > con.linewidth) )
+ con.x = 0;
+
+ txt++;
+
+ if (cr)
+ {
+ con.current--;
+ cr = false;
+ }
+
+
+ if (!con.x)
+ {
+ Con_Linefeed ();
+ // mark time for transparent overlay
+ if (con.current >= 0)
+ con.times[con.current % NUM_CON_TIMES] = cls.realtime;
+ }
+
+ switch (c)
+ {
+ case '\n':
+ con.x = 0;
+ break;
+
+ case '\r':
+ con.x = 0;
+ cr = 1;
+ break;
+
+ default: // display character and advance
+ y = con.current % con.totallines;
+ con.text[y*con.linewidth+con.x] = c | mask | con.ormask;
+ con.x++;
+ if (con.x >= con.linewidth)
+ con.x = 0;
+ break;
+ }
+
+ }
+}
+
+
+/*
+==============
+Con_CenteredPrint
+==============
+*/
+void Con_CenteredPrint (char *text)
+{
+ int l;
+ char buffer[1024];
+
+ l = strlen(text);
+ l = (con.linewidth-l)/2;
+ if (l < 0)
+ l = 0;
+ memset (buffer, ' ', l);
+ strcpy (buffer+l, text);
+ strcat (buffer, "\n");
+ Con_Print (buffer);
+}
+
+/*
+==============================================================================
+
+DRAWING
+
+==============================================================================
+*/
+
+
+/*
+================
+Con_DrawInput
+
+The input line scrolls horizontally if typing goes beyond the right edge
+================
+*/
+void Con_DrawInput (void)
+{
+ int i;
+ char *text;
+
+ if (cls.key_dest == key_menu)
+ return;
+ if (cls.key_dest != key_console && cls.state == ca_active)
+ return; // don't draw anything (always draw if not active)
+
+ text = key_lines[edit_line];
+
+// add the cursor frame
+ text[key_linepos] = 10+((int)(cls.realtime>>8)&1);
+
+// fill out remainder with spaces
+ for (i=key_linepos+1 ; i< con.linewidth ; i++)
+ text[i] = ' ';
+
+// prestep if horizontally scrolling
+ if (key_linepos >= con.linewidth)
+ text += 1 + key_linepos - con.linewidth;
+
+// draw it
+ for (i=0 ; i<con.linewidth ; i++)
+ re.DrawChar ( (i+1)<<3, con.vislines - 22, text[i]);
+
+// remove cursor
+ key_lines[edit_line][key_linepos] = 0;
+}
+
+
+/*
+================
+Con_DrawNotify
+
+Draws the last few lines of output transparently over the game top
+================
+*/
+void Con_DrawNotify (void)
+{
+ int x, v;
+ char *text;
+ int i;
+ int time;
+ char *s;
+ int skip;
+
+ v = 0;
+ for (i= con.current-NUM_CON_TIMES+1 ; i<=con.current ; i++)
+ {
+ if (i < 0)
+ continue;
+ time = con.times[i % NUM_CON_TIMES];
+ if (time == 0)
+ continue;
+ time = cls.realtime - time;
+ if (time > con_notifytime->value*1000)
+ continue;
+ text = con.text + (i % con.totallines)*con.linewidth;
+
+ for (x = 0 ; x < con.linewidth ; x++)
+ re.DrawChar ( (x+1)<<3, v, text[x]);
+
+ v += 8;
+ }
+
+
+ if (cls.key_dest == key_message)
+ {
+ if (chat_team)
+ {
+ DrawString (8, v, "say_team:");
+ skip = 11;
+ }
+ else
+ {
+ DrawString (8, v, "say:");
+ skip = 5;
+ }
+
+ s = chat_buffer;
+ if (chat_bufferlen > (vid.width>>3)-(skip+1))
+ s += chat_bufferlen - ((vid.width>>3)-(skip+1));
+ x = 0;
+ while(s[x])
+ {
+ re.DrawChar ( (x+skip)<<3, v, s[x]);
+ x++;
+ }
+ re.DrawChar ( (x+skip)<<3, v, 10+((cls.realtime>>8)&1));
+ v += 8;
+ }
+
+ if (v)
+ {
+ SCR_AddDirtyPoint (0,0);
+ SCR_AddDirtyPoint (vid.width-1, v);
+ }
+}
+
+/*
+================
+Con_DrawConsole
+
+Draws the console with the solid background
+================
+*/
+void Con_DrawConsole (float frac)
+{
+ int i, j, x, y, n;
+ int rows;
+ char *text;
+ int row;
+ int lines;
+ char version[64];
+ char dlbar[1024];
+
+ lines = vid.height * frac;
+ if (lines <= 0)
+ return;
+
+ if (lines > vid.height)
+ lines = vid.height;
+
+// draw the background
+ re.DrawStretchPic (0, -vid.height+lines, vid.width, vid.height, "conback");
+ SCR_AddDirtyPoint (0,0);
+ SCR_AddDirtyPoint (vid.width-1,lines-1);
+
+ Com_sprintf (version, sizeof(version), "v%4.2f", VERSION);
+ for (x=0 ; x<5 ; x++)
+ re.DrawChar (vid.width-44+x*8, lines-12, 128 + version[x] );
+
+// draw the text
+ con.vislines = lines;
+
+/*
+ rows = (lines-8)>>3; // rows of text to draw
+
+ y = lines - 24;
+*/
+ rows = (lines-22)>>3; // rows of text to draw
+
+ y = lines - 30;
+
+// draw from the bottom up
+ if (con.display != con.current)
+ {
+ // draw arrows to show the buffer is backscrolled
+ for (x=0 ; x<con.linewidth ; x+=4)
+ re.DrawChar ( (x+1)<<3, y, '^');
+
+ y -= 8;
+ rows--;
+ }
+
+ row = con.display;
+ for (i=0 ; i<rows ; i++, y-=8, row--)
+ {
+ if (row < 0)
+ break;
+ if (con.current - row >= con.totallines)
+ break; // past scrollback wrap point
+
+ text = con.text + (row % con.totallines)*con.linewidth;
+
+ for (x=0 ; x<con.linewidth ; x++)
+ re.DrawChar ( (x+1)<<3, y, text[x]);
+ }
+
+//ZOID
+ // draw the download bar
+ // figure out width
+ if (cls.download) {
+ if ((text = strrchr(cls.downloadname, '/')) != NULL)
+ text++;
+ else
+ text = cls.downloadname;
+
+ x = con.linewidth - ((con.linewidth * 7) / 40);
+ y = x - strlen(text) - 8;
+ i = con.linewidth/3;
+ if (strlen(text) > i) {
+ y = x - i - 11;
+ strncpy(dlbar, text, i);
+ dlbar[i] = 0;
+ strcat(dlbar, "...");
+ } else
+ strcpy(dlbar, text);
+ strcat(dlbar, ": ");
+ i = strlen(dlbar);
+ dlbar[i++] = 0x80;
+ // where's the dot go?
+ if (cls.downloadpercent == 0)
+ n = 0;
+ else
+ n = y * cls.downloadpercent / 100;
+
+ for (j = 0; j < y; j++)
+ if (j == n)
+ dlbar[i++] = 0x83;
+ else
+ dlbar[i++] = 0x81;
+ dlbar[i++] = 0x82;
+ dlbar[i] = 0;
+
+ sprintf(dlbar + strlen(dlbar), " %02d%%", cls.downloadpercent);
+
+ // draw it
+ y = con.vislines-12;
+ for (i = 0; i < strlen(dlbar); i++)
+ re.DrawChar ( (i+1)<<3, y, dlbar[i]);
+ }
+//ZOID
+
+// draw the input prompt, user text, and cursor if desired
+ Con_DrawInput ();
+}
--- /dev/null
+++ b/crc.c
@@ -1,0 +1,75 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+// this is a 16 bit, non-reflected CRC using the polynomial 0x1021
+// and the initial and final xor values shown below... in other words, the
+// CCITT standard CRC used by XMODEM
+
+#define CRC_INIT_VALUE 0xffff
+#define CRC_XOR_VALUE 0x0000
+
+static unsigned short crctable[256] =
+{
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+ 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+ 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+ 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+ 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+ 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+ 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+ 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+ 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+ 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+ 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+ 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+ 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+ 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+ 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+ 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+ 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+ 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+ 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+ 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+ 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+ 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+ 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+void CRC_Init(unsigned short *crcvalue)
+{
+ *crcvalue = CRC_INIT_VALUE;
+}
+
+void CRC_ProcessByte(unsigned short *crcvalue, byte data)
+{
+ *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
+}
+
+unsigned short CRC_Value(unsigned short crcvalue)
+{
+ return crcvalue ^ CRC_XOR_VALUE;
+}
+
+unsigned short CRC_Block (byte *start, int count)
+{
+ unsigned short crc;
+
+ CRC_Init (&crc);
+ while (count--)
+ crc = (crc << 8) ^ crctable[(crc >> 8) ^ *start++];
+
+ return crc;
+}
+
--- a/ctf/g_ai.c
+++ b/ctf/g_ai.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
qboolean FindTarget (edict_t *self);
extern cvar_t *maxclients;
--- a/ctf/g_chase.c
+++ b/ctf/g_chase.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
void UpdateChaseCam(edict_t *ent)
--- a/ctf/g_cmds.c
+++ b/ctf/g_cmds.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
#include "m_player.h"
--- a/ctf/g_combat.c
+++ b/ctf/g_combat.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
/*
============
--- a/ctf/g_ctf.c
+++ b/ctf/g_ctf.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
#include "m_player.h"
typedef enum match_s {
--- a/ctf/g_func.c
+++ b/ctf/g_func.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
/*
=========================================================
--- a/ctf/g_items.c
+++ b/ctf/g_items.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
qboolean Pickup_Weapon (edict_t *ent, edict_t *other);
--- a/ctf/g_main.c
+++ b/ctf/g_main.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
game_locals_t game;
level_locals_t level;
--- a/ctf/g_misc.c
+++ b/ctf/g_misc.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
/*QUAKED func_group (0 0 0) ?
--- a/ctf/g_monster.c
+++ b/ctf/g_monster.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
//
--- a/ctf/g_phys.c
+++ b/ctf/g_phys.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
/*
--- a/ctf/g_save.c
+++ b/ctf/g_save.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
field_t fields[] = {
{"classname", FOFS(classname), F_LSTRING},
--- a/ctf/g_spawn.c
+++ b/ctf/g_spawn.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
typedef struct
{
--- a/ctf/g_svcmds.c
+++ b/ctf/g_svcmds.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
void Svcmd_Test_f (void)
--- a/ctf/g_target.c
+++ b/ctf/g_target.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
/*QUAKED target_temp_entity (1 0 0) (-8 -8 -8) (8 8 8)
Fire an origin based temp entity event to the clients.
--- a/ctf/g_trigger.c
+++ b/ctf/g_trigger.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
void InitTrigger (edict_t *self)
--- a/ctf/g_utils.c
+++ b/ctf/g_utils.c
@@ -1,8 +1,9 @@
+#include <u.h>
+#include <libc.h>
// g_utils.c -- misc utility functions for game module
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
--- a/ctf/g_weapon.c
+++ b/ctf/g_weapon.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
/*
--- a/ctf/m_move.c
+++ b/ctf/m_move.c
@@ -1,8 +1,9 @@
+#include <u.h>
+#include <libc.h>
// m_move.c -- monster movement
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
#define STEPSIZE 18
--- a/ctf/p_client.c
+++ b/ctf/p_client.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
#include "m_player.h"
void ClientUserinfoChanged (edict_t *ent, char *userinfo);
--- a/ctf/p_hud.c
+++ b/ctf/p_hud.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
--- a/ctf/p_menu.c
+++ b/ctf/p_menu.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
// Note that the pmenu entries are duplicated
// this is so that a static set of pmenu entries can be used
--- a/ctf/p_trail.c
+++ b/ctf/p_trail.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
/*
--- a/ctf/p_view.c
+++ b/ctf/p_view.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
#include "m_player.h"
--- a/ctf/p_weapon.c
+++ b/ctf/p_weapon.c
@@ -1,6 +1,7 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
-#include "g_local.h"
#include "m_player.h"
--- a/ctf/q_shared.c
+++ b/ctf/q_shared.c
@@ -1,3 +1,5 @@
+#include <u.h>
+#include <libc.h>
#include "../dat.h"
#include "../fns.h"
@@ -249,7 +251,7 @@
// this is the slow, general version
-int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
+int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, cplane_t *p)
{
int i;
float dist1, dist2;
@@ -287,7 +289,7 @@
Returns 1, 2, or 1 + 2
==================
*/
-int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
+int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, cplane_t *p)
{
float dist1, dist2;
int sides;
--- /dev/null
+++ b/cvar.c
@@ -1,0 +1,387 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/* Dynamic variable tracking
+ *
+ * cvar_t variables are used to hold scalar or string variables that can be
+ * changed or displayed at the console or prog code as well as accessed
+ * directly in C code. The user can access cvars from the console in three ways:
+ * r_draworder prints the current value
+ * r_draworder 0 sets the current value to 0
+ * set r_draworder 0 as above, but creates the cvar if not present
+ * Cvars are restricted from having the same names as commands to keep this
+ * interface from being ambiguous. */
+
+cvar_t *cvar_vars;
+
+/* if set, each time a CVAR_USERINFO var is changed, the client will send it
+ * to the server */
+qboolean userinfo_modified;
+
+
+static qboolean
+Cvar_InfoValidate(char *s)
+{
+ if(strstr(s, "\\"))
+ return false;
+ if(strstr(s, "\""))
+ return false;
+ if(strstr(s, ";"))
+ return false;
+ return true;
+}
+
+static cvar_t *
+Cvar_FindVar(char *name)
+{
+ cvar_t *p;
+
+ for(p = cvar_vars; p != nil; p = p->next)
+ if(!strcmp(name, p->name))
+ return p;
+ return nil;
+}
+
+float
+Cvar_VariableValue(char *name)
+{
+ cvar_t *p;
+
+ if((p = Cvar_FindVar(name)) == nil)
+ return 0;
+ return atof(p->string);
+}
+
+char *
+Cvar_VariableString(char *name)
+{
+ cvar_t *p;
+
+ if((p = Cvar_FindVar(name)) == nil)
+ return "";
+ return p->string;
+}
+
+char *
+Cvar_CompleteVariable(char *partial)
+{
+ cvar_t *p;
+ int len;
+
+ len = strlen(partial);
+ if(!len)
+ return nil;
+
+ /* check exact match */
+ for(p = cvar_vars; p != nil; p = p->next)
+ if(!strcmp(partial, p->name))
+ return p->name;
+ /* check partial match */
+ for(p = cvar_vars; p != nil; p = p->next)
+ if(!strncmp(partial, p->name, len))
+ return p->name;
+ return nil;
+}
+
+/* If the variable already exists, the value will not be set. The flags will be
+ * or'ed in if the variable exists. */
+cvar_t *
+Cvar_Get(char *var_name, char *var_value, int flags)
+{
+ cvar_t *p;
+
+ if(flags & (CVAR_USERINFO|CVAR_SERVERINFO)){
+ if(!Cvar_InfoValidate(var_name)){
+ Com_Printf("invalid info cvar name\n");
+ return nil;
+ }
+ }
+
+ if((p = Cvar_FindVar(var_name)) != nil){
+ p->flags |= flags;
+ return p;
+ }
+
+ if(!var_value)
+ return nil;
+
+ if(flags & (CVAR_USERINFO|CVAR_SERVERINFO)){
+ if(!Cvar_InfoValidate(var_value)){
+ Com_Printf("invalid info cvar value\n");
+ return nil;
+ }
+ }
+
+ p = Z_Malloc(sizeof(*p));
+ p->name = CopyString(var_name);
+ p->string = CopyString(var_value);
+ p->modified = true;
+ p->value = atof(p->string);
+ p->next = cvar_vars;
+ cvar_vars = p;
+ p->flags = flags;
+ return p;
+}
+
+cvar_t *
+Cvar_Set2(char *var_name, char *value, qboolean force)
+{
+ cvar_t *var;
+
+ var = Cvar_FindVar(var_name);
+ if(!var)
+ return Cvar_Get(var_name, value, 0); // create it
+
+ if(var->flags & (CVAR_USERINFO|CVAR_SERVERINFO)){
+ if(!Cvar_InfoValidate(value)){
+ Com_Printf("invalid info cvar value\n");
+ return var;
+ }
+ }
+ if(!force){
+ if(var->flags & CVAR_NOSET){
+ Com_Printf("%s is write protected.\n", var_name);
+ return var;
+ }
+ if(var->flags & CVAR_LATCH){
+ if(var->latched_string){
+ if(!strcmp(value, var->latched_string))
+ return var;
+ Z_Free(var->latched_string);
+ }else if(!strcmp(value, var->string))
+ return var;
+
+ if(Com_ServerState()){
+ Com_Printf("%s will be changed for next game.\n", var_name);
+ var->latched_string = CopyString(value);
+ }else{
+ var->string = CopyString(value);
+ var->value = atof(var->string);
+ if(!strcmp(var->name, "game")){
+ FS_SetGamedir(var->string);
+ FS_ExecAutoexec();
+ }
+ }
+ return var;
+ }
+ }else{
+ if(var->latched_string){
+ Z_Free(var->latched_string);
+ var->latched_string = nil;
+ }
+ }
+
+ if(!strcmp(value, var->string))
+ return var; // not changed
+
+ var->modified = true;
+
+ if(var->flags & CVAR_USERINFO)
+ userinfo_modified = true; // transmit at next oportunity
+
+ Z_Free(var->string); // free the old value string
+ var->string = CopyString(value);
+ var->value = atof(var->string);
+ return var;
+}
+
+/* set the variable even if NOSET or LATCH */
+cvar_t *
+Cvar_ForceSet(char *var_name, char *value)
+{
+ return Cvar_Set2(var_name, value, true);
+}
+
+cvar_t *
+Cvar_Set(char *var_name, char *value)
+{
+ return Cvar_Set2(var_name, value, false);
+}
+
+cvar_t *
+Cvar_FullSet(char *var_name, char *value, int flags)
+{
+ cvar_t *var;
+
+ var = Cvar_FindVar(var_name);
+ if(!var)
+ return Cvar_Get(var_name, value, flags); // create it
+
+ var->modified = true;
+
+ if(var->flags & CVAR_USERINFO)
+ userinfo_modified = true; // transmit at next oportunity
+
+ Z_Free(var->string); // free the old value string
+ var->string = CopyString(value);
+ var->value = atof(var->string);
+ var->flags = flags;
+ return var;
+}
+
+void
+Cvar_SetValue(char *var_name, float value)
+{
+ char val[32];
+
+ if(value == (int)value)
+ Com_sprintf(val, sizeof val, "%d", (int)value);
+ else
+ Com_sprintf(val, sizeof val, "%f", value);
+ Cvar_Set(var_name, val);
+}
+
+/* Any variables with latched values will now be updated */
+void
+Cvar_GetLatchedVars(void)
+{
+ cvar_t *p;
+
+ for(p = cvar_vars; p != nil; p = p->next){
+ if(!p->latched_string)
+ continue;
+ Z_Free(p->string);
+ p->string = p->latched_string;
+ p->latched_string = nil;
+ p->value = atof(p->string);
+ if(!strcmp(p->name, "game")){
+ FS_SetGamedir(p->string);
+ FS_ExecAutoexec();
+ }
+ }
+}
+
+/* called by Cmd_ExecuteString when Cmd_Argv(0) doesn't match a known command.
+ * Returns true if the command was a variable reference that was handled (print
+ * or change). */
+qboolean
+Cvar_Command(void)
+{
+ cvar_t *p;
+
+ /* check variables */
+ if((p = Cvar_FindVar(Cmd_Argv(0))) == nil)
+ return false;
+
+ /* perform a variable print or set */
+ if(Cmd_Argc() == 1){
+ Com_Printf("\"%s\" is \"%s\"\n", p->name, p->string);
+ return true;
+ }
+
+ Cvar_Set(p->name, Cmd_Argv(1));
+ return true;
+}
+
+/* Allows setting and defining of arbitrary cvars from console */
+void
+Cvar_Set_f(void)
+{
+ int c;
+ int flags;
+
+ c = Cmd_Argc();
+ if(c != 3 && c != 4){
+ Com_Printf("usage: set <variable> <value> [u / s]\n");
+ return;
+ }
+ if(c == 4){
+ if(!strcmp(Cmd_Argv(3), "u"))
+ flags = CVAR_USERINFO;
+ else if(!strcmp(Cmd_Argv(3), "s"))
+ flags = CVAR_SERVERINFO;
+ else{
+ Com_Printf("flags can only be 'u' or 's'\n");
+ return;
+ }
+ Cvar_FullSet(Cmd_Argv(1), Cmd_Argv(2), flags);
+ }else
+ Cvar_Set(Cmd_Argv(1), Cmd_Argv(2));
+}
+
+/* Appends lines containing "set variable value" for all variables with the
+ * archive flag set to true. */
+void
+Cvar_WriteVariables(char *path)
+{
+ int fd;
+ cvar_t *p;
+
+ if((fd = open(path, OWRITE)) < 0){
+ fprint(2, "Cvar_WriteVariables:open: %r\n");
+ return;
+ }
+ seek(fd, 0, 2);
+ for(p = cvar_vars; p != nil; p = p->next)
+ if(p->flags & CVAR_ARCHIVE)
+ if(fprint(fd, "set %s \"%s\"\n", p->name, p->string) < 0)
+ sysfatal("Cvar_WriteVariables:fprint: %r");
+ close(fd);
+}
+
+void
+Cvar_List_f(void)
+{
+ cvar_t *p;
+ int i;
+
+ for(p = cvar_vars, i = 0; p != nil; p = p->next, i++){
+ if(p->flags & CVAR_ARCHIVE)
+ Com_Printf("*");
+ else
+ Com_Printf(" ");
+ if(p->flags & CVAR_USERINFO)
+ Com_Printf("U");
+ else
+ Com_Printf(" ");
+ if(p->flags & CVAR_SERVERINFO)
+ Com_Printf("S");
+ else
+ Com_Printf(" ");
+ if(p->flags & CVAR_NOSET)
+ Com_Printf("-");
+ else if(p->flags & CVAR_LATCH)
+ Com_Printf("L");
+ else
+ Com_Printf(" ");
+ Com_Printf(" %s \"%s\"\n", p->name, p->string);
+ }
+ Com_Printf("%d cvars\n", i);
+}
+
+char *
+Cvar_BitInfo(int bit)
+{
+ static char info[MAX_INFO_STRING];
+ cvar_t *p;
+
+ info[0] = 0;
+ for(p = cvar_vars; p != nil; p = p->next)
+ if(p->flags & bit)
+ Info_SetValueForKey(info, p->name, p->string);
+ return info;
+}
+
+/* returns an info string containing all the CVAR_USERINFO cvars */
+char *
+Cvar_Userinfo(void)
+{
+ return Cvar_BitInfo(CVAR_USERINFO);
+}
+
+/* returns an info string containing all the CVAR_SERVERINFO cvars */
+char *
+Cvar_Serverinfo(void)
+{
+ return Cvar_BitInfo(CVAR_SERVERINFO);
+}
+
+void
+Cvar_Init(void)
+{
+ Cmd_AddCommand("set", Cvar_Set_f);
+ Cmd_AddCommand("cvarlist", Cvar_List_f);
+}
--- /dev/null
+++ b/dat.h
@@ -1,0 +1,2931 @@
+//#define PARANOID // speed sapping error checking
+//#define SMALL_FINALVERT
+
+typedef uchar byte;
+typedef float vec_t;
+typedef vec_t vec3_t[3];
+typedef vec_t vec5_t[5];
+typedef int fixed4_t;
+typedef int fixed8_t;
+typedef int fixed16_t;
+typedef uchar pixel_t;
+
+typedef enum qboolean {false, true} qboolean;
+
+typedef struct edict_t edict_t;
+typedef struct cvar_t cvar_t;
+typedef struct cplane_t cplane_t;
+typedef struct cmodel_t cmodel_t;
+typedef struct csurface_t csurface_t;
+typedef struct mapsurface_t mapsurface_t;
+typedef struct trace_t trace_t;
+typedef struct pmove_state_t pmove_state_t;
+typedef struct usercmd_t usercmd_t;
+typedef struct pmove_t pmove_t;
+typedef struct entity_state_t entity_state_t;
+typedef struct player_state_t player_state_t;
+typedef struct sizebuf_t sizebuf_t;
+typedef struct netadr_t netadr_t;
+typedef struct netchan_t netchan_t;
+typedef struct dpackfile_t dpackfile_t;
+typedef struct dpackheader_t dpackheader_t;
+typedef struct pcx_t pcx_t;
+typedef struct dstvert_t dstvert_t;
+typedef struct dtriangle_t dtriangle_t;
+typedef struct dtrivertx_t dtrivertx_t;
+typedef struct daliasframe_t daliasframe_t;
+typedef struct dmdl_t dmdl_t;
+typedef struct dsprframe_t dsprframe_t;
+typedef struct dsprite_t dsprite_t;
+typedef struct miptex_t miptex_t;
+typedef struct lump_t lump_t;
+typedef struct dheader_t dheader_t;
+typedef struct dmodel_t dmodel_t;
+typedef struct dvertex_t dvertex_t;
+typedef struct dplane_t dplane_t;
+typedef struct dnode_t dnode_t;
+typedef struct texinfo_t texinfo_t;
+typedef struct dedge_t dedge_t;
+typedef struct dface_t dface_t;
+typedef struct dleaf_t dleaf_t;
+typedef struct dbrushside_t dbrushside_t;
+typedef struct dbrush_t dbrush_t;
+typedef struct dvis_t dvis_t;
+typedef struct dareaportal_t dareaportal_t;
+typedef struct darea_t darea_t;
+typedef struct vrect_t vrect_t;
+typedef struct viddef_t viddef_t;
+typedef struct image_t image_t;
+typedef struct oldrefdef_t oldrefdef_t;
+typedef struct mvertex_t mvertex_t;
+typedef struct mplane_t mplane_t;
+typedef struct medge_t medge_t;
+typedef struct mtexinfo_t mtexinfo_t;
+typedef struct msurface_t msurface_t;
+typedef struct mnode_t mnode_t;
+typedef struct mleaf_t mleaf_t;
+typedef struct model_t model_t;
+typedef struct emitpoint_t emitpoint_t;
+typedef struct finalvert_t finalvert_t;
+typedef struct affinetridesc_t affinetridesc_t;
+typedef struct drawsurf_t drawsurf_t;
+typedef struct alight_t alight_t;
+typedef struct bedge_t bedge_t;
+typedef struct clipplane_t clipplane_t;
+typedef struct surfcache_t surfcache_t;
+typedef struct espan_t espan_t;
+typedef struct polydesc_t polydesc_t;
+typedef struct surf_t surf_t;
+typedef struct edge_t edge_t;
+typedef struct aliastriangleparms_t aliastriangleparms_t;
+typedef struct swstate_t swstate_t;
+typedef struct entity_t entity_t;
+typedef struct dlight_t dlight_t;
+typedef struct particle_t particle_t;
+typedef struct lightstyle_t lightstyle_t;
+typedef struct refdef_t refdef_t;
+typedef struct refexport_t refexport_t;
+typedef struct refimport_t refimport_t;
+typedef struct portable_samplepair_t portable_samplepair_t;
+typedef struct sfxcache_t sfxcache_t;
+typedef struct sfx_t sfx_t;
+typedef struct playsound_t playsound_t;
+typedef struct dma_t dma_t;
+typedef struct channel_t channel_t;
+typedef struct wavinfo_t wavinfo_t;
+typedef struct console_t console_t;
+typedef struct frame_t frame_t;
+typedef struct centity_t centity_t;
+typedef struct clientinfo_t clientinfo_t;
+typedef struct client_state_t client_state_t;
+typedef struct client_static_t client_static_t;
+typedef struct cdlight_t cdlight_t;
+typedef struct cl_sustain_t cl_sustain_t;
+typedef struct cparticle_t cparticle_t;
+typedef struct kbutton_t kbutton_t;
+typedef struct menuframework_t menuframework_t;
+typedef struct menucommon_t menucommon_t;
+typedef struct menufield_t menufield_t;
+typedef struct menuslider_t menuslider_t;
+typedef struct menulist_t menulist_t;
+typedef struct menuaction_t menuaction_t;
+typedef struct menuseparator_t menuseparator_t;
+typedef struct server_t server_t;
+typedef struct client_frame_t client_frame_t;
+typedef struct client_t client_t;
+typedef struct challenge_t challenge_t;
+typedef struct server_static_t server_static_t;
+
+typedef void (*xcommand_t)(void);
+typedef refexport_t (*GetRefAPI_t)(refimport_t);
+
+enum{
+ /* angle indexes */
+ PITCH = 0,
+ YAW = 1,
+ ROLL = 2,
+
+ MAX_STRING_CHARS = 1024, // char* passed to Cmd_TokenizeString, max strlen
+ MAX_STRING_TOKENS = 80, // max tokens resulting from Cmd_TokenizeString
+ MAX_TOKEN_CHARS = 128, // max length of an individual token
+
+ /* max length of quake game and fs pathname */
+ MAX_QPATH = 64,
+ MAX_OSPATH = 128,
+
+ /* per-level limits */
+ MAX_CLIENTS = 256, // absolute limit
+ MAX_EDICTS = 1024, // must change protocol to increase more
+ MAX_LIGHTSTYLES = 256,
+
+ /* these are sent over the net as bytes so they cannot be blindly increased */
+ MAX_MODELS = 256,
+ MAX_SOUNDS = 256,
+ MAX_IMAGES = 256,
+ MAX_ITEMS = 256,
+
+ MAX_GENERAL = MAX_CLIENTS*2, // general config strings
+
+ /* game print flags */
+ PRINT_LOW = 0, // pickup messages
+ PRINT_MEDIUM = 1, // death messages
+ PRINT_HIGH = 2, // critical messages
+ PRINT_CHAT = 3, // chat messages
+
+ /* key / value info strings */
+ MAX_INFO_KEY = 64,
+ MAX_INFO_VALUE = 64,
+ MAX_INFO_STRING = 512,
+
+ MAX_PARSE_ENTITIES = 1024,
+};
+
+/* destination class for gi.multicast() */
+typedef enum multicast_t{
+ MULTICAST_ALL,
+ MULTICAST_PHS,
+ MULTICAST_PVS,
+ MULTICAST_ALL_R,
+ MULTICAST_PHS_R,
+ MULTICAST_PVS_R
+}multicast_t;
+
+#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
+
+extern vec3_t vec3_origin;
+
+#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
+#define VectorSubtract(a,b,c) (c[0]=a[0]-b[0],c[1]=a[1]-b[1],c[2]=a[2]-b[2])
+#define VectorAdd(a,b,c) (c[0]=a[0]+b[0],c[1]=a[1]+b[1],c[2]=a[2]+b[2])
+#define VectorCopy(a,b) (b[0]=a[0],b[1]=a[1],b[2]=a[2])
+#define VectorClear(a) (a[0]=a[1]=a[2]=0)
+#define VectorNegate(a,b) (b[0]=-a[0],b[1]=-a[1],b[2]=-a[2])
+#define VectorSet(v, x, y, z) (v[0]=(x), v[1]=(y), v[2]=(z))
+#define BOX_ON_PLANE_SIDE(emins, emaxs, p) \
+ (((p)->type < 3)? \
+ ( \
+ ((p)->dist <= (emins)[(p)->type])? \
+ 1 \
+ : \
+ ( \
+ ((p)->dist >= (emaxs)[(p)->type])?\
+ 2 \
+ : \
+ 3 \
+ ) \
+ ) \
+ : \
+ BoxOnPlaneSide( (emins), (emaxs), (p)))
+
+extern int curtime; // current time in ms, from Sys_Milliseconds()
+
+enum{
+ SFF_SUBDIR = 1<<3
+};
+
+enum{
+ CVAR_ARCHIVE = 1<<0, // save to vars.rc
+ CVAR_USERINFO = 1<<1, // add to userinfo on change
+ CVAR_SERVERINFO = 1<<2, // add to serverinfo on change
+ CVAR_NOSET = 1<<3, // only allow setting from commandline
+ CVAR_LATCH= 1<<4 // save changes until server restart
+};
+/* nothing outside the Cvar_*() functions should modify these fields! */
+struct cvar_t{
+ char *name;
+ char *string;
+ char *latched_string; // for CVAR_LATCH vars
+ int flags;
+ qboolean modified; // set each time the cvar is changed
+ float value;
+ cvar_t *next;
+};
+extern cvar_t *cvar_vars;
+extern qboolean userinfo_modified;
+
+enum{
+ /* contents flags are separate bits. a given brush can contribute
+ * multiple content bits. multiple brushes can be in a single leaf
+ * lower bits are stronger, and will eat weaker brushes completely */
+ CONTENTS_SOLID = 1<<0, // an eye is never valid in a solid
+ CONTENTS_WINDOW = 1<<1, // translucent, but not watery
+ CONTENTS_AUX = 1<<2,
+ CONTENTS_LAVA = 1<<3,
+ CONTENTS_SLIME = 1<<4,
+ CONTENTS_WATER = 1<<5,
+ CONTENTS_MIST = 1<<6,
+ LAST_VISIBLE_CONTENTS = 1<<6,
+ /* remaining contents are non-visible, and don't eat brushes */
+ CONTENTS_AREAPORTAL = 1<<15,
+ CONTENTS_PLAYERCLIP = 1<<16,
+ CONTENTS_MONSTERCLIP = 1<<17,
+ /* currents can be added to any other contents, and may be mixed */
+ CONTENTS_CURRENT_0 = 1<<18,
+ CONTENTS_CURRENT_90 = 1<<19,
+ CONTENTS_CURRENT_180 = 1<<20,
+ CONTENTS_CURRENT_270 = 1<<21,
+ CONTENTS_CURRENT_UP = 1<<22,
+ CONTENTS_CURRENT_DOWN = 1<<23,
+ CONTENTS_ORIGIN = 1<<24, // removed before bsping an entity
+ CONTENTS_MONSTER = 1<<25, // should never be on a brush, only in game
+ CONTENTS_DEADMONSTER = 1<<26,
+ CONTENTS_DETAIL = 1<<27, // brushes to be added after vis leafs
+ CONTENTS_TRANSLUCENT = 1<<28, // auto set if any surface has trans
+ CONTENTS_LADDER = 1<<29,
+
+ SURF_LIGHT = 1<<0, // value will hold the light strength
+ SURF_SLICK = 1<<1, // effects game physics
+ SURF_SKY = 1<<2, // don't draw, but add to skybox
+ SURF_WARP = 1<<3, // turbulent water warp
+ SURF_TRANS33 = 1<<4,
+ SURF_TRANS66 = 1<<5,
+ SURF_FLOWING = 1<<6, // scroll towards angle
+ SURF_NODRAW = 1<<7, // don't bother referencing the texture
+
+ /* content masks */
+ MASK_ALL = -1,
+ MASK_SOLID = CONTENTS_SOLID|CONTENTS_WINDOW,
+ MASK_PLAYERSOLID = CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER,
+ MASK_DEADSOLID = CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW,
+ MASK_MONSTERSOLID = CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER,
+ MASK_WATER = CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME,
+ MASK_OPAQUE = CONTENTS_SOLID|CONTENTS_SLIME|CONTENTS_LAVA,
+ MASK_SHOT = CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_WINDOW|CONTENTS_DEADMONSTER,
+ MASK_CURRENT = CONTENTS_CURRENT_0|CONTENTS_CURRENT_90|CONTENTS_CURRENT_180|CONTENTS_CURRENT_270|CONTENTS_CURRENT_UP|CONTENTS_CURRENT_DOWN,
+
+ // FIXME: eliminate AREA_ distinction?
+ /* SV_AreaEdicts() can return a list of either solid or trigger entities */
+ AREA_SOLID = 1<<0,
+ AREA_TRIGGERS = 1<<1
+};
+
+/* !!! if this is changed, it must be changed in asm code too !!! */
+struct cplane_t{
+ vec3_t normal;
+ float dist;
+ uchar type; // for fast side tests
+ uchar signbits; // signx + (signy<<1) + (signz<<1)
+ uchar pad[2];
+};
+struct cmodel_t{
+ vec3_t mins;
+ vec3_t maxs;
+ vec3_t origin; // for sounds or lights
+ int headnode;
+};
+struct csurface_t{
+ char name[16];
+ int flags;
+ int value;
+};
+/* used internally due to name len probs */
+struct mapsurface_t{
+ csurface_t c;
+ char rname[32];
+};
+/* a trace is returned when a box is swept through the world */
+struct trace_t{
+ qboolean allsolid; // if true, plane is not valid
+ qboolean startsolid; // if true, the initial point was in a solid area
+ float fraction; // time completed, 1.0 = didn't hit anything
+ vec3_t endpos; // final position
+ cplane_t plane; // surface normal at impact
+ csurface_t *surface; // surface hit
+ int contents; // contents on other side of surface hit
+ edict_t *ent; // not set by CM_*() functions
+};
+
+/* information necessary for client side movement prediction */
+typedef enum pmtype_t{
+ /* can accelerate and turn */
+ PM_NORMAL,
+ PM_SPECTATOR,
+ /* no acceleration or turning */
+ PM_DEAD,
+ PM_GIB, // different bounding box
+ PM_FREEZE
+}pmtype_t;
+
+enum{
+ PMF_DUCKED = 1<<0,
+ PMF_JUMP_HELD = 1<<1,
+ PMF_ON_GROUND = 1<<2,
+ PMF_TIME_WATERJUMP = 1<<3, // pm_time is waterjump
+ PMF_TIME_LAND = 1<<4, // pm_time is time before rejump
+ PMF_TIME_TELEPORT = 1<<5, // pm_time is non-moving time
+ /* temporarily disables prediction (used for grappling hook) */
+ PMF_NO_PREDICTION = 1<<6,
+};
+/* this structure needs to be communicated bit-accurate from the server to the
+ * client to guarantee that prediction stays in sync, so no floats are used.
+ * if any part of the game code modifies this struct, it will result in a
+ * prediction error of some degree. */
+struct pmove_state_t{
+ pmtype_t pm_type;
+ short origin[3]; // 12.3
+ short velocity[3]; // 12.3
+ uchar pm_flags; // ducked, jump_held, etc
+ uchar pm_time; // each unit = 8 ms
+ short gravity;
+ /* add to command angles to get view direction changed by spawns,
+ * rotating objects and teleporters */
+ short delta_angles[3];
+};
+
+enum{
+ BUTTON_ATTACK = 1<<0,
+ BUTTON_USE = 1<<1,
+ BUTTON_ANY = 1<<7, // any key whatsoever
+
+ MAXTOUCH = 32
+};
+/* sent to the server each client frame */
+struct usercmd_t{
+ uchar msec;
+ uchar buttons;
+ short angles[3];
+ short forwardmove;
+ short sidemove;
+ short upmove;
+ uchar impulse; // remove?
+ uchar lightlevel; // light level the player is standing on
+};
+struct pmove_t{
+ pmove_state_t s; // state (in / out)
+ /* command (in) */
+ usercmd_t cmd;
+ qboolean snapinitial; // if s has been changed outside pmove
+ /* results (out) */
+ int numtouch;
+ edict_t *touchents[MAXTOUCH];
+
+ vec3_t viewangles; // clamped
+ float viewheight;
+ vec3_t mins; // bounding box size
+ vec3_t maxs;
+ edict_t *groundentity;
+ int watertype;
+ int waterlevel;
+ /* callbacks to test the world */
+ trace_t (*trace)(vec3_t, vec3_t, vec3_t, vec3_t);
+ int (*pointcontents)(vec3_t);
+};
+
+enum{
+ /* entity_state_t->effects
+ * Effects are things handled on the client side (lights, particles, frame
+ * animations) that happen constantly on the given entity. An entity that has
+ * effects will be sent to the client even if it has a zero index model. */
+ EF_ROTATE = 1<<0, // rotate (bonus items)
+ EF_GIB = 1<<1, // leave a trail
+ EF_BLASTER = 1<<3, // redlight + trail
+ EF_ROCKET = 1<<4, // redlight + trail
+ EF_GRENADE = 1<<5,
+ EF_HYPERBLASTER = 1<<6,
+ EF_BFG = 1<<7,
+ EF_COLOR_SHELL = 1<<8,
+ EF_POWERSCREEN = 1<<9,
+ EF_ANIM01 = 1<<10, // automatically cycle between frames 0 and 1 at 2 hz
+ EF_ANIM23 = 1<<11, // automatically cycle between frames 2 and 3 at 2 hz
+ EF_ANIM_ALL = 1<<12, // automatically cycle through all frames at 2hz
+ EF_ANIM_ALLFAST = 1<<13, // automatically cycle through all frames at 10hz
+ EF_FLIES = 1<<14,
+ EF_QUAD = 1<<15,
+ EF_PENT = 1<<16,
+ EF_TELEPORTER = 1<<17, // particle fountain
+ EF_FLAG1 = 1<<18,
+ EF_FLAG2 = 1<<19,
+ EF_IONRIPPER = 1<<20,
+ EF_GREENGIB = 1<<21,
+ EF_BLUEHYPERBLASTER = 1<<22,
+ EF_SPINNINGLIGHTS = 1<<23,
+ EF_PLASMA = 1<<24,
+ EF_TRAP = 1<<25,
+ /* ROGUE */
+ EF_TRACKER = 1<<26,
+ EF_DOUBLE = 1<<27,
+ EF_SPHERETRANS = 1<<28,
+ EF_TAGTRAIL = 1<<29,
+ EF_HALF_DAMAGE = 1<<30,
+ EF_TRACKERTRAIL = 1<<31,
+
+ /* entity_state_t->renderfx */
+ RF_MINLIGHT = 1<<0, // allways have some light (viewmodel)
+ RF_VIEWERMODEL = 1<<1, // don't draw through eyes, only mirrors
+ RF_WEAPONMODEL = 1<<2, // only draw through eyes
+ RF_FULLBRIGHT = 1<<3, // allways draw full intensity
+ RF_DEPTHHACK = 1<<4, // for view weapon Z crunching
+ RF_TRANSLUCENT = 1<<5,
+ RF_FRAMELERP = 1<<6,
+ RF_BEAM = 1<<7,
+ RF_CUSTOMSKIN = 1<<8, // skin is an index in image_precache
+ RF_GLOW = 1<<9, // pulse lighting for bonus items
+ RF_SHELL_RED = 1<<10,
+ RF_SHELL_GREEN = 1<<11,
+ RF_SHELL_BLUE = 1<<12,
+ /* ROGUE */
+ RF_IR_VISIBLE = 1<<15,
+ RF_SHELL_DOUBLE = 1<<16,
+ RF_SHELL_HALF_DAM = 1<<17,
+ RF_USE_DISGUISE = 1<<18,
+
+ /* player_state_t->refdef */
+ RDF_UNDERWATER = 1<<0, // warp the screen as apropriate
+ RDF_NOWORLDMODEL = 1<<1, // used for player configuration screen
+ /* ROGUE */
+ RDF_IRGOGGLES = 1<<2,
+ RDF_UVGOGGLES = 1<<3,
+
+ /* muzzle flashes, player effects */
+ MZ_BLASTER = 0,
+ MZ_MACHINEGUN = 1,
+ MZ_SHOTGUN = 2,
+ MZ_CHAINGUN1 = 3,
+ MZ_CHAINGUN2 = 4,
+ MZ_CHAINGUN3 = 5,
+ MZ_RAILGUN = 6,
+ MZ_ROCKET = 7,
+ MZ_GRENADE = 8,
+ MZ_LOGIN = 9,
+ MZ_LOGOUT = 10,
+ MZ_RESPAWN = 11,
+ MZ_BFG = 12,
+ MZ_SSHOTGUN = 13,
+ MZ_HYPERBLASTER = 14,
+ MZ_ITEMRESPAWN = 15,
+ MZ_IONRIPPER = 16,
+ MZ_BLUEHYPERBLASTER = 17,
+ MZ_PHALANX = 18,
+ MZ_SILENCED = 128, // bit flag ORed with one of the above numbers
+ /* ROGUE */
+ MZ_ETF_RIFLE = 30,
+ MZ_UNUSED = 31,
+ MZ_SHOTGUN2 = 32,
+ MZ_HEATBEAM = 33,
+ MZ_BLASTER2 = 34,
+ MZ_TRACKER = 35,
+ MZ_NUKE1 = 36,
+ MZ_NUKE2 = 37,
+ MZ_NUKE4 = 38,
+ MZ_NUKE8 = 39,
+
+ /* monster muzzle flashes */
+ MZ2_TANK_BLASTER_1 = 1,
+ MZ2_TANK_BLASTER_2 = 2,
+ MZ2_TANK_BLASTER_3 = 3,
+ MZ2_TANK_MACHINEGUN_1 = 4,
+ MZ2_TANK_MACHINEGUN_2 = 5,
+ MZ2_TANK_MACHINEGUN_3 = 6,
+ MZ2_TANK_MACHINEGUN_4 = 7,
+ MZ2_TANK_MACHINEGUN_5 = 8,
+ MZ2_TANK_MACHINEGUN_6 = 9,
+ MZ2_TANK_MACHINEGUN_7 = 10,
+ MZ2_TANK_MACHINEGUN_8 = 11,
+ MZ2_TANK_MACHINEGUN_9 = 12,
+ MZ2_TANK_MACHINEGUN_10 = 13,
+ MZ2_TANK_MACHINEGUN_11 = 14,
+ MZ2_TANK_MACHINEGUN_12 = 15,
+ MZ2_TANK_MACHINEGUN_13 = 16,
+ MZ2_TANK_MACHINEGUN_14 = 17,
+ MZ2_TANK_MACHINEGUN_15 = 18,
+ MZ2_TANK_MACHINEGUN_16 = 19,
+ MZ2_TANK_MACHINEGUN_17 = 20,
+ MZ2_TANK_MACHINEGUN_18 = 21,
+ MZ2_TANK_MACHINEGUN_19 = 22,
+ MZ2_TANK_ROCKET_1 = 23,
+ MZ2_TANK_ROCKET_2 = 24,
+ MZ2_TANK_ROCKET_3 = 25,
+ MZ2_INFANTRY_MACHINEGUN_1 = 26,
+ MZ2_INFANTRY_MACHINEGUN_2 = 27,
+ MZ2_INFANTRY_MACHINEGUN_3 = 28,
+ MZ2_INFANTRY_MACHINEGUN_4 = 29,
+ MZ2_INFANTRY_MACHINEGUN_5 = 30,
+ MZ2_INFANTRY_MACHINEGUN_6 = 31,
+ MZ2_INFANTRY_MACHINEGUN_7 = 32,
+ MZ2_INFANTRY_MACHINEGUN_8 = 33,
+ MZ2_INFANTRY_MACHINEGUN_9 = 34,
+ MZ2_INFANTRY_MACHINEGUN_10 = 35,
+ MZ2_INFANTRY_MACHINEGUN_11 = 36,
+ MZ2_INFANTRY_MACHINEGUN_12 = 37,
+ MZ2_INFANTRY_MACHINEGUN_13 = 38,
+ MZ2_SOLDIER_BLASTER_1 = 39,
+ MZ2_SOLDIER_BLASTER_2 = 40,
+ MZ2_SOLDIER_SHOTGUN_1 = 41,
+ MZ2_SOLDIER_SHOTGUN_2 = 42,
+ MZ2_SOLDIER_MACHINEGUN_1 = 43,
+ MZ2_SOLDIER_MACHINEGUN_2 = 44,
+ MZ2_GUNNER_MACHINEGUN_1 = 45,
+ MZ2_GUNNER_MACHINEGUN_2 = 46,
+ MZ2_GUNNER_MACHINEGUN_3 = 47,
+ MZ2_GUNNER_MACHINEGUN_4 = 48,
+ MZ2_GUNNER_MACHINEGUN_5 = 49,
+ MZ2_GUNNER_MACHINEGUN_6 = 50,
+ MZ2_GUNNER_MACHINEGUN_7 = 51,
+ MZ2_GUNNER_MACHINEGUN_8 = 52,
+ MZ2_GUNNER_GRENADE_1 = 53,
+ MZ2_GUNNER_GRENADE_2 = 54,
+ MZ2_GUNNER_GRENADE_3 = 55,
+ MZ2_GUNNER_GRENADE_4 = 56,
+ MZ2_CHICK_ROCKET_1 = 57,
+ MZ2_FLYER_BLASTER_1 = 58,
+ MZ2_FLYER_BLASTER_2 = 59,
+ MZ2_MEDIC_BLASTER_1 = 60,
+ MZ2_GLADIATOR_RAILGUN_1 = 61,
+ MZ2_HOVER_BLASTER_1 = 62,
+ MZ2_ACTOR_MACHINEGUN_1 = 63,
+ MZ2_SUPERTANK_MACHINEGUN_1 = 64,
+ MZ2_SUPERTANK_MACHINEGUN_2 = 65,
+ MZ2_SUPERTANK_MACHINEGUN_3 = 66,
+ MZ2_SUPERTANK_MACHINEGUN_4 = 67,
+ MZ2_SUPERTANK_MACHINEGUN_5 = 68,
+ MZ2_SUPERTANK_MACHINEGUN_6 = 69,
+ MZ2_SUPERTANK_ROCKET_1 = 70,
+ MZ2_SUPERTANK_ROCKET_2 = 71,
+ MZ2_SUPERTANK_ROCKET_3 = 72,
+ MZ2_BOSS2_MACHINEGUN_L1 = 73,
+ MZ2_BOSS2_MACHINEGUN_L2 = 74,
+ MZ2_BOSS2_MACHINEGUN_L3 = 75,
+ MZ2_BOSS2_MACHINEGUN_L4 = 76,
+ MZ2_BOSS2_MACHINEGUN_L5 = 77,
+ MZ2_BOSS2_ROCKET_1 = 78,
+ MZ2_BOSS2_ROCKET_2 = 79,
+ MZ2_BOSS2_ROCKET_3 = 80,
+ MZ2_BOSS2_ROCKET_4 = 81,
+ MZ2_FLOAT_BLASTER_1 = 82,
+ MZ2_SOLDIER_BLASTER_3 = 83,
+ MZ2_SOLDIER_SHOTGUN_3 = 84,
+ MZ2_SOLDIER_MACHINEGUN_3 = 85,
+ MZ2_SOLDIER_BLASTER_4 = 86,
+ MZ2_SOLDIER_SHOTGUN_4 = 87,
+ MZ2_SOLDIER_MACHINEGUN_4 = 88,
+ MZ2_SOLDIER_BLASTER_5 = 89,
+ MZ2_SOLDIER_SHOTGUN_5 = 90,
+ MZ2_SOLDIER_MACHINEGUN_5 = 91,
+ MZ2_SOLDIER_BLASTER_6 = 92,
+ MZ2_SOLDIER_SHOTGUN_6 = 93,
+ MZ2_SOLDIER_MACHINEGUN_6 = 94,
+ MZ2_SOLDIER_BLASTER_7 = 95,
+ MZ2_SOLDIER_SHOTGUN_7 = 96,
+ MZ2_SOLDIER_MACHINEGUN_7 = 97,
+ MZ2_SOLDIER_BLASTER_8 = 98,
+ MZ2_SOLDIER_SHOTGUN_8 = 99,
+ MZ2_SOLDIER_MACHINEGUN_8 = 100,
+ /* --- Xian shit below --- */
+ MZ2_MAKRON_BFG = 101,
+ MZ2_MAKRON_BLASTER_1 = 102,
+ MZ2_MAKRON_BLASTER_2 = 103,
+ MZ2_MAKRON_BLASTER_3 = 104,
+ MZ2_MAKRON_BLASTER_4 = 105,
+ MZ2_MAKRON_BLASTER_5 = 106,
+ MZ2_MAKRON_BLASTER_6 = 107,
+ MZ2_MAKRON_BLASTER_7 = 108,
+ MZ2_MAKRON_BLASTER_8 = 109,
+ MZ2_MAKRON_BLASTER_9 = 110,
+ MZ2_MAKRON_BLASTER_10 = 111,
+ MZ2_MAKRON_BLASTER_11 = 112,
+ MZ2_MAKRON_BLASTER_12 = 113,
+ MZ2_MAKRON_BLASTER_13 = 114,
+ MZ2_MAKRON_BLASTER_14 = 115,
+ MZ2_MAKRON_BLASTER_15 = 116,
+ MZ2_MAKRON_BLASTER_16 = 117,
+ MZ2_MAKRON_BLASTER_17 = 118,
+ MZ2_MAKRON_RAILGUN_1 = 119,
+ MZ2_JORG_MACHINEGUN_L1 = 120,
+ MZ2_JORG_MACHINEGUN_L2 = 121,
+ MZ2_JORG_MACHINEGUN_L3 = 122,
+ MZ2_JORG_MACHINEGUN_L4 = 123,
+ MZ2_JORG_MACHINEGUN_L5 = 124,
+ MZ2_JORG_MACHINEGUN_L6 = 125,
+ MZ2_JORG_MACHINEGUN_R1 = 126,
+ MZ2_JORG_MACHINEGUN_R2 = 127,
+ MZ2_JORG_MACHINEGUN_R3 = 128,
+ MZ2_JORG_MACHINEGUN_R4 = 129,
+ MZ2_JORG_MACHINEGUN_R5 = 130,
+ MZ2_JORG_MACHINEGUN_R6 = 131,
+ MZ2_JORG_BFG_1 = 132,
+ MZ2_BOSS2_MACHINEGUN_R1 = 133,
+ MZ2_BOSS2_MACHINEGUN_R2 = 134,
+ MZ2_BOSS2_MACHINEGUN_R3 = 135,
+ MZ2_BOSS2_MACHINEGUN_R4 = 136,
+ MZ2_BOSS2_MACHINEGUN_R5 = 137,
+ /* ROGUE */
+ MZ2_CARRIER_MACHINEGUN_L1 = 138,
+ MZ2_CARRIER_MACHINEGUN_R1 = 139,
+ MZ2_CARRIER_GRENADE = 140,
+ MZ2_TURRET_MACHINEGUN = 141,
+ MZ2_TURRET_ROCKET = 142,
+ MZ2_TURRET_BLASTER = 143,
+ MZ2_STALKER_BLASTER = 144,
+ MZ2_DAEDALUS_BLASTER = 145,
+ MZ2_MEDIC_BLASTER_2 = 146,
+ MZ2_CARRIER_RAILGUN = 147,
+ MZ2_WIDOW_DISRUPTOR = 148,
+ MZ2_WIDOW_BLASTER = 149,
+ MZ2_WIDOW_RAIL = 150,
+ MZ2_WIDOW_PLASMABEAM = 151, // PMM - not used
+ MZ2_CARRIER_MACHINEGUN_L2 = 152,
+ MZ2_CARRIER_MACHINEGUN_R2 = 153,
+ MZ2_WIDOW_RAIL_LEFT = 154,
+ MZ2_WIDOW_RAIL_RIGHT = 155,
+ MZ2_WIDOW_BLASTER_SWEEP1 = 156,
+ MZ2_WIDOW_BLASTER_SWEEP2 = 157,
+ MZ2_WIDOW_BLASTER_SWEEP3 = 158,
+ MZ2_WIDOW_BLASTER_SWEEP4 = 159,
+ MZ2_WIDOW_BLASTER_SWEEP5 = 160,
+ MZ2_WIDOW_BLASTER_SWEEP6 = 161,
+ MZ2_WIDOW_BLASTER_SWEEP7 = 162,
+ MZ2_WIDOW_BLASTER_SWEEP8 = 163,
+ MZ2_WIDOW_BLASTER_SWEEP9 = 164,
+ MZ2_WIDOW_BLASTER_100 = 165,
+ MZ2_WIDOW_BLASTER_90 = 166,
+ MZ2_WIDOW_BLASTER_80 = 167,
+ MZ2_WIDOW_BLASTER_70 = 168,
+ MZ2_WIDOW_BLASTER_60 = 169,
+ MZ2_WIDOW_BLASTER_50 = 170,
+ MZ2_WIDOW_BLASTER_40 = 171,
+ MZ2_WIDOW_BLASTER_30 = 172,
+ MZ2_WIDOW_BLASTER_20 = 173,
+ MZ2_WIDOW_BLASTER_10 = 174,
+ MZ2_WIDOW_BLASTER_0 = 175,
+ MZ2_WIDOW_BLASTER_10L = 176,
+ MZ2_WIDOW_BLASTER_20L = 177,
+ MZ2_WIDOW_BLASTER_30L = 178,
+ MZ2_WIDOW_BLASTER_40L = 179,
+ MZ2_WIDOW_BLASTER_50L = 180,
+ MZ2_WIDOW_BLASTER_60L = 181,
+ MZ2_WIDOW_BLASTER_70L = 182,
+ MZ2_WIDOW_RUN_1 = 183,
+ MZ2_WIDOW_RUN_2 = 184,
+ MZ2_WIDOW_RUN_3 = 185,
+ MZ2_WIDOW_RUN_4 = 186,
+ MZ2_WIDOW_RUN_5 = 187,
+ MZ2_WIDOW_RUN_6 = 188,
+ MZ2_WIDOW_RUN_7 = 189,
+ MZ2_WIDOW_RUN_8 = 190,
+ MZ2_CARRIER_ROCKET_1 = 191,
+ MZ2_CARRIER_ROCKET_2 = 192,
+ MZ2_CARRIER_ROCKET_3 = 193,
+ MZ2_CARRIER_ROCKET_4 = 194,
+ MZ2_WIDOW2_BEAMER_1 = 195,
+ MZ2_WIDOW2_BEAMER_2 = 196,
+ MZ2_WIDOW2_BEAMER_3 = 197,
+ MZ2_WIDOW2_BEAMER_4 = 198,
+ MZ2_WIDOW2_BEAMER_5 = 199,
+ MZ2_WIDOW2_BEAM_SWEEP_1 = 200,
+ MZ2_WIDOW2_BEAM_SWEEP_2 = 201,
+ MZ2_WIDOW2_BEAM_SWEEP_3 = 202,
+ MZ2_WIDOW2_BEAM_SWEEP_4 = 203,
+ MZ2_WIDOW2_BEAM_SWEEP_5 = 204,
+ MZ2_WIDOW2_BEAM_SWEEP_6 = 205,
+ MZ2_WIDOW2_BEAM_SWEEP_7 = 206,
+ MZ2_WIDOW2_BEAM_SWEEP_8 = 207,
+ MZ2_WIDOW2_BEAM_SWEEP_9 = 208,
+ MZ2_WIDOW2_BEAM_SWEEP_10 = 209,
+ MZ2_WIDOW2_BEAM_SWEEP_11 = 210
+};
+
+extern vec3_t monster_flash_offset[];
+
+/* Temp entity events are for things that happen at a location seperate from
+ * any existing entity. Temporary entity messages are explicitly constructed
+ * and broadcast. */
+typedef enum temp_event_t{
+ TE_GUNSHOT,
+ TE_BLOOD,
+ TE_BLASTER,
+ TE_RAILTRAIL,
+ TE_SHOTGUN,
+ TE_EXPLOSION1,
+ TE_EXPLOSION2,
+ TE_ROCKET_EXPLOSION,
+ TE_GRENADE_EXPLOSION,
+ TE_SPARKS,
+ TE_SPLASH,
+ TE_BUBBLETRAIL,
+ TE_SCREEN_SPARKS,
+ TE_SHIELD_SPARKS,
+ TE_BULLET_SPARKS,
+ TE_LASER_SPARKS,
+ TE_PARASITE_ATTACK,
+ TE_ROCKET_EXPLOSION_WATER,
+ TE_GRENADE_EXPLOSION_WATER,
+ TE_MEDIC_CABLE_ATTACK,
+ TE_BFG_EXPLOSION,
+ TE_BFG_BIGEXPLOSION,
+ TE_BOSSTPORT, // used as '22' in a map, so DON'T RENUMBER!!!
+ TE_BFG_LASER,
+ TE_GRAPPLE_CABLE,
+ TE_WELDING_SPARKS,
+ TE_GREENBLOOD,
+ TE_BLUEHYPERBLASTER,
+ TE_PLASMA_EXPLOSION,
+ TE_TUNNEL_SPARKS,
+ /* ROGUE */
+ TE_BLASTER2,
+ TE_RAILTRAIL2,
+ TE_FLAME,
+ TE_LIGHTNING,
+ TE_DEBUGTRAIL,
+ TE_PLAIN_EXPLOSION,
+ TE_FLASHLIGHT,
+ TE_FORCEWALL,
+ TE_HEATBEAM,
+ TE_MONSTER_HEATBEAM,
+ TE_STEAM,
+ TE_BUBBLETRAIL2,
+ TE_MOREBLOOD,
+ TE_HEATBEAM_SPARKS,
+ TE_HEATBEAM_STEAM,
+ TE_CHAINFIST_SMOKE,
+ TE_ELECTRIC_SPARKS,
+ TE_TRACKER_EXPLOSION,
+ TE_TELEPORT_EFFECT,
+ TE_DBALL_GOAL,
+ TE_WIDOWBEAMOUT,
+ TE_NUKEBLAST,
+ TE_WIDOWSPLASH,
+ TE_EXPLOSION1_BIG,
+ TE_EXPLOSION1_NP,
+ TE_FLECHETTE
+}temp_event_t;
+
+enum{
+ SPLASH_UNKNOWN = 0,
+ SPLASH_SPARKS = 1,
+ SPLASH_BLUE_WATER = 2,
+ SPLASH_BROWN_WATER = 3,
+ SPLASH_SLIME = 4,
+ SPLASH_LAVA = 5,
+ SPLASH_BLOOD = 6,
+
+ /* sound channels
+ * channel 0 never willingly overrides
+ * other channels (1-7) allways override a playing sound on that channel */
+ CHAN_AUTO = 0,
+ CHAN_WEAPON = 1,
+ CHAN_VOICE = 2,
+ CHAN_ITEM = 3,
+ CHAN_BODY = 4,
+ /* modifier flags */
+ CHAN_NO_PHS_ADD = 1<<3, // send to all clients, not just ones in PHS (ATTN 0 will also do this)
+ CHAN_RELIABLE = 1<<4, // send by reliable message, not datagram
+
+ /* sound attenuation values */
+ ATTN_NONE = 0, // full volume the entire level
+ ATTN_NORM = 1,
+ ATTN_IDLE = 2,
+ ATTN_STATIC = 3, // diminish very rapidly with distance
+
+ /* player_state->stats[] */
+ STAT_HEALTH_ICON = 0,
+ STAT_HEALTH = 1,
+ STAT_AMMO_ICON = 2,
+ STAT_AMMO = 3,
+ STAT_ARMOR_ICON = 4,
+ STAT_ARMOR = 5,
+ STAT_SELECTED_ICON = 6,
+ STAT_PICKUP_ICON = 7,
+ STAT_PICKUP_STRING = 8,
+ STAT_TIMER_ICON = 9,
+ STAT_TIMER = 10,
+ STAT_HELPICON = 11,
+ STAT_SELECTED_ITEM = 12,
+ STAT_LAYOUTS = 13,
+ STAT_FRAGS = 14,
+ STAT_FLASHES = 15, // cleared each frame, 1 = health, 2 = armor
+ STAT_CHASE = 16,
+ STAT_SPECTATOR = 17,
+ MAX_STATS = 32,
+
+ /* dmflags->value */
+ DF_NO_HEALTH = 1<<0,
+ DF_NO_ITEMS = 1<<1,
+ DF_WEAPONS_STAY = 1<<2,
+ DF_NO_FALLING = 1<<3,
+ DF_INSTANT_ITEMS = 1<<4,
+ DF_SAME_LEVEL = 1<<5,
+ DF_SKINTEAMS = 1<<6,
+ DF_MODELTEAMS = 1<<7,
+ DF_NO_FRIENDLY_FIRE = 1<<8,
+ DF_SPAWN_FARTHEST = 1<<9,
+ DF_FORCE_RESPAWN = 1<<10,
+ DF_NO_ARMOR = 1<<11,
+ DF_ALLOW_EXIT = 1<<12,
+ DF_INFINITE_AMMO = 1<<13,
+ DF_QUAD_DROP = 1<<14,
+ DF_FIXED_FOV = 1<<15,
+ DF_QUADFIRE_DROP = 1<<16,
+ /* ROGUE */
+ DF_NO_MINES = 1<<17,
+ DF_NO_STACK_DOUBLE = 1<<18,
+ DF_NO_NUKES = 1<<19,
+ DF_NO_SPHERES = 1<<20,
+
+ ROGUE_VERSION_ID = 1278 // probably bs
+};
+
+/* communicated accross the net */
+
+#define ANGLE2SHORT(x) ((int)((x)*65536/360) & 65535)
+#define SHORT2ANGLE(x) ((x)*(360.0/65536))
+
+enum{
+ /* config strings are a general means of communication from the server
+ * to all connected clients. each config string can be at most
+ * MAX_QPATH characters. */
+ CS_NAME = 0,
+ CS_CDTRACK = 1,
+ CS_SKY = 2,
+ CS_SKYAXIS = 3, // %f %f %f format
+ CS_SKYROTATE = 4,
+ CS_STATUSBAR = 5, // display program string
+ CS_AIRACCEL = 29, // air acceleration control
+ CS_MAXCLIENTS = 30,
+ CS_MAPCHECKSUM = 31, // for catching cheater maps
+ CS_MODELS = 32,
+ CS_SOUNDS = CS_MODELS+MAX_MODELS,
+ CS_IMAGES = CS_SOUNDS+MAX_SOUNDS,
+ CS_LIGHTS = CS_IMAGES+MAX_IMAGES,
+ CS_ITEMS = CS_LIGHTS+MAX_LIGHTSTYLES,
+ CS_PLAYERSKINS = CS_ITEMS+MAX_ITEMS,
+ CS_GENERAL = CS_PLAYERSKINS+MAX_CLIENTS,
+ MAX_CONFIGSTRINGS = CS_GENERAL+MAX_GENERAL
+};
+
+/* entity events are for effects that take place relative to an existing
+ * entitiy origin. Very network efficient. All muzzle flashes really should be
+ * converted to events... */
+typedef enum entity_event_t{
+ EV_NONE,
+ EV_ITEM_RESPAWN,
+ EV_FOOTSTEP,
+ EV_FALLSHORT,
+ EV_FALL,
+ EV_FALLFAR,
+ EV_PLAYER_TELEPORT,
+ EV_OTHER_TELEPORT
+}entity_event_t;
+
+/* information conveyed from the server in an update message about entities
+ * that the client will need to render in some way */
+struct entity_state_t{
+ int number; // edict index
+ vec3_t origin;
+ vec3_t angles;
+ vec3_t old_origin; // for lerping
+ int modelindex;
+ int modelindex2; // weapons, CTF flags, etc
+ int modelindex3;
+ int modelindex4;
+ int frame;
+ int skinnum;
+ uint effects; // PGM - we're filling it, so it needs to be unsigned
+ int renderfx;
+ /* for client side prediction; SV_LinkEdict() sets .solid properly:
+ * 8*(bits 0-4) is x/y radius
+ * 8*(bits 5-9) is z down distance
+ * 8(bits10-15) is z up */
+ int solid;
+ int sound; // for looping sounds, to guarantee shutoff
+ /* impulse events: muzzle flashes, footsteps, etc.
+ * events only go out for a single frame, they are automatically
+ * cleared each frame */
+ int event;
+};
+/* the cl_parse_entities must be large enough to hold UPDATE_BACKUP frames of
+ * entities, so that when a delta compressed message arives from the server it
+ * can be un-deltad from the original */
+extern entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES];
+
+/* information needed in addition to pmove_state_t to render a view. There will
+ * only be 10 player_state_t sent each second, but the number of pmove_state_t
+ * changes will be reletive to client frame rates */
+struct player_state_t{
+ pmove_state_t pmove; // for prediction
+ /* these fields do not need to be communicated bit-precise */
+ vec3_t viewangles; // for fixed views
+ vec3_t viewoffset; // add to pmovestate->origin
+ /* set by weapon kicks, pain effects, etc. */
+ vec3_t kick_angles; // add to view direction to get render angles
+ vec3_t gunangles;
+ vec3_t gunoffset;
+ int gunindex;
+ int gunframe;
+ float blend[4]; // rgba full screen effect
+ float fov; // horizontal field of view
+ int rdflags; // refdef flags
+ short stats[MAX_STATS]; // fast status bar updates
+};
+
+enum{
+ VIDREF_GL = 1,
+ VIDREF_SOFT = 2
+};
+extern int vidref_val;
+
+
+#include "game/game.h" // ugh
+extern game_export_t *ge;
+
+
+#define VERSION 3.19
+#define BASEDIRNAME "baseq2"
+
+struct sizebuf_t{
+ qboolean allowoverflow; // if false, do a Com_Error
+ qboolean overflowed; // set to true if the buffer size failed
+ uchar *data;
+ int maxsize;
+ int cursize;
+ int readcount;
+};
+extern sizebuf_t net_message;
+
+#define DEFAULT_SOUND_PACKET_VOLUME 1.0
+#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0
+enum{
+ PROTOCOL_VERSION = 34,
+ PORT_MASTER = 27900,
+ PORT_CLIENT = 27901,
+ PORT_SERVER = 27910,
+ UPDATE_BACKUP = 16, // buffered copies of entity_state_t; must be power of two
+ UPDATE_MASK = UPDATE_BACKUP-1,
+
+ /* server to client: protocol bytes that can be directly added to
+ * messages; the svc_strings[] array in cl_parse.c should mirror this */
+ svc_bad = 0,
+ /* these ops are known to the game dll */
+ svc_muzzleflash,
+ svc_muzzleflash2,
+ svc_temp_entity,
+ svc_layout,
+ svc_inventory,
+ /* the rest are private to the client and server */
+ svc_nop,
+ svc_disconnect,
+ svc_reconnect,
+ svc_sound,
+ svc_print, // [byte] id [string] null terminated string
+ svc_stufftext, // [string] stuffed into client's console buffer, should be \n terminated
+ svc_serverdata, // [long] protocol ...
+ svc_configstring, // [short] [string]
+ svc_spawnbaseline,
+ svc_centerprint, // [string] to put in center of the screen
+ svc_download, // [short] size [size bytes]
+ svc_playerinfo, // variable
+ svc_packetentities, // [...]
+ svc_deltapacketentities, // [...]
+ svc_frame,
+
+ /* client to server */
+ clc_bad = 0,
+ clc_nop,
+ clc_move, // [[usercmd_t]
+ clc_userinfo, // [[userinfo string]
+ clc_stringcmd, // [string] message
+
+ /* player_state_t communication */
+ PS_M_TYPE = 1<<0,
+ PS_M_ORIGIN = 1<<1,
+ PS_M_VELOCITY = 1<<2,
+ PS_M_TIME = 1<<3,
+ PS_M_FLAGS = 1<<4,
+ PS_M_GRAVITY = 1<<5,
+ PS_M_DELTA_ANGLES = 1<<6,
+ PS_VIEWOFFSET = 1<<7,
+ PS_VIEWANGLES = 1<<8,
+ PS_KICKANGLES = 1<<9,
+ PS_BLEND = 1<<10,
+ PS_FOV = 1<<11,
+ PS_WEAPONINDEX = 1<<12,
+ PS_WEAPONFRAME = 1<<13,
+ PS_RDFLAGS = 1<<14,
+
+ /* user_cmd_t communication: ms and light always sent, the others are
+ * optional */
+ CM_ANGLE1 = 1<<0,
+ CM_ANGLE2 = 1<<1,
+ CM_ANGLE3 = 1<<2,
+ CM_FORWARD = 1<<3,
+ CM_SIDE = 1<<4,
+ CM_UP = 1<<5,
+ CM_BUTTONS = 1<<6,
+ CM_IMPULSE = 1<<7,
+
+ /* a sound without an ent or pos will be a local only sound */
+ SND_VOLUME = 1<<0, // a byte
+ SND_ATTENUATION = 1<<1, // a byte
+ SND_POS = 1<<2, // three coordinates
+ SND_ENT = 1<<3, // a short 0-2: channel, 3-12: entity
+ SND_OFFSET = 1<<4, // a byte, msec offset from frame start
+
+ /* entity_state_t communication */
+ /* try to pack the common update flags into the first byte */
+ U_ORIGIN1 = 1<<0,
+ U_ORIGIN2 = 1<<1,
+ U_ANGLE2 = 1<<2,
+ U_ANGLE3 = 1<<3,
+ U_FRAME8 = 1<<4, // frame is a byte
+ U_EVENT = 1<<5,
+ U_REMOVE = 1<<6, // REMOVE this entity, don't add it
+ U_MOREBITS1 = 1<<7, // read one additional byte
+ U_NUMBER16 = 1<<8, // NUMBER8 is implicit if not set
+ U_ORIGIN3 = 1<<9,
+ U_ANGLE1 = 1<<10,
+ U_MODEL = 1<<11,
+ U_RENDERFX8 = 1<<12, // fullbright, etc
+ U_EFFECTS8 = 1<<14, // autorotate, trails, etc
+ U_MOREBITS2 = 1<<15, // read one additional byte
+ U_SKIN8 = 1<<16,
+ U_FRAME16 = 1<<17, // frame is a short
+ U_RENDERFX16 = 1<<18, // 8 + 16 = 32
+ U_EFFECTS16 = 1<<19, // 8 + 16 = 32
+ U_MODEL2 = 1<<20, // weapons, flags, etc
+ U_MODEL3 = 1<<21,
+ U_MODEL4 = 1<<22,
+ U_MOREBITS3 = 1<<23, // read one additional byte
+ U_OLDORIGIN = 1<<24, // FIXME: get rid of this
+ U_SKIN16 = 1<<25,
+ U_SOUND = 1<<26,
+ U_SOLID = 1<<27,
+};
+extern char *svc_strings[256];
+
+typedef enum netsrc_t{
+ NS_CLIENT,
+ NS_SERVER
+}netsrc_t;
+typedef enum netadrtype_t{
+ NA_LOOPBACK,
+ NA_BROADCAST,
+ NA_IP,
+ NA_IPX,
+ NA_BROADCAST_IPX
+}netadrtype_t;
+
+#define OLD_AVG 0.99 // total = oldtotal*OLD_AVG + new*(1-OLD_AVG)
+enum{
+ PORT_ANY = -1,
+ MAX_MSGLEN = 1400, // max length of a message
+ PACKET_HEADER = 10, // two ints and a short
+ MAX_LATENT = 32,
+ MAX_MASTERS = 8 // max recipients for heartbeat packets
+};
+struct netadr_t{
+ netadrtype_t type;
+ uchar ip[4];
+ uchar ipx[10];
+ ushort port;
+};
+extern netadr_t net_from;
+extern netadr_t master_adr[MAX_MASTERS]; // address of the master server
+
+struct netchan_t{
+ qboolean fatal_error;
+ netsrc_t sock;
+ int dropped; // between last packet and previous
+ int last_received; // for timeouts
+ int last_sent; // for retransmits
+ netadr_t remote_address;
+ int qport; // qport value to write when transmitting
+ /* sequencing variables */
+ int incoming_sequence;
+ int incoming_acknowledged;
+ int incoming_reliable_acknowledged; // single bit
+ int incoming_reliable_sequence; // single bit, maintained local
+ int outgoing_sequence;
+ int reliable_sequence; // single bit
+ int last_reliable_sequence; // sequence number of last send
+ /* reliable staging and holding areas */
+ sizebuf_t message; // writing buffer to send to server
+ uchar message_buf[MAX_MSGLEN-16]; // leave space for header
+ /* message is copied to this buffer when it is first transfered */
+ int reliable_length;
+ uchar reliable_buf[MAX_MSGLEN-16]; // unacked reliable message
+};
+extern uchar net_message_buffer[MAX_MSGLEN];
+
+extern float pm_airaccelerate;
+
+extern cvar_t *developer;
+extern cvar_t *dedicated;
+extern cvar_t *host_speeds;
+extern cvar_t *log_stats;
+
+enum{
+ ERR_FATAL = 0, // exit the entire game with a popup window
+ ERR_DROP = 1, // print to console and disconnect from game
+ ERR_QUIT = 2, // not an error, just a normal exit
+ ERR_DISCONNECT = 2, // don't kill server
+ EXEC_NOW = 0, // don't return until completed
+ EXEC_INSERT = 1, // insert at current position, but don't run yet
+ EXEC_APPEND = 2, // add to end of the command buffer
+ PRINT_ALL = 0,
+ PRINT_DEVELOPER = 1, // only print when "developer 1"
+
+ NUMVERTEXNORMALS = 162,
+
+ /* thread groups */
+ THin = 1,
+ THsnd = 2,
+ THnet = 3
+};
+
+extern FILE *log_stats_file;
+/* host_speeds times */
+extern int time_before_game;
+extern int time_after_game;
+extern int time_before_ref;
+extern int time_after_ref;
+
+extern vec3_t bytedirs[NUMVERTEXNORMALS];
+
+extern uint sys_frame_time;
+
+#pragma pack on
+
+/* .pak files are just a linear collapse of a directory tree */
+enum{
+ IDPAKHEADER = ('K'<<24)+('C'<<16)+('A'<<8)+'P',
+ MAX_FILES_IN_PACK = 4096
+};
+struct dpackfile_t{
+ char name[56];
+ int filepos;
+ int filelen;
+};
+struct dpackheader_t{
+ int ident; // == IDPAKHEADER
+ int dirofs;
+ int dirlen;
+};
+
+/* PCX images */
+struct pcx_t{
+ char manufacturer;
+ char version;
+ char encoding;
+ char bits_per_pixel;
+ ushort xmin;
+ ushort ymin;
+ ushort xmax;
+ ushort ymax;
+ ushort hres;
+ ushort vres;
+ uchar palette[48];
+ char reserved;
+ char color_planes;
+ ushort bytes_per_line;
+ ushort palette_type;
+ char filler[58];
+ uchar data; // unbounded
+};
+
+/* .md2 triangle model file format */
+enum{
+ IDALIASHEADER = ('2'<<24)+('P'<<16)+('D'<<8)+'I',
+ ALIAS_VERSION = 8,
+ MAX_TRIANGLES = 4096,
+ MAX_VERTS = 2048,
+ MAX_FRAMES = 512,
+ MAX_MD2SKINS = 32,
+ MAX_SKINNAME = 64
+};
+struct dstvert_t{
+ short s;
+ short t;
+};
+struct dtriangle_t{
+ short index_xyz[3];
+ short index_st[3];
+};
+struct dtrivertx_t{
+ uchar v[3]; // scaled byte to fit in frame mins/maxs
+ uchar lightnormalindex;
+};
+struct daliasframe_t{
+ float scale[3]; // multiply byte verts by this
+ float translate[3]; // then add this
+ char name[16]; // frame name from grabbing
+ dtrivertx_t verts[1]; // variable sized
+};
+
+/* glcmd format
+ * a positive integer starts a tristrip command, followed by that many vertex
+ * structures. a negative integer starts a trifan command, followed by -x
+ * vertexes a zero indicates the end of the command list. a vertex consists of
+ * a floating point s, a floating point t, and an integer vertex index. */
+struct dmdl_t{
+ int ident;
+ int version;
+ int skinwidth;
+ int skinheight;
+ int framesize; // byte size of each frame
+ int num_skins;
+ int num_xyz;
+ int num_st; // greater than num_xyz for seams
+ int num_tris;
+ int num_glcmds; // dwords in strip/fan command lis
+ int num_frames;
+ int ofs_skins; // each skin is a MAX_SKINNAME string
+ int ofs_st; // byte offset from start for stverts
+ int ofs_tris; // offset for dtriangles
+ int ofs_frames; // offset for first frame
+ int ofs_glcmds;
+ int ofs_end; // end of file
+};
+
+/* .sp2 sprite file format */
+enum{
+ IDSPRITEHEADER = ('2'<<24)+('S'<<16)+('D'<<8)+'I',
+ SPRITE_VERSION = 2
+};
+struct dsprframe_t{
+ int width;
+ int height;
+ int origin_x;
+ int origin_y; // raster coordinates inside pic
+ char name[MAX_SKINNAME]; // name of pcx file
+};
+struct dsprite_t{
+ int ident;
+ int version;
+ int numframes;
+ dsprframe_t frames[1]; // variable sized
+};
+
+/* .wal texture file format */
+enum{
+ MIPLEVELS = 4
+};
+struct miptex_t{
+ char name[32];
+ uint width;
+ uint height;
+ uint offsets[MIPLEVELS]; // four mip maps stored
+ char animname[32]; // next frame in animation chain
+ int flags;
+ int contents;
+ int value;
+};
+
+/* .bsp file format */
+enum{
+ IDBSPHEADER = ('P'<<24)+('S'<<16)+('B'<<8)+'I',
+ BSPVERSION = 38,
+
+ /* upper design bounds; leaffaces, leafbrushes, planes, and verts are
+ * still bounded by 16 bit short limits */
+ MAX_MAP_MODELS = 1024,
+ MAX_MAP_BRUSHES = 8192,
+ MAX_MAP_ENTITIES = 2048,
+ MAX_MAP_ENTSTRING = 0x40000,
+ MAX_MAP_TEXINFO = 8192,
+ MAX_MAP_AREAS = 256,
+ MAX_MAP_AREAPORTALS = 1024,
+ MAX_MAP_PLANES = 65536,
+ MAX_MAP_NODES = 65536,
+ MAX_MAP_BRUSHSIDES = 65536,
+ MAX_MAP_LEAFS = 65536,
+ MAX_MAP_VERTS = 65536,
+ MAX_MAP_FACES = 65536,
+ MAX_MAP_LEAFFACES = 65536,
+ MAX_MAP_LEAFBRUSHES = 65536,
+ MAX_MAP_PORTALS = 65536,
+ MAX_MAP_EDGES = 128000,
+ MAX_MAP_SURFEDGES = 256000,
+ MAX_MAP_LIGHTING = 0x200000,
+ MAX_MAP_VISIBILITY = 0x100000,
+
+ /* key / value pair sizes */
+ MAX_KEY = 32,
+ MAX_VALUE = 1024,
+
+ LUMP_ENTITIES = 0,
+ LUMP_PLANES = 1,
+ LUMP_VERTEXES = 2,
+ LUMP_VISIBILITY = 3,
+ LUMP_NODES = 4,
+ LUMP_TEXINFO = 5,
+ LUMP_FACES = 6,
+ LUMP_LIGHTING = 7,
+ LUMP_LEAFS = 8,
+ LUMP_LEAFFACES = 9,
+ LUMP_LEAFBRUSHES = 10,
+ LUMP_EDGES = 11,
+ LUMP_SURFEDGES = 12,
+ LUMP_MODELS = 13,
+ LUMP_BRUSHES = 14,
+ LUMP_BRUSHSIDES = 15,
+ LUMP_POP = 16,
+ LUMP_AREAS = 17,
+ LUMP_AREAPORTALS = 18,
+ HEADER_LUMPS = 19,
+
+ /* 0-2 are axial planes */
+ PLANE_X = 0,
+ PLANE_Y = 1,
+ PLANE_Z = 2,
+ /* 3-5 are non-axial planes snapped to the nearest */
+ PLANE_ANYX = 3,
+ PLANE_ANYY = 4,
+ PLANE_ANYZ = 5
+ /* planes (x&~1) and (x&~1)+1 are always opposites */
+};
+struct lump_t{
+ int fileofs;
+ int filelen;
+};
+struct dheader_t{
+ int ident;
+ int version;
+ lump_t lumps[HEADER_LUMPS];
+};
+
+struct dmodel_t{
+ float mins[3];
+ float maxs[3];
+ float origin[3]; // for sounds or lights
+ int headnode;
+ int firstface;
+ /* submodels just draw faces without walking the bsp tree */
+ int numfaces;
+};
+struct dvertex_t{
+ float point[3];
+};
+struct dplane_t{
+ float normal[3];
+ float dist;
+ int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
+};
+struct dnode_t{
+ int planenum;
+ int children[2]; // negative numbers are -(leafs+1), not nodes
+ short mins[3]; // for frustom culling
+ short maxs[3];
+ ushort firstface;
+ ushort numfaces; // counting both sides
+};
+struct texinfo_t{
+ float vecs[2][4]; // [s/t][xyz offset]
+ int flags; // miptex flags + overrides
+ int value; // light emission, etc
+ char texture[32]; // texture name (textures/*.wal)
+ int nexttexinfo; // for animations, -1 = end of chain
+};
+
+enum{
+ MAXLIGHTMAPS = 4,
+ ANGLE_UP = -1,
+ ANGLE_DOWN = -2
+};
+/* note that edge 0 is never used, because negative edge nums are used for
+ * counterclockwise use of the edge in a face */
+struct dedge_t{
+ ushort v[2]; // vertex numbers
+};
+struct dface_t{
+ ushort planenum;
+ short side;
+ int firstedge; // we must support > 64k edges
+ short numedges;
+ short texinfo;
+ /* lighting info */
+ uchar styles[MAXLIGHTMAPS];
+ int lightofs; // start of [numstyles*surfsize] samples
+};
+struct dleaf_t{
+ int contents; // OR of all brushes (not needed?)
+ short cluster;
+ short area;
+ short mins[3]; // for frustum culling
+ short maxs[3];
+ ushort firstleafface;
+ ushort numleaffaces;
+ ushort firstleafbrush;
+ ushort numleafbrushes;
+};
+struct dbrushside_t{
+ ushort planenum; // facing out of the leaf
+ short texinfo;
+};
+struct dbrush_t{
+ int firstside;
+ int numsides;
+ int contents;
+};
+
+/* the visibility lump consists of a header with a count, then byte offsets for
+ * the PVS and PHS of each cluster, then the raw compressed bit vectors */
+enum{
+ DVIS_PVS = 0,
+ DVIS_PHS = 1
+};
+struct dvis_t{
+ int numclusters;
+ int bitofs[8][2]; // bitofs[numclusters][2]
+};
+/* each area has a list of portals that lead into other areas; when portals are
+ * closed, other areas may not be visible or hearable even if the vis info says
+ * that it should be */
+struct dareaportal_t{
+ int portalnum;
+ int otherarea;
+};
+struct darea_t{
+ int numareaportals;
+ int firstareaportal;
+};
+
+#pragma pack off
+
+struct vrect_t{
+ int x;
+ int y;
+ int width;
+ int height;
+ vrect_t *pnext;
+};
+struct viddef_t{
+ int width;
+ int height;
+ pixel_t *buffer; // invisible buffer
+ pixel_t *colormap; // 256 * VID_GRADES size
+ pixel_t *alphamap; // 256 * 256 translucency map
+ int rowbytes; // may be > width if displayed in a window or <0 for stupid dibs
+};
+extern viddef_t vid;
+
+#define REF_VERSION "SOFT 0.01"
+/* skins are outline flood filled and mip mapped; pics and sprites with alpha
+ * will be outline flood filled pic won't be mip mapped */
+
+extern cvar_t *sw_aliasstats;
+extern cvar_t *sw_clearcolor;
+extern cvar_t *sw_drawflat;
+extern cvar_t *sw_draworder;
+extern cvar_t *sw_maxedges;
+extern cvar_t *sw_maxsurfs;
+extern cvar_t *sw_mipcap;
+extern cvar_t *sw_mipscale;
+extern cvar_t *sw_mode;
+extern cvar_t *sw_reportsurfout;
+extern cvar_t *sw_reportedgeout;
+extern cvar_t *sw_stipplealpha;
+extern cvar_t *sw_surfcacheoverride;
+extern cvar_t *sw_waterwarp;
+extern cvar_t *r_fullbright;
+extern cvar_t *r_lefthand;
+extern cvar_t *r_drawentities;
+extern cvar_t *r_drawworld;
+extern cvar_t *r_dspeeds;
+extern cvar_t *r_lerpmodels;
+extern cvar_t *r_speeds;
+extern cvar_t *r_lightlevel; //FIXME HACK
+
+typedef enum imagetype_t{
+ it_skin,
+ it_sprite,
+ it_wall,
+ it_pic,
+ it_sky
+}imagetype_t;
+struct image_t{
+ char name[MAX_QPATH]; // game path, including extension
+ imagetype_t type;
+ int width;
+ int height;
+ qboolean transparent; // true if any 255 pixels in image
+ int registration_sequence; // 0 = free
+ uchar *pixels[4]; // mip levels
+};
+
+typedef enum rserr_t{
+ rserr_ok,
+ rserr_invalid_fullscreen,
+ rserr_invalid_mode,
+ rserr_unknown
+}rserr_t;
+
+/* !!! if this is changed, it must be changed in asm_draw.h too !!! */
+struct oldrefdef_t{
+ vrect_t vrect; // subwindow in video for refresh
+ // FIXME: not need vrect next field here?
+ vrect_t aliasvrect; // scaled Alias version
+ int vrectright;
+ int vrectbottom; // right & bottom screen coords
+ int aliasvrectright;
+ int aliasvrectbottom; // scaled Alias versions
+ /* rightmost right edge we care about, for use in edge list */
+ float vrectrightedge;
+ float fvrectx;
+ float fvrecty; // for floating-point compares
+ float fvrectx_adj;
+ float fvrecty_adj; // left and top edges, for clamping
+ int vrect_x_adj_shift20; // vrect.x+0.5-epsilon << 20
+ int vrectright_adj_shift20; // vrectright+0.5-epsilon << 20
+ float fvrectright_adj;
+ float fvrectbottom_adj;
+ /* right and bottom edges, for clamping */
+ float fvrectright; // rightmost edge, for Alias clamping
+ float fvrectbottom; // bottommost edge, for Alias clamping
+ /* at Z = 1.0, this many X is visible; 2.0 = 90 degrees */
+ float horizontalFieldOfView;
+ float xOrigin; // should probably always be 0.5
+ float yOrigin; // between be around 0.3 to 0.5
+ vec3_t vieworg;
+ vec3_t viewangles;
+ int ambientlight;
+};
+extern oldrefdef_t r_refdef;
+
+/* d*_t structures are on-disk representations; m*_t structures are in-memory */
+
+enum{
+ SIDE_FRONT = 0,
+ SIDE_BACK = 1,
+ SIDE_ON = 2,
+
+ // FIXME: differentiate from texinfo SURF_ flags
+ SURF_PLANEBACK = 1<<1,
+ SURF_DRAWSKY = 1<<2, // sky brush face
+ SURF_DRAWTURB = 1<<4,
+ SURF_DRAWBACKGROUND = 1<<6,
+ SURF_DRAWSKYBOX = 1<<7, // sky box
+ SURF_FLOW = 1<<8,
+
+ CONTENTS_NODE = -1
+};
+/* !!! if this is changed, it must be changed in asm_draw.h too !!! */
+struct mvertex_t{
+ vec3_t position;
+};
+/* !!! if this is changed, it must be changed in asm_i386.h too !!! */
+struct mplane_t{
+ vec3_t normal;
+ float dist;
+ uchar type; // for texture axis selection and fast side tests
+ uchar signbits; // signx + signy<<1 + signz<<1
+ uchar pad[2];
+};
+/* !!! if this is changed, it must be changed in asm_draw.h too !!! */
+struct medge_t{
+ ushort v[2];
+ uint cachededgeoffset;
+};
+struct mtexinfo_t{
+ float vecs[2][4];
+ float mipadjust;
+ image_t *image;
+ int flags;
+ int numframes;
+ mtexinfo_t *next; // animation chain
+};
+struct msurface_t{
+ int visframe; // should be drawn when node is crossed
+ int dlightframe;
+ int dlightbits;
+ mplane_t *plane;
+ int flags;
+ int firstedge; // look up in model->surfedges[], negative numbers
+ int numedges; // are backwards edges
+ /* surface generation data */
+ surfcache_t *cachespots[MIPLEVELS];
+ short texturemins[2];
+ short extents[2];
+ mtexinfo_t *texinfo;
+ /* lighting info */
+ uchar styles[MAXLIGHTMAPS];
+ uchar *samples; // [numstyles*surfsize]
+ msurface_t *nextalphasurface;
+};
+
+struct mnode_t{
+ /* common with leaf */
+ int contents; // CONTENTS_NODE, to differentiate from leafs
+ int visframe; // node needs to be traversed if current
+ short minmaxs[6]; // for bounding box culling
+ mnode_t *parent;
+ /* node specific */
+ mplane_t *plane;
+ mnode_t *children[2];
+ ushort firstsurface;
+ ushort numsurfaces;
+};
+struct mleaf_t{
+ /* common with node */
+ int contents; // wil be something other than CONTENTS_NODE
+ int visframe; // node needs to be traversed if current
+ short minmaxs[6]; // for bounding box culling
+ mnode_t *parent;
+ /* leaf specific */
+ int cluster;
+ int area;
+ msurface_t **firstmarksurface;
+ int nummarksurfaces;
+ int key; // BSP sequence number for leaf's contents
+};
+
+typedef enum modtype_t{
+ mod_bad,
+ mod_brush,
+ mod_sprite,
+ mod_alias
+}modtype_t;
+struct model_t{
+ char name[MAX_QPATH];
+ int registration_sequence;
+ modtype_t type;
+ int numframes;
+ int flags;
+ /* volume occupied by the model graphics */
+ vec3_t mins;
+ vec3_t maxs;
+ /* solid volume for clipping (sent from server) */
+ qboolean clipbox;
+ vec3_t clipmins;
+ vec3_t clipmaxs;
+ /* brush model */
+ int firstmodelsurface;
+ int nummodelsurfaces;
+ int numsubmodels;
+ dmodel_t *submodels;
+ int numplanes;
+ mplane_t *planes;
+ int numleafs; // number of visible leafs, not counting 0
+ mleaf_t *leafs;
+ int numvertexes;
+ mvertex_t *vertexes;
+ int numedges;
+ medge_t *edges;
+ int numnodes;
+ int firstnode;
+ mnode_t *nodes;
+ int numtexinfo;
+ mtexinfo_t *texinfo;
+ int numsurfaces;
+ msurface_t *surfaces;
+ int numsurfedges;
+ int *surfedges;
+ int nummarksurfaces;
+ msurface_t **marksurfaces;
+ dvis_t *vis;
+ uchar *lightdata;
+ /* for alias models and sprites */
+ image_t *skins[MAX_MD2SKINS];
+ void *extradata;
+ int extradatasize;
+};
+
+extern int registration_sequence;
+
+#define PARTICLE_Z_CLIP 8.0
+#define XCENTERING (1.0 / 2.0)
+#define YCENTERING (1.0 / 2.0)
+#define CLIP_EPSILON 0.001
+#define BACKFACE_EPSILON 0.01
+/* !!! if this is changed, it must be changed in asm_draw.h too !!! */
+#define NEAR_CLIP 0.01
+enum{
+ CACHE_SIZE = 32,
+ VID_CBITS = 6,
+ VID_GRADES = 1<<VID_CBITS,
+ MAXVERTS = 64, // max points in a surface polygon
+ /* max points in an intermediate polygon (while processing) */
+ MAXWORKINGVERTS = MAXVERTS+4,
+ /* !!! if this is changed, it must be changed in d_ifacea.h too !!! */
+ MAXHEIGHT = 4096,
+ MAXWIDTH = 4096,
+ /* distance that's always guaranteed to be farther away than anything
+ * in the scene */
+ INFINITE_DISTANCE = 0x10000,
+ WARP_WIDTH = 320,
+ WARP_HEIGHT = 240,
+ MAX_LBM_HEIGHT = 480,
+
+ /* !!! must be kept the same as in quakeasm.h !!! */
+ TRANSPARENT_COLOR = 0xff,
+ /* !!! if this is changed, it must be changed in d_ifacea.h too !!! */
+ TURB_TEX_SIZE = 64, // base turbulent texture size
+ /* !!! if this is changed, it must be changed in d_ifacea.h too !!! */
+ CYCLE = 128, // turbulent cycle size
+
+ SCANBUFFERPAD = 0x1000,
+ DS_SPAN_LIST_END = -128,
+ NUMSTACKEDGES = 2000,
+ MINEDGES = NUMSTACKEDGES,
+ NUMSTACKSURFACES = 1000,
+ MINSURFACES = NUMSTACKSURFACES,
+ MAXSPANS = 3000,
+
+ /* finalvert_t.flags */
+ ALIAS_LEFT_CLIP = 1<<0,
+ ALIAS_TOP_CLIP = 1<<1,
+ ALIAS_RIGHT_CLIP = 1<<2,
+ ALIAS_BOTTOM_CLIP = 1<<3,
+ ALIAS_Z_CLIP = 1<<4,
+ ALIAS_XY_CLIP_MASK = 0xf,
+
+ SURFCACHE_SIZE_AT_320X240 = 1024*768,
+ /* value returned by R_BmodelCheckBBox() if bbox is trivially rejected */
+ BMODEL_FULLY_CLIPPED = 1<<4,
+ MAXALIASVERTS = 2000, // TODO: tune this
+ ALIAS_Z_CLIP_PLANE = 4,
+ /* turbulence stuff */
+ AMP = 0x80000,
+ AMP2 = 3,
+ SPEED = 20
+};
+struct emitpoint_t{
+ float u;
+ float v;
+ float s;
+ float t;
+ float zi;
+};
+
+/* asm: if you modidify finalvert_t's definition, make sure to change the
+ * associated offsets too! */
+#ifdef SMALL_FINALVERT
+struct finalvert_t{
+ short u;
+ short v;
+ short s;
+ short t;
+ int l;
+ int zi;
+ int flags;
+ float xyz[3]; // eye space
+};
+#else // !SMALL_FINALVERT
+struct finalvert_t{
+ int u;
+ int v;
+ int s;
+ int t;
+ int l;
+ int zi;
+ int flags;
+ float xyz[3]; // eye space
+};
+#endif // SMALL_FINALVERT
+
+struct affinetridesc_t{
+ void *pskin;
+ int pskindesc;
+ int skinwidth;
+ int skinheight;
+ dtriangle_t *ptriangles;
+ finalvert_t *pfinalverts;
+ int numtriangles;
+ int drawtype;
+ int seamfixupX16;
+ qboolean do_vis_thresh;
+ int vis_thresh;
+};
+extern affinetridesc_t r_affinetridesc;
+
+struct drawsurf_t{
+ uchar *surfdat; // destination for generated surface
+ int rowbytes; // destination logical width in bytes
+ msurface_t *surf; // description for surface to generate
+ /* adjust for lightmap levels for dynamic lighting */
+ fixed8_t lightadj[MAXLIGHTMAPS];
+ image_t *image;
+ int surfmip; // mipmapped ratio of surface texels / world pixels
+ int surfwidth; // in mipmapped texels
+ int surfheight; // in mipmapped texels
+};
+extern drawsurf_t r_drawsurf;
+
+struct alight_t{
+ int ambientlight;
+ int shadelight;
+ float *plightvec;
+};
+
+/* clipped bmodel edges */
+struct bedge_t{
+ mvertex_t *v[2];
+ bedge_t *pnext;
+};
+
+/* !!! if this is changed, it must be changed in asm_draw.h too !!! */
+struct clipplane_t{
+ vec3_t normal;
+ float dist;
+ clipplane_t *next;
+ uchar leftedge;
+ uchar rightedge;
+ uchar reserved[2];
+};
+
+struct surfcache_t{
+ surfcache_t *next;
+ surfcache_t **owner; // nil is an empty chunk of memory
+ int lightadj[MAXLIGHTMAPS]; // checked for strobe flush
+ int dlight;
+ int size; // including header
+ uint width;
+ uint height; // DEBUG only needed for debug
+ float mipscale;
+ image_t *image;
+ uchar data[4]; // width*height elements
+};
+extern surfcache_t *sc_rover;
+extern surfcache_t *d_initial_rover;
+
+/* !!! if this is changed, it must be changed in asm_draw.h too !!! */
+struct espan_t{
+ int u;
+ int v;
+ int count;
+ espan_t *pnext;
+};
+
+/* used by the polygon drawer (R_POLY.C) and sprite setup code (R_SPRITE.C) */
+struct polydesc_t{
+ int nump;
+ emitpoint_t *pverts;
+ uchar *pixels; // image
+ int pixel_width; // image width
+ int pixel_height; // image height
+ vec3_t vup;
+ vec3_t vright;
+ vec3_t vpn; // in worldspace, for plane eq
+ float dist;
+ float s_offset;
+ float t_offset;
+ float viewer_position[3];
+ void (*drawspanlet)(void);
+ int stipple_parity;
+};
+
+// FIXME: compress, make a union if that will help
+// insubmodel is only 1, flags is fewer than 32, spanstate could be a byte
+struct surf_t{
+ surf_t *next; // active surface stack in r_edge.c
+ surf_t *prev; // used in r_edge.c for active surf stack
+ espan_t *spans; // pointer to linked list of spans to draw
+ int key; // sorting key (BSP order)
+ int last_u; // set during tracing
+ int spanstate; // 0 = not in span; 1 = in span; -1 in inverted span (end before start)
+ int flags; // currentface flags
+ msurface_t *msurf;
+ entity_t *entity;
+ float nearzi; // nearest 1/z on surface, for mipmapping
+ qboolean insubmodel;
+ float d_ziorigin;
+ float d_zistepu;
+ float d_zistepv;
+ int pad[2]; // to 64 bytes
+};
+
+/* !!! if this is changed, it must be changed in asm_draw.h too !!! */
+struct edge_t{
+ fixed16_t u;
+ fixed16_t u_step;
+ edge_t *prev;
+ edge_t *next;
+ ushort surfs[2];
+ edge_t *nextremove;
+ float nearzi;
+ medge_t *owner;
+};
+
+struct aliastriangleparms_t{
+ finalvert_t *a;
+ finalvert_t *b;
+ finalvert_t *c;
+};
+extern aliastriangleparms_t aliastriangleparms;
+
+struct swstate_t{
+ qboolean fullscreen;
+ int prev_mode; // last valid SW mode
+ uchar gammatable[256];
+ uchar currentpalette[1024];
+
+};
+extern swstate_t sw_state;
+
+extern int d_spanpixcount;
+extern int r_framecount; // sequence # of current frame since quake started
+/* scale-up factor for screen u and v on Alias vertices passed to driver */
+extern float r_aliasuvscale;
+extern qboolean r_dowarp;
+extern vec3_t r_pright;
+extern vec3_t r_pup;
+extern vec3_t r_ppn;
+extern void *acolormap; // FIXME: should go away
+extern int c_surf;
+extern uchar r_warpbuffer[WARP_WIDTH*WARP_HEIGHT];
+extern float scale_for_mip;
+extern qboolean d_roverwrapped;
+
+extern float d_sdivzstepu;
+extern float d_tdivzstepu;
+extern float d_zistepu;
+extern float d_sdivzstepv;
+extern float d_tdivzstepv;
+extern float d_zistepv;
+extern float d_sdivzorigin;
+extern float d_tdivzorigin;
+extern float d_ziorigin;
+extern fixed16_t sadjust;
+extern fixed16_t tadjust;
+extern fixed16_t bbextents;
+extern fixed16_t bbextentt;
+
+extern int d_vrectx;
+extern int d_vrecty;
+extern int d_vrectright_particle;
+extern int d_vrectbottom_particle;
+extern int d_pix_min;
+extern int d_pix_max;
+extern int d_pix_shift;
+
+extern pixel_t *d_viewbuffer;
+extern short *d_pzbuffer;
+extern uint d_zrowbytes;
+extern uint d_zwidth;
+extern short *zspantable[MAXHEIGHT];
+extern int d_scantable[MAXHEIGHT];
+extern int d_minmip;
+extern float d_scalemip[3];
+
+/* surfaces are generated in back to front order by the bsp, so if a surf
+ * pointer is greater than another one, it should be drawn in front.
+ * surfaces[1] is the background, and is used as the active surface stack.
+ * surfaces[0] is a dummy, because index 0 is used to indicate no surface
+ * attached to an edge_t */
+extern int cachewidth;
+extern pixel_t *cacheblock;
+extern int r_screenwidth;
+extern int r_drawnpolycount;
+extern int sintable[1280];
+extern int intsintable[1280];
+extern int blanktable[1280];
+extern vec3_t vup;
+extern vec3_t base_vup;
+extern vec3_t vpn;
+extern vec3_t base_vpn;
+extern vec3_t vright;
+extern vec3_t base_vright;
+extern surf_t *surfaces;
+extern surf_t *surface_p;
+extern surf_t *surf_max;
+
+extern vec3_t sxformaxis[4]; // s axis transformed into viewspace
+extern vec3_t txformaxis[4]; // t axis transformed into viewspac
+extern float xcenter;
+extern float ycenter;
+extern float xscale;
+extern float yscale;
+extern float xscaleinv;
+extern float yscaleinv;
+extern float xscaleshrink;
+extern float yscaleshrink;
+extern int ubasestep;
+extern int errorterm;
+extern int erroradjustup;
+extern int erroradjustdown;
+
+extern clipplane_t view_clipplanes[4];
+extern int *pfrustum_indexes[4];
+
+extern mplane_t screenedge[4];
+extern vec3_t r_origin;
+extern entity_t r_worldentity;
+extern model_t *currentmodel;
+extern entity_t *currententity;
+extern vec3_t modelorg;
+extern vec3_t r_entorigin;
+extern float verticalFieldOfView;
+extern float xOrigin;
+extern float yOrigin;
+extern int r_visframecount;
+extern msurface_t *r_alpha_surfaces;
+
+extern qboolean insubmodel;
+
+extern int c_faceclip;
+extern int r_polycount;
+extern int r_wholepolycount;
+extern int ubasestep;
+extern int errorterm;
+extern int erroradjustup;
+extern int erroradjustdown;
+extern fixed16_t sadjust;
+extern fixed16_t tadjust;
+extern fixed16_t bbextents;
+extern fixed16_t bbextentt;
+extern mvertex_t *r_ptverts;
+extern mvertex_t *r_ptvertsmax;
+extern float entity_rotation[3][3];
+extern int r_currentkey;
+extern int r_currentbkey;
+extern int r_amodels_drawn;
+extern edge_t *auxedges;
+extern int r_numallocatededges;
+extern edge_t *r_edges;
+extern edge_t *edge_p;
+extern edge_t *edge_max;
+extern edge_t *newedges[MAXHEIGHT];
+extern edge_t *removeedges[MAXHEIGHT];
+extern edge_t edge_head; // FIXME: make stack vars when debugging done
+extern edge_t edge_tail;
+extern edge_t edge_aftertail;
+extern int r_aliasblendcolor;
+extern float aliasxscale;
+extern float aliasyscale;
+extern float aliasxcenter;
+extern float aliasycenter;
+extern int r_outofsurfaces;
+extern int r_outofedges;
+extern mvertex_t *r_pcurrentvertbase;
+extern int r_maxvalidedgeoffset;
+
+extern float r_time1;
+extern float da_time1;
+extern float da_time2;
+extern float dp_time1;
+extern float dp_time2;
+extern float db_time1;
+extern float db_time2;
+extern float rw_time1;
+extern float rw_time2;
+extern float se_time1;
+extern float se_time2;
+extern float de_time1;
+extern float de_time2;
+extern float dv_time1;
+extern float dv_time2;
+extern int r_frustum_indexes[4*6];
+extern int r_maxsurfsseen;
+extern int r_maxedgesseen;
+extern int r_cnumsurfs;
+extern qboolean r_surfsonstack;
+extern mleaf_t *r_viewleaf;
+extern int r_viewcluster;
+extern int r_oldviewcluster;
+extern int r_clipflags;
+extern int r_dlightframecount;
+extern qboolean r_fov_greater_than_90;
+extern image_t *r_notexture_mip;
+extern model_t *r_worldmodel;
+
+extern refdef_t r_newrefdef;
+extern surfcache_t *sc_rover;
+extern surfcache_t *sc_base;
+extern void *colormap;
+
+extern unsigned d_8to24table[256]; // base
+extern mtexinfo_t *sky_texinfo[6];
+
+extern cvar_t *vid_fullscreen;
+extern cvar_t *vid_gamma;
+extern cvar_t *scr_viewsize;
+extern cvar_t *crosshair;
+
+#define POWERSUIT_SCALE 4.0F
+enum{
+ API_VERSION = 3,
+ MAX_DLIGHTS = 32,
+ MAX_ENTITIES = 128,
+ MAX_PARTICLES = 4096,
+
+ SHELL_RED_COLOR = 0xf2,
+ SHELL_GREEN_COLOR = 0xd0,
+ SHELL_BLUE_COLOR = 0xf3,
+ SHELL_RG_COLOR = 0xdc,
+ SHELL_RB_COLOR = 0x68,
+ SHELL_BG_COLOR = 0x78,
+ SHELL_WHITE_COLOR = 0xd7,
+ /* ROGUE */
+ SHELL_DOUBLE_COLOR = 0xdf,
+ SHELL_HALF_DAM_COLOR = 0x90,
+ SHELL_CYAN_COLOR = 0x72,
+
+ ENTITY_FLAGS = 68
+};
+
+struct entity_t{
+ model_t *model; // opaque type outside refresh
+ float angles[3];
+
+ /* most recent data */
+ float origin[3]; // also used as RF_BEAM's "from"
+ int frame; // also used as RF_BEAM's diameter
+ /* previous data for lerping */
+ float oldorigin[3]; // also used as RF_BEAM's "to"
+ int oldframe;
+
+ float backlerp; // 0.0 = current, 1.0 = old
+ int skinnum; // also used as RF_BEAM's palette index
+ int lightstyle; // for flashing entities
+ float alpha; // ignore if RF_TRANSLUCENT isn't set
+ image_t *skin; // nil for inline skin
+ int flags;
+};
+struct dlight_t{
+ vec3_t origin;
+ vec3_t color;
+ float intensity;
+};
+struct particle_t{
+ vec3_t origin;
+ int color;
+ float alpha;
+};
+struct lightstyle_t{
+ float rgb[3]; // 0.0 - 2.0
+ float white; // highest of rgb
+};
+
+struct refdef_t{
+ int x; // in virtual screen coordinates
+ int y;
+ int width;
+ int height;
+ float fov_x;
+ float fov_y;
+ float vieworg[3];
+ float viewangles[3];
+ float blend[4]; // rgba 0-1 full screen blend
+ float time; // time is uesed to auto animate
+ int rdflags; // RDF_UNDERWATER, etc
+ uchar *areabits; // if not nil, only areas with set bits will be drawn
+
+ lightstyle_t *lightstyles; // [MAX_LIGHTSTYLES]
+ int num_entities;
+ entity_t *entities;
+ int num_dlights;
+ dlight_t *dlights;
+ int num_particles;
+ particle_t *particles;
+};
+
+struct refexport_t{
+ int api_version;
+ /* All data that will be used in a level should be registered before
+ * rendering any frames to prevent disk hits, but they can still be
+ * registered at a later time if necessary.
+ * EndRegistration will free any remaining data that wasn't registered.
+ * Any model_s or skin_s pointers from before the BeginRegistration are
+ * no longer valid after EndRegistration.
+ * Skins and images need to be differentiated, because skins are flood
+ * filled to eliminate mip map edge errors, and pics have an implicit
+ * "pics/" prepended to the name. (a pic name that starts with a slash
+ * will not use the "pics/" prefix or the ".pcx" postfix) */
+ qboolean (*Init)(void *, void *);
+ void (*Shutdown)(void);
+ void (*BeginRegistration)(char *);
+ model_t* (*RegisterModel)(char *);
+ image_t* (*RegisterSkin)(char *);
+ image_t* (*RegisterPic)(char *);
+ void (*SetSky)(char *, float, vec3_t);
+ void (*EndRegistration)(void);
+ void (*RenderFrame)(refdef_t *);
+ void (*DrawGetPicSize)(int *, int *, char *);
+ void (*DrawPic)(int, int, char *);
+ void (*DrawStretchPic)(int, int, int, int, char *);
+ void (*DrawChar)(int, int, int);
+ void (*DrawTileClear)(int, int, int, int, char *);
+ void (*DrawFill)(int, int, int, int, int);
+ void (*DrawFadeScreen)(void);
+ void (*DrawStretchRaw)(int, int, int, int, int, int, uchar *);
+ void (*CinematicSetPalette)(uchar *);
+ void (*BeginFrame)(float);
+ void (*EndFrame)(void);
+ void (*AppActivate)(qboolean);
+};
+extern refexport_t re;
+
+struct refimport_t{
+ void (*Sys_Error)(int, char *, ...);
+ void (*Cmd_AddCommand)(char *, void(*)(void));
+ void (*Cmd_RemoveCommand)(char *);
+ int (*Cmd_Argc)(void);
+ char* (*Cmd_Argv)(int);
+ void (*Cmd_ExecuteText)(int, char *);
+ void (*Con_Printf)(int, char *, ...);
+ /* files will be memory mapped read only; the returned buffer may be
+ * part of a larger pak file, or a discrete file from anywhere in the
+ * quake search path
+ * a -1 return means the file does not exist
+ * nil can be passed for buf to just determine existance */
+ int (*FS_LoadFile)(char *, void **);
+ void (*FS_FreeFile)(void *);
+ char* (*FS_Gamedir)(void);
+ cvar_t* (*Cvar_Get)(char *, char *, int);
+ cvar_t* (*Cvar_Set)(char *, char *);
+ void (*Cvar_SetValue)(char *, float);
+ qboolean (*Vid_GetModeInfo)(int *, int *, int);
+ void (*Vid_MenuInit)(void);
+ void (*Vid_NewWindow)(int, int);
+};
+extern refimport_t ri;
+
+extern float scr_con_current;
+extern float scr_conlines; // lines of console to display
+extern int sb_lines;
+extern vrect_t scr_vrect; // position of render window
+extern char crosshair_pic[MAX_QPATH];
+extern int crosshair_width;
+extern int crosshair_height;
+
+extern cvar_t *s_volume;
+extern cvar_t *s_loadas8bit;
+extern cvar_t *s_khz;
+extern cvar_t *s_show;
+extern cvar_t *s_mixahead;
+extern cvar_t *s_testsound;
+extern cvar_t *s_primary;
+
+enum{
+ MAX_CHANNELS = 32,
+ MAX_RAW_SAMPLES = 8192
+};
+
+/* !!! if this is changed, the asm code must change !!! */
+struct portable_samplepair_t{
+ int left;
+ int right;
+};
+extern portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
+
+struct sfxcache_t{
+ int length;
+ int loopstart;
+ int speed; // not needed, because converted on load?
+ int width;
+ int stereo;
+ uchar data[1]; // variable sized
+};
+
+struct sfx_t{
+ char name[MAX_QPATH];
+ int registration_sequence;
+ sfxcache_t *cache;
+ char *truename;
+};
+
+/* a playsound_t will be generated by each call to S_StartSound, when the mixer
+ * reaches playsound->begin, the playsound will be assigned to a channel */
+struct playsound_t{
+ playsound_t *prev;
+ playsound_t *next;
+ sfx_t *sfx;
+ float volume;
+ float attenuation;
+ int entnum;
+ int entchannel;
+ qboolean fixed_origin; // use origin field instead of entnum's origin
+ vec3_t origin;
+ uint begin; // begin on this sample
+};
+extern playsound_t s_pendingplays;
+
+struct dma_t{
+ int channels;
+ int samples; // mono samples in buffer
+ int submission_chunk; // don't mix less than this #
+ int samplepos; // in mono samples
+ int samplebits;
+ int speed;
+ uchar *buffer;
+};
+extern dma_t dma;
+
+/* !!! if this is changed, the asm code must change !!! */
+struct channel_t{
+ sfx_t *sfx; // sfx number
+ int leftvol; // 0-255 volume
+ int rightvol; // 0-255 volume
+ int end; // end time in global paintsamples
+ int pos; // sample position in sfx
+ int looping; // where to loop, -1 = no looping OBSOLETE?
+ int entnum; // to allow overriding a specific sound
+ int entchannel;
+ vec3_t origin; // only use if fixed_origin is set
+ vec_t dist_mult; // distance multiplier (attenuation/clipK)
+ int master_vol; // 0-255 master volume
+ qboolean fixed_origin; // use origin instead of fetching entnum's origin
+ qboolean autosound; // from an entity->sound, cleared each frame
+};
+extern channel_t channels[MAX_CHANNELS];
+
+struct wavinfo_t{
+ int rate;
+ int width;
+ int channels;
+ int loopstart;
+ int samples;
+ int dataofs; // chunk starts this many bytes from file start
+};
+
+extern int paintedtime;
+extern int s_rawend;
+extern vec3_t listener_origin;
+extern vec3_t listener_forward;
+extern vec3_t listener_right;
+extern vec3_t listener_up;
+
+extern cvar_t *in_joystick;
+extern cvar_t *lookspring;
+extern cvar_t *lookstrafe;
+extern cvar_t *sensitivity;
+extern cvar_t *freelook;
+extern cvar_t *m_pitch;
+
+/* key numbers passed to Key_Event() */
+enum{
+ K_TAB = 9,
+ K_ENTER = 13,
+ K_ESCAPE = 27,
+ K_SPACE = 32,
+ /* normal keys should be passed as lowercased ascii */
+ K_BACKSPACE = 127,
+ K_UPARROW = 128,
+ K_DOWNARROW = 129,
+ K_LEFTARROW = 130,
+ K_RIGHTARROW = 131,
+ K_ALT = 132,
+ K_CTRL = 133,
+ K_SHIFT = 134,
+ K_F1 = 135,
+ K_F2 = 136,
+ K_F3 = 137,
+ K_F4 = 138,
+ K_F5 = 139,
+ K_F6 = 140,
+ K_F7 = 141,
+ K_F8 = 142,
+ K_F9 = 143,
+ K_F10 = 144,
+ K_F11 = 145,
+ K_F12 = 146,
+ K_INS = 147,
+ K_DEL = 148,
+ K_PGDN = 149,
+ K_PGUP = 150,
+ K_HOME = 151,
+ K_END = 152,
+ K_KP_HOME = 160,
+ K_KP_UPARROW = 161,
+ K_KP_PGUP = 162,
+ K_KP_LEFTARROW = 163,
+ K_KP_5 = 164,
+ K_KP_RIGHTARROW = 165,
+ K_KP_END = 166,
+ K_KP_DOWNARROW = 167,
+ K_KP_PGDN = 168,
+ K_KP_ENTER = 169,
+ K_KP_INS = 170,
+ K_KP_DEL = 171,
+ K_KP_SLASH = 172,
+ K_KP_MINUS = 173,
+ K_KP_PLUS = 174,
+ /* mouse buttons generate virtual keys */
+ K_MOUSE1 = 200,
+ K_MOUSE3 = 201,
+ K_MOUSE2 = 202,
+ K_MWHEELUP = 203,
+ K_MWHEELDOWN = 204,
+ /* joystick buttons */
+ K_JOY1 = 205,
+ K_JOY2 = 206,
+ K_JOY3 = 207,
+ K_JOY4 = 208,
+ /* aux keys are for multi-buttoned joysticks to generate so they can
+ * use the normal binding process */
+ K_AUX1 = 209,
+ K_AUX2 = 210,
+ K_AUX3 = 211,
+ K_AUX4 = 212,
+ K_AUX5 = 213,
+ K_AUX6 = 214,
+ K_AUX7 = 215,
+ K_AUX8 = 216,
+ K_AUX9 = 217,
+ K_AUX10 = 218,
+ K_AUX11 = 219,
+ K_AUX12 = 220,
+ K_AUX13 = 221,
+ K_AUX14 = 222,
+ K_AUX15 = 223,
+ K_AUX16 = 224,
+ K_AUX17 = 225,
+ K_AUX18 = 226,
+ K_AUX19 = 227,
+ K_AUX20 = 228,
+ K_AUX21 = 229,
+ K_AUX22 = 230,
+ K_AUX23 = 231,
+ K_AUX24 = 232,
+ K_AUX25 = 233,
+ K_AUX26 = 234,
+ K_AUX27 = 235,
+ K_AUX28 = 236,
+ K_AUX29 = 237,
+ K_AUX30 = 238,
+ K_AUX31 = 239,
+ K_AUX32 = 240,
+ K_PAUSE = 255
+};
+extern char *keybindings[256];
+extern int key_repeats[256];
+extern int anykeydown;
+extern char chat_buffer[];
+extern int chat_bufferlen;
+extern qboolean chat_team;
+
+enum{
+ NUM_CON_TIMES = 4,
+ CON_TEXTSIZE = 32768
+};
+struct console_t{
+ qboolean initialized;
+ char text[CON_TEXTSIZE];
+ int current; // line where next message will be printed
+ int x; // offset in current line for next print
+ int display; // bottom of console displays this line
+ int ormask; // high bit mask for colored characters
+ int linewidth; // characters across screen
+ int totallines; // total lines in console scrollback
+ float cursorspeed;
+ int vislines;
+ /* cls.realtime time the line was generated for transparent notify lines */
+ float times[NUM_CON_TIMES];
+};
+extern console_t con;
+
+extern cvar_t *cl_stereo_separation;
+extern cvar_t *cl_stereo;
+extern cvar_t *cl_gun;
+extern cvar_t *cl_add_blend;
+extern cvar_t *cl_add_lights;
+extern cvar_t *cl_add_particles;
+extern cvar_t *cl_add_entities;
+extern cvar_t *cl_predict;
+extern cvar_t *cl_footsteps;
+extern cvar_t *cl_noskins;
+extern cvar_t *cl_autoskins;
+extern cvar_t *cl_upspeed;
+extern cvar_t *cl_forwardspeed;
+extern cvar_t *cl_sidespeed;
+extern cvar_t *cl_yawspeed;
+extern cvar_t *cl_pitchspeed;
+extern cvar_t *cl_run;
+extern cvar_t *cl_anglespeedkey;
+extern cvar_t *cl_shownet;
+extern cvar_t *cl_showmiss;
+extern cvar_t *cl_showclamp;
+extern cvar_t *cl_lightlevel; // FIXME HACK
+extern cvar_t *cl_paused;
+extern cvar_t *cl_timedemo;
+extern cvar_t *cl_vwep;
+
+struct frame_t{
+ qboolean valid; // cleared if delta parsing was invalid
+ int serverframe;
+ int servertime; // server time the message is valid for (in msec)
+ int deltaframe;
+ uchar areabits[MAX_MAP_AREAS/8]; // portalarea visibility bits
+ player_state_t playerstate;
+ int num_entities;
+ int parse_entities; // non-masked index into cl_parse_entities array
+};
+
+struct centity_t{
+ entity_state_t baseline; // delta from this if not from a previous frame
+ entity_state_t current;
+ entity_state_t prev; // will always be valid, but can be just a copy of current
+ int serverframe; // if not current, this ent isn't in the frame
+ int trailcount; // for diminishing grenade trails
+ vec3_t lerp_origin; // for trails (variable hz)
+ int fly_stoptime;
+};
+extern centity_t cl_entities[MAX_EDICTS];
+
+enum{
+ MAX_CLIENTWEAPONMODELS = 20
+};
+struct clientinfo_t{
+ char name[MAX_QPATH];
+ char cinfo[MAX_QPATH];
+ image_t *skin;
+ image_t *icon;
+ char iconname[MAX_QPATH];
+ model_t *model;
+ model_t *weaponmodel[MAX_CLIENTWEAPONMODELS];
+};
+extern char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
+extern int num_cl_weaponmodels;
+
+enum{
+ CMD_BACKUP = 64 // allow a lot of command backups for very fast systems
+};
+/* client_state_t is wiped completely at every server map change */
+struct client_state_t{
+ int timeoutcount;
+ int timedemo_frames;
+ int timedemo_start;
+ qboolean refresh_prepped; // false if on new level or new ref dll
+ qboolean sound_prepped; // ambient sounds can start
+ qboolean force_refdef; // vid has changed, so we can't use a paused refdef
+ int parse_entities; // index (not anded off) into cl_parse_entities[]
+ usercmd_t cmd;
+ usercmd_t cmds[CMD_BACKUP]; // each mesage will send several old cmds
+ int cmd_time[CMD_BACKUP]; // time sent, for calculating pings
+ short predicted_origins[CMD_BACKUP][3]; // for debug comparing against server
+ float predicted_step; // for stair up smoothing
+ uint predicted_step_time;
+ vec3_t predicted_origin; // generated by CL_PredictMovement
+ vec3_t predicted_angles;
+ vec3_t prediction_error;
+ frame_t frame; // received from server
+ int surpressCount; // number of messages rate supressed
+ frame_t frames[UPDATE_BACKUP];
+
+ /* the client maintains its own idea of view angles, which are sent to
+ * the server each frame. it is cleared to 0 upon entering each level.
+ * the server sends a delta each frame which is added to the locally
+ * tracked view angles to account for standing on rotating objects, and
+ * teleport direction changes. */
+ vec3_t viewangles;
+ /* time that the client is rendering at. always <= cls.realtime */
+ int time; // this is the time value that the client
+ float lerpfrac; // between oldframe and frame
+ refdef_t refdef;
+ vec3_t v_forward;
+ vec3_t v_right;
+ vec3_t v_up; // set when refdef.angles is set
+
+ /* transient data from server */
+ char layout[1024]; // general 2D overlay
+ int inventory[MAX_ITEMS];
+
+ // FIXME: move this cinematic stuff into the cin_t structure
+ /* non-gameserver infornamtion */
+ FILE *cinematic_file;
+ int cinematictime; // cls.realtime for first cinematic frame
+ int cinematicframe;
+ char cinematicpalette[768];
+ qboolean cinematicpalette_active;
+
+ /* server state information */
+ qboolean attractloop; // running the attract loop, any key will menu
+ int servercount; // server identification for prespawns
+ char gamedir[MAX_QPATH];
+ int playernum;
+ char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH];
+
+ /* locally derived information from server state */
+ model_t *model_draw[MAX_MODELS];
+ cmodel_t *model_clip[MAX_MODELS];
+ sfx_t *sound_precache[MAX_SOUNDS];
+ image_t *image_precache[MAX_IMAGES];
+ clientinfo_t clientinfo[MAX_CLIENTS];
+ clientinfo_t baseclientinfo;
+};
+extern client_state_t cl;
+
+typedef enum connstate_t{
+ ca_uninitialized,
+ ca_disconnected, // not talking to a server
+ ca_connecting, // sending request packets to the server
+ ca_connected, // netchan_t established, waiting for svc_serverdata
+ ca_active // game views should be displayed
+}connstate_t;
+typedef enum dltype_t{
+ dl_none,
+ dl_model,
+ dl_sound,
+ dl_skin,
+ dl_single
+}dltype_t;
+typedef enum keydest_t{
+ key_game,
+ key_console,
+ key_message,
+ key_menu
+}keydest_t;
+/* the client_static_t structure is persistant through an arbitrary number of
+ * server connections */
+struct client_static_t{
+ connstate_t state;
+ keydest_t key_dest;
+ int framecount;
+ int realtime; // always increasing, no clamping, etc
+ float frametime; // seconds since last frame
+
+ /* screen rendering information */
+ /* showing loading plaque between levels; if time gets >30 sec ahead,
+ * break it */
+ float disable_screen;
+ /* on receiving a frame and cl.servercount > cls.disable_servercount,
+ * clear disable_screen */
+ int disable_servercount;
+
+ /* connection information */
+ char servername[MAX_OSPATH]; // name of server from original connect
+ float connect_time; // for connection retransmits
+ /* ushort allowing servers to work around address translating routers */
+ int quakePort;
+ netchan_t netchan;
+ int serverProtocol; // in case we are doing some kind of version hack
+ int challenge; // from the server to use for connecting
+
+ FILE *download; // file transfer from server
+ char downloadtempname[MAX_OSPATH];
+ char downloadname[MAX_OSPATH];
+ int downloadnumber;
+ dltype_t downloadtype;
+ int downloadpercent;
+
+ /* demo recording info must be here, so it isn't cleared on level change */
+ qboolean demorecording;
+ qboolean demowaiting; // don't record until a non-delta message is received
+ FILE *demofile;
+};
+extern client_static_t cls;
+
+struct cdlight_t{
+ int key; // so entities can reuse same entry
+ vec3_t color;
+ vec3_t origin;
+ float radius;
+ float die; // stop lighting after this time
+ float decay; // drop this each second
+ float minlight; // don't add when contributing less
+};
+extern cdlight_t cl_dlights[MAX_DLIGHTS];
+
+enum{
+ MAX_SUSTAINS = 32
+};
+struct cl_sustain_t{
+ int id;
+ int type;
+ int endtime;
+ int nextthink;
+ int thinkinterval;
+ vec3_t org;
+ vec3_t dir;
+ int color;
+ int count;
+ int magnitude;
+ void (*think)(cl_sustain_t *);
+};
+
+#define INSTANT_PARTICLE -10000.0
+enum{
+ PARTICLE_GRAVITY = 40,
+ BLASTER_PARTICLE_COLOR = 0xe0
+};
+struct cparticle_t{
+ cparticle_t *next;
+ float time;
+ vec3_t org;
+ vec3_t vel;
+ vec3_t accel;
+ float color;
+ float colorvel;
+ float alpha;
+ float alphavel;
+};
+
+struct kbutton_t{
+ int down[2]; // key nums holding it down
+ uint downtime; // msec timestamp
+ uint msec; // msec down this frame
+ int state;
+};
+extern kbutton_t in_mlook;
+extern kbutton_t in_klook;
+extern kbutton_t in_strafe;
+extern kbutton_t in_speed;
+
+extern int gun_frame;
+extern model_t *gun_model;
+
+enum{
+ MAXMENUITEMS = 64,
+ MTYPE_SLIDER = 0,
+ MTYPE_LIST = 1,
+ MTYPE_ACTION = 2,
+ MTYPE_SPINCONTROL = 3,
+ MTYPE_SEPARATOR = 4,
+ MTYPE_FIELD = 5,
+ QMF_LEFT_JUSTIFY = 1<<0,
+ QMF_GRAYED = 1<<1,
+ QMF_NUMBERSONLY = 1<<2,
+};
+struct menuframework_t{
+ int x;
+ int y;
+ int cursor;
+ int nitems;
+ int nslots;
+ void *items[64];
+ char *statusbar;
+ void (*cursordraw)(menuframework_t *);
+};
+struct menucommon_t{
+ int type;
+ char *name;
+ int x;
+ int y;
+ menuframework_t *parent;
+ int cursor_offset;
+ int localdata[4];
+ uint flags;
+ char *statusbar;
+ void (*callback)(void *);
+ void (*statusbarfunc)(void *);
+ void (*ownerdraw)(void *);
+ void (*cursordraw)(void *);
+};
+struct menufield_t{
+ menucommon_t generic;
+ char buffer[80];
+ int cursor;
+ int length;
+ int visible_length;
+ int visible_offset;
+};
+struct menuslider_t{
+ menucommon_t generic;
+ float minvalue;
+ float maxvalue;
+ float curvalue;
+ float range;
+};
+struct menulist_t{
+ menucommon_t generic;
+ int curvalue;
+ char **itemnames;
+};
+struct menuaction_t{
+ menucommon_t generic;
+};
+struct menuseparator_t{
+ menucommon_t generic;
+};
+
+extern cvar_t *sv_paused;
+extern cvar_t *maxclients;
+/* don't reload level state when reentering */
+extern cvar_t *sv_noreload;
+/* don't reload level state when reentering development tool */
+extern cvar_t *sv_airaccelerate;
+extern cvar_t *sv_enforcetime;
+
+typedef enum redirect_t{
+ RD_NONE,
+ RD_CLIENT,
+ RD_PACKET
+}redirect_t;
+
+typedef enum server_state_t{
+ ss_dead, // no map loaded
+ ss_loading, // spawning level edicts
+ ss_game, // actively running
+ ss_cinematic,
+ ss_demo,
+ ss_pic
+}server_state_t;
+/* some qc commands are only valid before the server has finished initializing
+ * (precache commands, static sounds / objects, etc) */
+struct server_t{
+ server_state_t state; // precache commands are only valid during load
+ qboolean attractloop; // running cinematics and demos for the local system only
+ qboolean loadgame; // client begins should reuse existing entity
+ uint time; // always sv.framenum * 100 msec
+ int framenum;
+ char name[MAX_QPATH]; // map name, or cinematic name
+ cmodel_t *models[MAX_MODELS];
+ char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH];
+ entity_state_t baselines[MAX_EDICTS];
+ /* the multicast buffer is used to send a message to a set of clients
+ * it is only used to marshall data until SV_Multicast is called */
+ sizebuf_t multicast;
+ uchar multicast_buf[MAX_MSGLEN];
+ /* demo server information */
+ FILE *demofile;
+ qboolean timedemo; // don't time sync
+};
+extern server_t sv; // local server
+
+#define EDICT_NUM(n) ((edict_t *)((uchar *)ge->edicts + ge->edict_size*(n)))
+#define NUM_FOR_EDICT(e) ( ((uchar *)(e)-(uchar *)ge->edicts ) / ge->edict_size)
+
+struct client_frame_t{
+ int areabytes;
+ uchar areabits[MAX_MAP_AREAS/8]; // portalarea visibility bits
+ player_state_t ps;
+ int num_entities;
+ int first_entity; // into the circular sv_packet_entities[]
+ int senttime; // for ping calculations
+};
+
+typedef enum clstate_t{
+ cs_free, // can be reused for a new connection
+ cs_zombie, // client disconnected, don't reuse connection for a couple secs
+ cs_connected, // has been assigned to a client_t, but not in game yet
+ cs_spawned // client is fully in game
+}clstate_t;
+
+enum{
+ LATENCY_COUNTS = 16,
+ RATE_MESSAGES = 10
+};
+struct client_t{
+ clstate_t state;
+ char userinfo[MAX_INFO_STRING]; // name, etc
+ int lastframe; // for delta compression
+ usercmd_t lastcmd; // for filling in big drops
+ /* every seconds this is reset, if user commands exhaust it, assume
+ * time cheating */
+ int commandMsec;
+ int frame_latency[LATENCY_COUNTS];
+ int ping;
+ int message_size[RATE_MESSAGES]; // used to rate drop packets
+ int rate;
+ int surpressCount; // number of messages rate supressed
+ edict_t *edict; // EDICT_NUM(clientnum+1)
+ char name[32]; // extracted from userinfo, high bits masked
+ int messagelevel; // for filtering printed messages
+ /* the datagram is written to by sound calls, prints, temp ents, etc.
+ * it can be harmlessly overflowed. */
+ sizebuf_t datagram;
+ uchar datagram_buf[MAX_MSGLEN];
+ client_frame_t frames[UPDATE_BACKUP]; // updates can be delta'd from here
+ uchar *download; // file being downloaded
+ int downloadsize; // total bytes (can't use EOF because of paks)
+ int downloadcount; // bytes sent
+ int lastmessage; // sv.framenum when packet was last received
+ int lastconnect;
+ int challenge; // challenge of this user, randomly generated
+ netchan_t netchan;
+};
+extern client_t *sv_client;
+
+/* a client can leave the server in one of four ways: dropping properly by
+ * quiting or disconnecting; timing out if no valid messages are received for
+ * timeout.value seconds; getting kicked off by the server operator; a program
+ * error, like an overflowed reliable buffer */
+enum{
+ /* for preventing denial of service attacks that could cycle all of
+ * them out before legitimate users connected */
+ MAX_CHALLENGES = 1024,
+ SV_OUTPUTBUF_LENGTH = MAX_MSGLEN - 16
+};
+struct challenge_t{
+ netadr_t adr;
+ int challenge;
+ int time;
+};
+struct server_static_t{
+ qboolean initialized; // sv_init has completed
+ int realtime; // always increasing, no clamping, etc
+ char mapcmd[MAX_TOKEN_CHARS]; // ie: *intro.cin+base
+ int spawncount; // incremented each server start used to check late spawns
+ client_t *clients; // [maxclients->value];
+ int num_client_entities; // maxclients->value*UPDATE_BACKUP*MAX_PACKET_ENTITIES
+ int next_client_entities; // next client_entity to use
+ entity_state_t *client_entities; // [num_client_entities]
+ int last_heartbeat;
+ challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting
+ /* serverrecord values */
+ FILE *demofile;
+ sizebuf_t demo_multicast;
+ uchar demo_multicast_buf[MAX_MSGLEN];
+};
+extern server_static_t svs; // persistant server info
+
+extern edict_t *sv_player;
+extern char sv_outputbuf[SV_OUTPUTBUF_LENGTH];
--- /dev/null
+++ b/files.c
@@ -1,0 +1,860 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+// define this to dissalow any data but the demo pak file
+//#define NO_ADDONS
+
+// if a packfile directory differs from this, it is assumed to be hacked
+// Full version
+#define PAK0_CHECKSUM 0x40e614e0
+// Demo
+//#define PAK0_CHECKSUM 0xb2c6d7ea
+// OEM
+//#define PAK0_CHECKSUM 0x78e135c
+
+/*
+=============================================================================
+
+QUAKE FILESYSTEM
+
+=============================================================================
+*/
+
+
+//
+// in memory
+//
+
+typedef struct
+{
+ char name[MAX_QPATH];
+ int filepos, filelen;
+} packfile_t;
+
+typedef struct pack_s
+{
+ char filename[MAX_OSPATH];
+ FILE *handle;
+ int numfiles;
+ packfile_t *files;
+} pack_t;
+
+char fs_gamedir[MAX_OSPATH];
+cvar_t *fs_basedir;
+cvar_t *fs_cddir;
+cvar_t *fs_gamedirvar;
+
+typedef struct filelink_s
+{
+ struct filelink_s *next;
+ char *from;
+ int fromlength;
+ char *to;
+} filelink_t;
+
+filelink_t *fs_links;
+
+typedef struct searchpath_s
+{
+ char filename[MAX_OSPATH];
+ pack_t *pack; // only one of filename / pack will be used
+ struct searchpath_s *next;
+} searchpath_t;
+
+searchpath_t *fs_searchpaths;
+searchpath_t *fs_base_searchpaths; // without gamedirs
+
+
+/*
+
+All of Quake's data access is through a hierchal file system, but the contents of the file system can be transparently merged from several sources.
+
+The "base directory" is the path to the directory holding the quake.exe and all game directories. The sys_* files pass this to host_init in quakeparms_t->basedir. This can be overridden with the "-basedir" command line parm to allow code debugging in a different directory. The base directory is
+only used during filesystem initialization.
+
+The "game directory" is the first tree on the search path and directory that all generated files (savegames, screenshots, demos, config files) will be saved to. This can be overridden with the "-game" command line parameter. The game directory can never be changed while quake is executing. This is a precacution against having a malicious server instruct clients to write files over areas they shouldn't.
+
+*/
+
+
+/*
+================
+FS_filelength
+================
+*/
+int FS_filelength (FILE *f)
+{
+ int pos;
+ int end;
+
+ pos = ftell (f);
+ fseek (f, 0, SEEK_END);
+ end = ftell (f);
+ fseek (f, pos, SEEK_SET);
+
+ return end;
+}
+
+
+/*
+============
+FS_CreatePath
+
+Creates any directories needed to store the given filename
+============
+*/
+void FS_CreatePath (char *path)
+{
+ char *ofs;
+
+ for (ofs = path+1 ; *ofs ; ofs++)
+ {
+ if (*ofs == '/')
+ { // create the directory
+ *ofs = 0;
+ Sys_Mkdir (path);
+ *ofs = '/';
+ }
+ }
+}
+
+
+/*
+==============
+FS_FCloseFile
+
+For some reason, other dll's can't just cal fclose()
+on files returned by FS_FOpenFile...
+==============
+*/
+void FS_FCloseFile (FILE *f)
+{
+ fclose (f);
+}
+
+
+// RAFAEL
+/*
+ Developer_searchpath
+*/
+int Developer_searchpath (int /*who*/)
+{
+
+ // PMM - warning removal
+// char *start;
+ searchpath_t *search;
+
+ for (search = fs_searchpaths ; search ; search = search->next)
+ {
+ if (strstr (search->filename, "xatrix"))
+ return 1;
+
+ if (strstr (search->filename, "rogue"))
+ return 2;
+/*
+ start = strchr (search->filename, ch);
+
+ if (start == NULL)
+ continue;
+
+ if (strcmp (start ,"xatrix") == 0)
+ return (1);
+*/
+ }
+ return (0);
+
+}
+
+
+/*
+===========
+FS_FOpenFile
+
+Finds the file in the search path.
+returns filesize and an open FILE *
+Used for streaming data out of either a pak file or
+a seperate file.
+===========
+*/
+int file_from_pak = 0;
+#ifndef NO_ADDONS
+int FS_FOpenFile (char *filename, FILE **file)
+{
+ searchpath_t *search;
+ char netpath[MAX_OSPATH];
+ pack_t *pak;
+ int i;
+ filelink_t *link;
+
+ file_from_pak = 0;
+
+ // check for links first
+ for (link = fs_links ; link ; link=link->next)
+ {
+ if (!strncmp (filename, link->from, link->fromlength))
+ {
+ Com_sprintf (netpath, sizeof(netpath), "%s%s",link->to, filename+link->fromlength);
+ *file = fopen (netpath, "rb");
+ if (*file)
+ {
+ Com_DPrintf ("link file: %s\n",netpath);
+ return FS_filelength (*file);
+ }
+ return -1;
+ }
+ }
+
+//
+// search through the path, one element at a time
+//
+ for (search = fs_searchpaths ; search ; search = search->next)
+ {
+ // is the element a pak file?
+ if (search->pack)
+ {
+ // look through all the pak file elements
+ pak = search->pack;
+ for (i=0 ; i<pak->numfiles ; i++)
+ if (!cistrcmp (pak->files[i].name, filename))
+ { // found it!
+ file_from_pak = 1;
+ Com_DPrintf ("PackFile: %s : %s\n",pak->filename, filename);
+ // open a new file on the pakfile
+ *file = fopen (pak->filename, "rb");
+ if (!*file)
+ Com_Error (ERR_FATAL, "Couldn't reopen %s", pak->filename);
+ fseek (*file, pak->files[i].filepos, SEEK_SET);
+ return pak->files[i].filelen;
+ }
+ }
+ else
+ {
+ // check a file in the directory tree
+
+ Com_sprintf (netpath, sizeof(netpath), "%s/%s",search->filename, filename);
+
+ *file = fopen (netpath, "rb");
+ if (!*file)
+ continue;
+
+ Com_DPrintf ("FindFile: %s\n",netpath);
+
+ return FS_filelength (*file);
+ }
+
+ }
+
+ Com_DPrintf ("FindFile: can't find %s\n", filename);
+
+ *file = NULL;
+ return -1;
+}
+
+#else
+
+// this is just for demos to prevent add on hacking
+
+int FS_FOpenFile (char *filename, FILE **file)
+{
+ searchpath_t *search;
+ char netpath[MAX_OSPATH];
+ pack_t *pak;
+ int i;
+
+ file_from_pak = 0;
+
+ // get config from directory, everything else from pak
+ if (!strcmp(filename, "config.cfg") || !strncmp(filename, "players/", 8))
+ {
+ Com_sprintf (netpath, sizeof(netpath), "%s/%s",FS_Gamedir(), filename);
+
+ *file = fopen (netpath, "rb");
+ if (!*file)
+ return -1;
+
+ Com_DPrintf ("FindFile: %s\n",netpath);
+
+ return FS_filelength (*file);
+ }
+
+ for (search = fs_searchpaths ; search ; search = search->next)
+ if (search->pack)
+ break;
+ if (!search)
+ {
+ *file = NULL;
+ return -1;
+ }
+
+ pak = search->pack;
+ for (i=0 ; i<pak->numfiles ; i++)
+ if (!cistrcmp (pak->files[i].name, filename))
+ { // found it!
+ file_from_pak = 1;
+ Com_DPrintf ("PackFile: %s : %s\n",pak->filename, filename);
+ // open a new file on the pakfile
+ *file = fopen (pak->filename, "rb");
+ if (!*file)
+ Com_Error (ERR_FATAL, "Couldn't reopen %s", pak->filename);
+ fseek (*file, pak->files[i].filepos, SEEK_SET);
+ return pak->files[i].filelen;
+ }
+
+ Com_DPrintf ("FindFile: can't find %s\n", filename);
+
+ *file = NULL;
+ return -1;
+}
+
+#endif
+
+
+/*
+=================
+FS_ReadFile
+
+Properly handles partial reads
+=================
+*/
+void CDAudio_Stop(void);
+#define MAX_READ 0x10000 // read in blocks of 64k
+void FS_Read (void *buffer, int len, FILE *f)
+{
+ int block, remaining;
+ int read;
+ byte *buf;
+ int tries;
+
+ buf = (byte *)buffer;
+
+ // read in chunks for progress bar
+ remaining = len;
+ tries = 0;
+ while (remaining)
+ {
+ block = remaining;
+ if (block > MAX_READ)
+ block = MAX_READ;
+ read = fread (buf, 1, block, f);
+ if (read == 0)
+ {
+ // we might have been trying to read from a CD
+ if (!tries)
+ {
+ tries = 1;
+ CDAudio_Stop();
+ }
+ else
+ Com_Error (ERR_FATAL, "FS_Read: 0 bytes read");
+ }
+
+ if (read == -1)
+ Com_Error (ERR_FATAL, "FS_Read: -1 bytes read");
+
+ // do some progress bar thing here...
+
+ remaining -= read;
+ buf += read;
+ }
+}
+
+/*
+============
+FS_LoadFile
+
+Filename are reletive to the quake search path
+a null buffer will just return the file length without loading
+============
+*/
+int FS_LoadFile (char *path, void **buffer)
+{
+ FILE *h;
+ byte *buf;
+ int len;
+
+// look for it in the filesystem or pack files
+ len = FS_FOpenFile (path, &h);
+ if (!h)
+ {
+ if (buffer)
+ *buffer = NULL;
+ return -1;
+ }
+
+ if (!buffer)
+ {
+ fclose (h);
+ return len;
+ }
+
+ buf = Z_Malloc(len);
+ *buffer = buf;
+
+ FS_Read (buf, len, h);
+
+ fclose (h);
+
+ return len;
+}
+
+
+/*
+=============
+FS_FreeFile
+=============
+*/
+void FS_FreeFile (void *buffer)
+{
+ Z_Free (buffer);
+}
+
+/*
+=================
+FS_LoadPackFile
+
+Takes an explicit (not game tree related) path to a pak file.
+
+Loads the header and directory, adding the files at the beginning
+of the list so they override previous pack files.
+=================
+*/
+pack_t *FS_LoadPackFile (char *packfile)
+{
+ dpackheader_t header;
+ int i;
+ packfile_t *newfiles;
+ int numpackfiles;
+ pack_t *pack;
+ FILE *packhandle;
+ dpackfile_t info[MAX_FILES_IN_PACK];
+ unsigned checksum;
+
+ packhandle = fopen(packfile, "rb");
+ if (!packhandle)
+ return NULL;
+
+ fread (&header, 1, sizeof(header), packhandle);
+ if (LittleLong(header.ident) != IDPAKHEADER)
+ Com_Error (ERR_FATAL, "%s is not a packfile", packfile);
+ header.dirofs = LittleLong (header.dirofs);
+ header.dirlen = LittleLong (header.dirlen);
+
+ numpackfiles = header.dirlen / sizeof(dpackfile_t);
+
+ if (numpackfiles > MAX_FILES_IN_PACK)
+ Com_Error (ERR_FATAL, "%s has %i files", packfile, numpackfiles);
+
+ newfiles = Z_Malloc (numpackfiles * sizeof(packfile_t));
+
+ fseek (packhandle, header.dirofs, SEEK_SET);
+ fread (info, 1, header.dirlen, packhandle);
+
+// crc the directory to check for modifications
+ checksum = Com_BlockChecksum ((void *)info, header.dirlen);
+
+#ifdef NO_ADDONS
+ if (checksum != PAK0_CHECKSUM)
+ return NULL;
+#else
+ USED(checksum);
+#endif
+// parse the directory
+ for (i=0 ; i<numpackfiles ; i++)
+ {
+ strcpy (newfiles[i].name, info[i].name);
+ newfiles[i].filepos = LittleLong(info[i].filepos);
+ newfiles[i].filelen = LittleLong(info[i].filelen);
+ }
+
+ pack = Z_Malloc (sizeof (pack_t));
+ strcpy (pack->filename, packfile);
+ pack->handle = packhandle;
+ pack->numfiles = numpackfiles;
+ pack->files = newfiles;
+
+ Com_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
+ return pack;
+}
+
+
+/*
+================
+FS_AddGameDirectory
+
+Sets fs_gamedir, adds the directory to the head of the path,
+then loads and adds pak1.pak pak2.pak ...
+================
+*/
+void FS_AddGameDirectory (char *dir)
+{
+ int i;
+ searchpath_t *search;
+ pack_t *pak;
+ char pakfile[MAX_OSPATH];
+
+ strcpy (fs_gamedir, dir);
+
+ //
+ // add the directory to the search path
+ //
+ search = Z_Malloc (sizeof(searchpath_t));
+ strcpy (search->filename, dir);
+ search->next = fs_searchpaths;
+ fs_searchpaths = search;
+
+ //
+ // add any pak files in the format pak0.pak pak1.pak, ...
+ //
+ for (i=0; i<10; i++)
+ {
+ Com_sprintf (pakfile, sizeof(pakfile), "%s/pak%i.pak", dir, i);
+ pak = FS_LoadPackFile (pakfile);
+ if (!pak)
+ continue;
+ search = Z_Malloc (sizeof(searchpath_t));
+ search->pack = pak;
+ search->next = fs_searchpaths;
+ fs_searchpaths = search;
+ }
+
+
+}
+
+/*
+============
+FS_Gamedir
+
+Called to find where to write a file (demos, savegames, etc)
+============
+*/
+char *FS_Gamedir (void)
+{
+ return fs_gamedir;
+}
+
+/*
+=============
+FS_ExecAutoexec
+=============
+*/
+void FS_ExecAutoexec (void)
+{
+ char *dir;
+ char name [MAX_QPATH];
+
+ dir = Cvar_VariableString("gamedir");
+ if (*dir)
+ Com_sprintf(name, sizeof(name), "%s/%s/autoexec.cfg", fs_basedir->string, dir);
+ else
+ Com_sprintf(name, sizeof(name), "%s/%s/autoexec.cfg", fs_basedir->string, BASEDIRNAME);
+ if (Sys_FindFirst(name, 0, SFF_SUBDIR))
+ Cbuf_AddText ("exec autoexec.cfg\n");
+ Sys_FindClose();
+}
+
+
+/*
+================
+FS_SetGamedir
+
+Sets the gamedir and path to a different directory.
+================
+*/
+void FS_SetGamedir (char *dir)
+{
+ searchpath_t *next;
+
+ if (strstr(dir, "..") || strstr(dir, "/")
+ || strstr(dir, "\\") || strstr(dir, ":") )
+ {
+ Com_Printf ("Gamedir should be a single filename, not a path\n");
+ return;
+ }
+
+ //
+ // free up any current game dir info
+ //
+ while (fs_searchpaths != fs_base_searchpaths)
+ {
+ if (fs_searchpaths->pack)
+ {
+ fclose (fs_searchpaths->pack->handle);
+ Z_Free (fs_searchpaths->pack->files);
+ Z_Free (fs_searchpaths->pack);
+ }
+ next = fs_searchpaths->next;
+ Z_Free (fs_searchpaths);
+ fs_searchpaths = next;
+ }
+
+ //
+ // flush all data, so it will be forced to reload
+ //
+ if (dedicated && !dedicated->value)
+ Cbuf_AddText ("vid_restart\nsnd_restart\n");
+
+ Com_sprintf (fs_gamedir, sizeof(fs_gamedir), "%s/%s", fs_basedir->string, dir);
+
+ if (!strcmp(dir,BASEDIRNAME) || (*dir == 0))
+ {
+ Cvar_FullSet ("gamedir", "", CVAR_SERVERINFO|CVAR_NOSET);
+ Cvar_FullSet ("game", "", CVAR_LATCH|CVAR_SERVERINFO);
+ }
+ else
+ {
+ Cvar_FullSet ("gamedir", dir, CVAR_SERVERINFO|CVAR_NOSET);
+ if (fs_cddir->string[0])
+ FS_AddGameDirectory (va("%s/%s", fs_cddir->string, dir) );
+ FS_AddGameDirectory (va("%s/%s", fs_basedir->string, dir) );
+ }
+}
+
+
+/*
+================
+FS_Link_f
+
+Creates a filelink_t
+================
+*/
+void FS_Link_f (void)
+{
+ filelink_t *l, **prev;
+
+ if (Cmd_Argc() != 3)
+ {
+ Com_Printf ("USAGE: link <from> <to>\n");
+ return;
+ }
+
+ // see if the link already exists
+ prev = &fs_links;
+ for (l=fs_links ; l ; l=l->next)
+ {
+ if (!strcmp (l->from, Cmd_Argv(1)))
+ {
+ Z_Free (l->to);
+ if (!strlen(Cmd_Argv(2)))
+ { // delete it
+ *prev = l->next;
+ Z_Free (l->from);
+ Z_Free (l);
+ return;
+ }
+ l->to = CopyString (Cmd_Argv(2));
+ return;
+ }
+ prev = &l->next;
+ }
+
+ // create a new link
+ l = Z_Malloc(sizeof(*l));
+ l->next = fs_links;
+ fs_links = l;
+ l->from = CopyString(Cmd_Argv(1));
+ l->fromlength = strlen(l->from);
+ l->to = CopyString(Cmd_Argv(2));
+}
+
+/*
+** FS_ListFiles
+*/
+char **FS_ListFiles( char *findname, int *numfiles, unsigned musthave, unsigned canthave )
+{
+ char *s;
+ int nfiles = 0;
+ char **list;
+
+ s = Sys_FindFirst( findname, musthave, canthave );
+ while ( s )
+ {
+ if ( s[strlen(s)-1] != '.' )
+ nfiles++;
+ s = Sys_FindNext( musthave, canthave );
+ }
+ Sys_FindClose ();
+
+ if ( !nfiles )
+ return NULL;
+
+ nfiles++; // add space for a guard
+ *numfiles = nfiles;
+
+ list = malloc( sizeof( char * ) * nfiles );
+ memset( list, 0, sizeof( char * ) * nfiles );
+
+ s = Sys_FindFirst( findname, musthave, canthave );
+ nfiles = 0;
+ while ( s )
+ {
+ if ( s[strlen(s)-1] != '.' )
+ {
+ list[nfiles] = strdup( s );
+ nfiles++;
+ }
+ s = Sys_FindNext( musthave, canthave );
+ }
+ Sys_FindClose ();
+
+ return list;
+}
+
+/*
+** FS_Dir_f
+*/
+void FS_Dir_f( void )
+{
+ char *path = NULL;
+ char findname[1024];
+ char wildcard[1024] = "*.*";
+ char **dirnames;
+ int ndirs;
+
+ if ( Cmd_Argc() != 1 )
+ {
+ strcpy( wildcard, Cmd_Argv( 1 ) );
+ }
+
+ while ( ( path = FS_NextPath( path ) ) != NULL )
+ {
+ char *tmp = findname;
+
+ Com_sprintf( findname, sizeof(findname), "%s/%s", path, wildcard );
+
+ while ( *tmp != 0 )
+ {
+ if ( *tmp == '\\' )
+ *tmp = '/';
+ tmp++;
+ }
+ Com_Printf( "Directory of %s\n", findname );
+ Com_Printf( "----\n" );
+
+ if ( ( dirnames = FS_ListFiles( findname, &ndirs, 0, 0 ) ) != 0 )
+ {
+ int i;
+
+ for ( i = 0; i < ndirs-1; i++ )
+ {
+ if ( strrchr( dirnames[i], '/' ) )
+ Com_Printf( "%s\n", strrchr( dirnames[i], '/' ) + 1 );
+ else
+ Com_Printf( "%s\n", dirnames[i] );
+
+ free( dirnames[i] );
+ }
+ free( dirnames );
+ }
+ Com_Printf( "\n" );
+ };
+}
+
+/*
+============
+FS_Path_f
+
+============
+*/
+void FS_Path_f (void)
+{
+ searchpath_t *s;
+ filelink_t *l;
+
+ Com_Printf ("Current search path:\n");
+ for (s=fs_searchpaths ; s ; s=s->next)
+ {
+ if (s == fs_base_searchpaths)
+ Com_Printf ("----------\n");
+ if (s->pack)
+ Com_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
+ else
+ Com_Printf ("%s\n", s->filename);
+ }
+
+ Com_Printf ("\nLinks:\n");
+ for (l=fs_links ; l ; l=l->next)
+ Com_Printf ("%s : %s\n", l->from, l->to);
+}
+
+/*
+================
+FS_NextPath
+
+Allows enumerating all of the directories in the search path
+================
+*/
+char *FS_NextPath (char *prevpath)
+{
+ searchpath_t *s;
+ char *prev;
+
+ if (!prevpath)
+ return fs_gamedir;
+
+ prev = fs_gamedir;
+ for (s=fs_searchpaths ; s ; s=s->next)
+ {
+ if (s->pack)
+ continue;
+ if (prevpath == prev)
+ return s->filename;
+ prev = s->filename;
+ }
+
+ return NULL;
+}
+
+
+/*
+================
+FS_InitFilesystem
+================
+*/
+void FS_InitFilesystem (void)
+{
+ static char homedir[1024];
+ char *home;
+
+ Cmd_AddCommand ("path", FS_Path_f);
+ Cmd_AddCommand ("link", FS_Link_f);
+ Cmd_AddCommand ("dir", FS_Dir_f );
+
+ //
+ // basedir <path>
+ // allows the game to run from outside the data tree
+ //
+ if(home = getenv("home")){
+ snprint(homedir, sizeof homedir, "%s/lib/quake2", home);
+ free(home);
+ }else
+ snprint(homedir, sizeof homedir, "/sys/lib/quake2");
+ fs_basedir = Cvar_Get ("basedir", homedir, CVAR_NOSET);
+
+ //
+ // cddir <path>
+ // Logically concatenates the cddir after the basedir for
+ // allows the game to run from outside the data tree
+ //
+ fs_cddir = Cvar_Get ("cddir", "", CVAR_NOSET);
+ if (fs_cddir->string[0])
+ FS_AddGameDirectory (va("%s/"BASEDIRNAME, fs_cddir->string) );
+
+ //
+ // start up with baseq2 by default
+ //
+ FS_AddGameDirectory (va("%s/"BASEDIRNAME, fs_basedir->string) );
+
+ // any set gamedirs will be freed up to here
+ fs_base_searchpaths = fs_searchpaths;
+
+ // check for game override
+ fs_gamedirvar = Cvar_Get ("game", "", CVAR_LATCH|CVAR_SERVERINFO);
+ if (fs_gamedirvar->string[0])
+ FS_SetGamedir (fs_gamedirvar->string);
+}
+
+
+
--- /dev/null
+++ b/fns.h
@@ -1,0 +1,613 @@
+void Qcommon_Init(int, char **);
+void Qcommon_Frame(int);
+void Z_Free(void *);
+void* Z_Malloc(int);
+void* Z_TagMalloc(int, int);
+void Z_FreeTags(int);
+int COM_Argc(void);
+char* COM_Argv(int);
+void COM_ClearArgv(int);
+int COM_CheckParm(char *);
+void COM_AddParm(char *);
+void COM_Init(void);
+void COM_InitArgv(int, char **);
+char* COM_SkipPath(char *);
+void COM_StripExtension(char *, char *);
+void COM_FileBase(char *, char *);
+void COM_FilePath(char *, char *);
+void COM_DefaultExtension(char *, char *);
+char* COM_Parse(char **);
+void Com_PageInMemory(uchar *, int);
+char* CopyString(char *);
+char* va(char *, ...);
+void Com_sprintf(char *, int, char *, ...);
+void Info_Print(char *);
+void Com_BeginRedirect(int, char *, int, void(*));
+void Com_EndRedirect(void);
+void Com_Printf(char *, ...);
+void Com_DPrintf(char *, ...);
+void Com_Error(int, char *, ...);
+void Com_Quit(void);
+int Com_ServerState(void);
+void Com_SetServerState(int state);
+unsigned Com_BlockChecksum(void *, int);
+uchar COM_BlockSequenceCRCByte(uchar *, int, int);
+float qfrand(void);
+float crand(void);
+
+void FS_InitFilesystem(void);
+void FS_SetGamedir(char *);
+char* FS_Gamedir(void);
+char* FS_NextPath(char *);
+void FS_ExecAutoexec(void);
+int FS_FOpenFile(char *, FILE **);
+void FS_FCloseFile(FILE *);
+int FS_LoadFile(char *, void **);
+void FS_Read(void *, int, FILE *);
+void FS_FreeFile(void *);
+void FS_CreatePath(char *);
+
+char* Sys_FindFirst(char *, uint, uint);
+char* Sys_FindNext(uint, uint);
+void Sys_FindClose(void);
+int Sys_Milliseconds(void);
+void Sys_Mkdir(char *);
+void Sys_Init(void);
+void Sys_AppActivate(void);
+void Sys_UnloadGame(void);
+char* Sys_ConsoleInput(void);
+void Sys_ConsoleOutput(char *);
+void Sys_SendKeyEvents(void);
+void Sys_Error(char *, ...);
+void Sys_Quit(void);
+char* Sys_GetClipboardData(void);
+void Sys_CopyProtect(void);
+void Sys_MakeCodeWriteable(ulong, ulong);
+void Sys_SetFPCW(void);
+vlong flen(int);
+void* Hunk_Begin(int);
+void* Hunk_Alloc(int);
+void Hunk_Free(void *);
+int Hunk_End(void);
+
+void CL_Init(void);
+void CL_Drop(void);
+void CL_Shutdown(void);
+void CL_Frame(int);
+
+short BigShort(short);
+short LittleShort(short);
+int BigLong(int);
+int LittleLong(int);
+float BigFloat(float);
+float LittleFloat(float);
+void Swap_Init(void);
+
+char* Info_ValueForKey(char *, char *);
+void Info_RemoveKey(char *, char *);
+void Info_SetValueForKey(char *, char *, char *);
+qboolean Info_Validate(char *);
+
+void SZ_Init(sizebuf_t *, uchar *, int);
+void SZ_Clear(sizebuf_t *);
+void* SZ_GetSpace(sizebuf_t *, int);
+void SZ_Write(sizebuf_t *, void *, int);
+void SZ_Print(sizebuf_t *, char *);
+void MSG_WriteChar(sizebuf_t *, int);
+void MSG_WriteByte(sizebuf_t *, int);
+void MSG_WriteShort(sizebuf_t *, int);
+void MSG_WriteLong(sizebuf_t *, int);
+void MSG_WriteFloat(sizebuf_t *, float);
+void MSG_WriteString(sizebuf_t *, char *);
+void MSG_WriteCoord(sizebuf_t *, float);
+void MSG_WritePos(sizebuf_t *, vec3_t);
+void MSG_WriteAngle(sizebuf_t *, float);
+void MSG_WriteAngle16(sizebuf_t *, float);
+void MSG_WriteDeltaUsercmd(sizebuf_t *, usercmd_t *, usercmd_t *);
+void MSG_WriteDeltaEntity(entity_state_t *, entity_state_t *, sizebuf_t *, qboolean, qboolean);
+void MSG_WriteDir(sizebuf_t *, vec3_t);
+void MSG_BeginReading(sizebuf_t *);
+int MSG_ReadChar(sizebuf_t *);
+int MSG_ReadByte(sizebuf_t *);
+int MSG_ReadShort(sizebuf_t *);
+int MSG_ReadLong(sizebuf_t *);
+float MSG_ReadFloat(sizebuf_t *);
+char* MSG_ReadString(sizebuf_t *);
+char* MSG_ReadStringLine(sizebuf_t *);
+float MSG_ReadCoord(sizebuf_t *);
+void MSG_ReadPos(sizebuf_t *, vec3_t);
+float MSG_ReadAngle(sizebuf_t *);
+float MSG_ReadAngle16(sizebuf_t *);
+void MSG_ReadDeltaUsercmd(sizebuf_t *, usercmd_t *, usercmd_t *);
+void MSG_ReadDir(sizebuf_t *, vec3_t);
+void MSG_ReadData(sizebuf_t *, void *, int);
+
+void CRC_Init(ushort *);
+void CRC_ProcessByte(ushort *, uchar);
+ushort CRC_Value(ushort);
+ushort CRC_Block(uchar *, int);
+
+void Cbuf_Init(void);
+void Cbuf_AddText(char *);
+void Cbuf_InsertText(char *);
+void Cbuf_ExecuteText(int, char *);
+void Cbuf_Execute(void);
+void Cbuf_AddEarlyCommands(qboolean);
+qboolean Cbuf_AddLateCommands(void);
+void Cbuf_CopyToDefer(void);
+void Cbuf_InsertFromDefer(void);
+void Cmd_Init(void);
+void Cmd_AddCommand(char *, xcommand_t);
+void Cmd_RemoveCommand(char *);
+qboolean Cmd_Exists(char *);
+char* Cmd_CompleteCommand(char *);
+int Cmd_Argc(void);
+char* Cmd_Argv(int);
+char* Cmd_Args(void);
+void Cmd_TokenizeString(char *, qboolean);
+void Cmd_ExecuteString(char *);
+void Cmd_ForwardToServer(void);
+
+void Con_DrawCharacter(int, int, int);
+void Con_CheckResize(void);
+void Con_Init(void);
+void Con_DrawConsole(float);
+void Con_Print(char *);
+void Con_CenteredPrint(char *);
+void Con_Clear_f(void);
+void Con_DrawNotify(void);
+void Con_ClearNotify(void);
+void Con_ToggleConsole_f(void);
+void DrawString(int, int, char *);
+void DrawAltString(int, int, char *);
+
+cvar_t* Cvar_Get(char *, char *, int);
+cvar_t* Cvar_Set(char *, char *);
+cvar_t* Cvar_ForceSet(char *, char *);
+cvar_t* Cvar_FullSet(char *, char *, int);
+void Cvar_SetValue(char *, float);
+float Cvar_VariableValue(char *);
+char* Cvar_VariableString(char *);
+char* Cvar_CompleteVariable(char *);
+void Cvar_GetLatchedVars(void);
+qboolean Cvar_Command(void);
+void Cvar_WriteVariables(char *);
+void Cvar_Init(void);
+char* Cvar_Userinfo(void);
+char* Cvar_Serverinfo(void);
+
+void CL_ParticleSteamEffect2(cl_sustain_t *);
+void CL_TeleporterParticles(entity_state_t *);
+void CL_ParticleEffect(vec3_t, vec3_t, int, int);
+void CL_ParticleEffect2(vec3_t, vec3_t, int, int);
+void CL_ParticleEffect3(vec3_t, vec3_t, int, int);
+void CL_ClearEffects(void);
+void CL_ClearTEnts(void);
+void CL_BlasterTrail(vec3_t, vec3_t);
+void CL_QuadTrail(vec3_t, vec3_t);
+void CL_RailTrail(vec3_t, vec3_t);
+void CL_BubbleTrail(vec3_t, vec3_t);
+void CL_FlagTrail(vec3_t, vec3_t, float);
+void CL_IonripperTrail(vec3_t, vec3_t);
+void CL_BlasterParticles2(vec3_t, vec3_t, uint);
+void CL_BlasterTrail2(vec3_t, vec3_t);
+void CL_DebugTrail(vec3_t, vec3_t);
+void CL_SmokeTrail(vec3_t, vec3_t, int, int, int);
+void CL_Flashlight(int, vec3_t);
+void CL_ForceWall(vec3_t, vec3_t, int);
+void CL_FlameEffects(centity_t *, vec3_t);
+void CL_GenericParticleEffect(vec3_t, vec3_t, int, int, int, int, float);
+void CL_BubbleTrail2(vec3_t, vec3_t, int);
+void CL_Heatbeam(vec3_t, vec3_t);
+void CL_ParticleSteamEffect(vec3_t, vec3_t, int, int, int);
+void CL_TrackerTrail(vec3_t, vec3_t, int);
+void CL_Tracker_Explode(vec3_t);
+void CL_TagTrail(vec3_t, vec3_t, float);
+void CL_ColorFlash(vec3_t, int, int, float, float, float);
+void CL_Tracker_Shell(vec3_t);
+void CL_MonsterPlasma_Shell(vec3_t);
+void CL_ColorExplosionParticles(vec3_t, int, int);
+void CL_ParticleSmokeEffect(vec3_t, vec3_t, int, int, int);
+void CL_Widowbeamout(cl_sustain_t *);
+void CL_Nukeblast(cl_sustain_t *);
+void CL_WidowSplash(vec3_t);
+int CL_ParseEntityBits(int *);
+void CL_ParseDelta(entity_state_t *, entity_state_t *, int, int);
+void CL_ParseFrame(void);
+void CL_ParseTEnt(void);
+void CL_ParseConfigString(void);
+void CL_ParseMuzzleFlash(void);
+void CL_ParseMuzzleFlash2(void);
+void SmokeAndFlash(vec3_t);
+void CL_SetLightstyle(int);
+void CL_RunParticles(void);
+void CL_RunDLights(void);
+void CL_RunLightStyles(void);
+void CL_AddEntities(void);
+void CL_AddDLights(void);
+void CL_AddTEnts(void);
+void CL_AddLightStyles(void);
+void CL_PrepRefresh(void);
+void CL_RegisterSounds(void);
+void CL_Quit_f(void);
+void CL_ParseLayout(void);
+void CL_Init(void);
+void CL_FixUpGender(void);
+void CL_Disconnect(void);
+void CL_Disconnect_f(void);
+void CL_GetChallengePacket(void);
+void CL_PingServers_f(void);
+void CL_Snd_Restart_f(void);
+void CL_RequestNextDownload(void);
+void CL_InitInput(void);
+void CL_SendCmd(void);
+void CL_SendMove(usercmd_t *);
+void CL_ClearState(void);
+void CL_ReadPackets(void);
+int CL_ReadFromServer(void);
+void CL_WriteToServer(usercmd_t *);
+void CL_BaseMove(usercmd_t *);
+void IN_CenterView(void);
+float CL_KeyState(kbutton_t *);
+char* Key_KeynumToString(int);
+void CL_WriteDemoMessage(void);
+void CL_Stop_f(void);
+void CL_Record_f(void);
+void CL_ParseServerMessage(void);
+void CL_LoadClientinfo(clientinfo_t *, char *);
+void SHOWNET(char *);
+void CL_ParseClientinfo(int);
+void CL_Download_f(void);
+void V_Init(void);
+void V_RenderView(float);
+void V_AddEntity(entity_t *);
+void V_AddParticle(vec3_t, int, float);
+void V_AddLight(vec3_t, float, float, float, float);
+void V_AddLightStyle(int, float, float, float);
+void CL_RegisterTEntSounds(void);
+void CL_RegisterTEntModels(void);
+void CL_SmokeAndFlash(vec3_t);
+void CL_InitPrediction(void);
+void CL_PredictMove(void);
+void CL_CheckPredictionError(void);
+cdlight_t* CL_AllocDlight(int);
+void CL_BigTeleportParticles(vec3_t);
+void CL_RocketTrail(vec3_t, vec3_t, centity_t *);
+void CL_DiminishingTrail(vec3_t, vec3_t, centity_t *, int);
+void CL_FlyEffect(centity_t *, vec3_t);
+void CL_BfgParticles(entity_t *);
+void CL_AddParticles(void);
+void CL_EntityEvent(entity_state_t *);
+void CL_TrapParticles(entity_t *);
+void M_Init(void);
+void M_Keydown(int);
+void M_Draw(void);
+void M_Menu_Main_f(void);
+void M_ForceMenuOff(void);
+void M_AddToServerList(netadr_t, char *);
+void CL_ParseInventory(void);
+void CL_KeyInventory(int);
+void CL_DrawInventory(void);
+void CL_PredictMovement(void);
+qboolean CL_CheckOrDownloadFile(char *);
+void CL_AddNetgraph(void);
+
+void SV_Init(void);
+void SV_Shutdown(char *, qboolean);
+void SV_Frame(int);
+void SV_FinalMessage(char *, qboolean);
+void SV_DropClient(client_t *);
+int SV_ModelIndex(char *);
+int SV_SoundIndex(char *);
+int SV_ImageIndex(char *);
+void SV_WriteClientdataToMessage(client_t *, sizebuf_t *);
+void SV_ExecuteUserCommand(char *);
+void SV_InitOperatorCommands(void);
+void SV_SendServerinfo(client_t *);
+void SV_UserinfoChanged(client_t *);
+void Master_Heartbeat(void);
+void Master_Packet(void);
+void SV_InitGame(void);
+void SV_Map(qboolean, char *, qboolean);
+void SV_PrepWorldFrame(void);
+void SV_FlushRedirect(int, char *);
+void SV_DemoCompleted(void);
+void SV_SendClientMessages(void);
+void SV_Multicast(vec3_t, multicast_t);
+void SV_StartSound(vec3_t, edict_t *, int, int, float, float, float);
+void SV_ClientPrintf(client_t *, int, char *, ...);
+void SV_BroadcastPrintf(int, char *, ...);
+void SV_BroadcastCommand(char *, ...);
+void SV_Nextserver(void);
+void SV_ExecuteClientMessage(client_t *);
+void SV_ReadLevelFile(void);
+void SV_Status_f(void);
+void SV_WriteFrameToClient(client_t *, sizebuf_t *);
+void SV_RecordDemoMessage(void);
+void SV_BuildClientFrame(client_t *);
+void SV_Error(char *, ...);
+void SV_InitGameProgs(void);
+void SV_ShutdownGameProgs(void);
+void SV_InitEdict(edict_t *);
+void SV_ClearWorld(void);
+void SV_UnlinkEdict(edict_t *);
+void SV_LinkEdict(edict_t *);
+int SV_AreaEdicts(vec3_t, vec3_t, edict_t **, int, int);
+int SV_PointContents(vec3_t);
+trace_t SV_Trace(vec3_t, vec3_t, vec3_t, vec3_t, edict_t *, int);
+
+void NET_Init(void);
+void NET_Shutdown(void);
+void NET_Config(qboolean);
+qboolean NET_GetPacket(netsrc_t, netadr_t *, sizebuf_t *);
+void NET_SendPacket(netsrc_t, int, void *, netadr_t);
+qboolean NET_CompareAdr(netadr_t, netadr_t);
+qboolean NET_CompareBaseAdr(netadr_t, netadr_t);
+qboolean NET_IsLocalAddress(netadr_t);
+char* NET_AdrToString(netadr_t);
+qboolean NET_StringToAdr (char *, netadr_t *);
+void NET_Sleep(int);
+
+void Netchan_Init(void);
+void Netchan_Setup(netsrc_t, netchan_t *, netadr_t, int);
+qboolean Netchan_NeedReliable(netchan_t *);
+void Netchan_Transmit(netchan_t *, int, uchar *);
+void Netchan_OutOfBand(int, netadr_t, int, uchar *);
+void Netchan_OutOfBandPrint(int, netadr_t, char *, ...);
+qboolean Netchan_Process(netchan_t *, sizebuf_t *);
+qboolean Netchan_CanReliable(netchan_t *);
+
+void Mod_Init(void);
+void Mod_ClearAll(void);
+model_t* Mod_ForName(char *, qboolean);
+void* Mod_Extradata(model_t *);
+void Mod_TouchModel(char *);
+mleaf_t* Mod_PointInLeaf(float *, model_t *);
+uchar* Mod_ClusterPVS(int, model_t *);
+void Mod_Modellist_f(void);
+void Mod_FreeAll(void);
+void Mod_Free(model_t *);
+
+void D_DrawSurfaces(void);
+void D_ViewChanged(void);
+void D_WarpScreen(void);
+void D_DrawSpans16(espan_t *);
+void D_DrawZSpans(espan_t *);
+void Turbulent8(espan_t *);
+void NonTurbulent8(espan_t *);
+void TransformVector(vec3_t, vec3_t);
+void SetUpForLineScan(fixed8_t, fixed8_t, fixed8_t, fixed8_t);
+surfcache_t* D_CacheSurface(msurface_t *, int);
+void R_DrawParticle(void);
+void R_PolysetUpdateTables(void);
+void R_DrawSurface(void);
+void R_RenderWorld(void);
+void R_ClearPolyList(void);
+void R_DrawPolyList(void);
+void R_DrawAlphaSurfaces(void);
+void R_DrawSprite(void);
+void R_DrawBeam(entity_t *);
+void R_RenderFace(msurface_t *, int);
+void R_RenderBmodelFace(bedge_t *, msurface_t *);
+void R_TransformPlane(mplane_t *, float *, float *);
+void R_TransformFrustum(void);
+void R_DrawSurfaceBlock16(void);
+void R_DrawSurfaceBlock8(void);
+void R_GenSkyTile(void *);
+void R_GenSkyTile16(void *);
+void R_Surf8Patch(void);
+void R_Surf16Patch(void);
+void R_DrawSubmodelPolygons(model_t *, int, mnode_t *);
+void R_DrawSolidClippedSubmodelPolygons(model_t *, mnode_t *);
+void R_AddPolygonEdges(emitpoint_t *, int, int);
+surf_t* R_GetSurf(void);
+void R_AliasDrawModel(void);
+void R_BeginEdgeFrame(void);
+void R_ScanEdges(void);
+void D_DrawSurfaces(void);
+void R_InsertNewEdges(edge_t *, edge_t *);
+void R_StepActiveU(edge_t *);
+void R_RemoveEdges(edge_t *);
+void R_PushDlights(model_t *);
+void R_Surf8Start(void);
+void R_Surf8End(void);
+void R_Surf16Start(void);
+void R_Surf16End(void);
+void R_EdgeCodeStart(void);
+void R_EdgeCodeEnd(void);
+void R_RotateBmodel(void);
+void R_InitTurb(void);
+void R_DrawParticles(void);
+void R_SurfacePatch(void);
+void R_DrawTriangle(void);
+void R_AliasClipTriangle(finalvert_t *, finalvert_t *, finalvert_t *);
+void R_PrintAliasStats(void);
+void R_PrintTimes(void);
+void R_PrintDSpeeds(void);
+void R_AnimateLight(void);
+void R_LightPoint(vec3_t, vec3_t);
+void R_SetupFrame(void);
+void R_cshift_f(void);
+void R_EmitEdge(mvertex_t *, mvertex_t *);
+void R_ClipEdge(mvertex_t *, mvertex_t *, clipplane_t *);
+void R_SplitEntityOnNode2(mnode_t *);
+float R_DLightPoint(vec3_t);
+void R_NewMap(void);
+void R_Register(void);
+void R_UnRegister(void);
+void Draw_InitLocal(void);
+qboolean R_Init(void *, void *);
+void R_Shutdown(void);
+void R_InitCaches(void);
+void D_FlushCaches(void);
+void R_ScreenShot_f(void);
+void R_BeginRegistration(char *map);
+model_t* R_RegisterModel(char *);
+void R_EndRegistration(void);
+void R_RenderFrame(refdef_t *);
+image_t* Draw_FindPic(char *);
+void Draw_GetPicSize(int *, int *, char *);
+void Draw_Pic(int, int, char *);
+void Draw_StretchPic(int, int, int, int, char *);
+void Draw_StretchRaw(int, int, int, int, int, int, uchar *);
+void Draw_Char(int, int, int);
+void Draw_TileClear(int, int, int, int, char *);
+void Draw_Fill(int, int, int, int, int);
+void Draw_FadeScreen(void);
+void Draw_GetPalette(void);
+void R_BeginFrame(float);
+void R_CinematicSetPalette(uchar *palette);
+void LoadPCX(char *, uchar **, uchar **, int *, int *);
+void R_InitImages(void);
+void R_ShutdownImages(void);
+image_t* R_FindImage(char *, imagetype_t);
+void R_FreeUnusedImages(void);
+void R_GammaCorrectAndSetPalette(uchar *pal);
+void R_InitSkyBox(void);
+void R_IMFlatShadedQuad(vec3_t, vec3_t, vec3_t, vec3_t, int, float);
+image_t* R_RegisterSkin(char *);
+
+void VectorMA(vec3_t, float, vec3_t, vec3_t);
+vec_t _DotProduct(vec3_t, vec3_t); // just in case you do't want to use the macros
+void _VectorSubtract(vec3_t, vec3_t, vec3_t);
+void _VectorAdd(vec3_t, vec3_t, vec3_t);
+void _VectorCopy(vec3_t, vec3_t);
+void ClearBounds(vec3_t, vec3_t);
+void AddPointToBounds(vec3_t, vec3_t, vec3_t);
+int VectorCompare(vec3_t, vec3_t);
+vec_t VectorLength(vec3_t);
+void CrossProduct(vec3_t, vec3_t, vec3_t);
+vec_t VectorNormalize(vec3_t);
+vec_t VectorNormalize2 (vec3_t, vec3_t);
+void VectorInverse(vec3_t);
+void VectorScale(vec3_t, vec_t, vec3_t);
+void R_ConcatRotations(float[3][3], float[3][3], float[3][3]);
+void R_ConcatTransforms(float[3][4], float[3][4], float[3][4]);
+void AngleVectors(vec3_t, vec3_t, vec3_t, vec3_t);
+int BoxOnPlaneSide(vec3_t, vec3_t, cplane_t *);
+float anglemod(float);
+float LerpAngle(float, float, float);
+void ProjectPointOnPlane(vec3_t, vec3_t, vec3_t);
+void PerpendicularVector(vec3_t, vec3_t);
+void RotatePointAroundVector(vec3_t, vec3_t, vec3_t, float);
+
+cmodel_t* CM_LoadMap(char *, qboolean, unsigned *);
+cmodel_t* CM_InlineModel(char *);
+int CM_NumClusters(void);
+int CM_NumInlineModels(void);
+char* CM_EntityString(void);
+int CM_HeadnodeForBox(vec3_t, vec3_t);
+int CM_PointContents(vec3_t, int);
+int CM_TransformedPointContents(vec3_t, int, vec3_t, vec3_t);
+trace_t CM_BoxTrace(vec3_t, vec3_t, vec3_t, vec3_t, int, int);
+trace_t CM_TransformedBoxTrace(vec3_t, vec3_t, vec3_t, vec3_t, int, int, vec3_t, vec3_t);
+uchar* CM_ClusterPVS(int);
+uchar* CM_ClusterPHS(int);
+int CM_PointLeafnum(vec3_t);
+int CM_BoxLeafnums(vec3_t, vec3_t, int *, int, int *);
+int CM_LeafContents(int);
+int CM_LeafCluster(int);
+int CM_LeafArea(int);
+void CM_SetAreaPortalState(int, qboolean);
+qboolean CM_AreasConnected(int, int);
+int CM_WriteAreaBits(uchar *, int);
+qboolean CM_HeadnodeVisible(int, uchar *);
+void CM_WritePortalState(FILE *);
+void CM_ReadPortalState(FILE *);
+
+void Pmove(pmove_t *);
+
+void SCR_Init(void);
+void SCR_UpdateScreen(void);
+void SCR_SizeUp(void);
+void SCR_SizeDown(void);
+void SCR_CenterPrint(char *);
+void SCR_BeginLoadingPlaque(void);
+void SCR_EndLoadingPlaque(void);
+void SCR_DebugGraph(float, int);
+void SCR_TouchPics(void);
+void SCR_RunConsole(void);
+void SCR_AddDirtyPoint(int, int);
+void SCR_DirtyScreen(void);
+void SCR_PlayCinematic (char *name);
+qboolean SCR_DrawCinematic(void);
+void SCR_RunCinematic(void);
+void SCR_StopCinematic(void);
+void SCR_FinishCinematic(void);
+
+void VID_Init(void);
+void VID_Shutdown(void);
+void VID_CheckChanges(void);
+void VID_MenuInit(void);
+void VID_MenuDraw(void);
+char* VID_MenuKey(int);
+
+void SWimp_BeginFrame(float);
+void SWimp_EndFrame(void);
+int SWimp_Init(void *, void *);
+void SWimp_SetPalette(uchar *);
+void SWimp_Shutdown(void);
+rserr_t SWimp_SetMode(int *, int *, int, qboolean);
+void SWimp_AppActivate(qboolean);
+
+void S_Init(void);
+void S_Shutdown(void);
+void S_StartSound(vec3_t, int, int, sfx_t *, float, float, float);
+void S_StartLocalSound(char *);
+void S_RawSamples(int, int, int, int, uchar *);
+void S_StopAllSounds(void);
+void S_Update(vec3_t, vec3_t, vec3_t, vec3_t);
+void S_Activate(qboolean);
+void S_BeginRegistration(void);
+sfx_t* S_RegisterSound(char *);
+void S_EndRegistration(void);
+void CL_GetEntitySoundOrigin(int, vec3_t);
+qboolean SNDDMA_Init(void);
+int SNDDMA_GetDMAPos(void);
+void SNDDMA_Shutdown(void);
+void SNDDMA_BeginPainting(void);
+void SNDDMA_Submit(void);
+wavinfo_t GetWavinfo(char *, uchar *, int);
+void S_InitScaletable(void);
+sfxcache_t* S_LoadSound(sfx_t *);
+void S_IssuePlaysound(playsound_t *);
+void S_PaintChannels(int);
+channel_t* S_PickChannel(int, int);
+void S_Spatialize(channel_t *);
+
+int CDAudio_Init(void);
+void CDAudio_Shutdown(void);
+void CDAudio_Play(int, qboolean);
+void CDAudio_Stop(void);
+void CDAudio_Update(void);
+void CDAudio_Activate(qboolean);
+
+void IN_Init(void);
+void IN_Shutdown(void);
+void IN_Commands(void);
+void IN_Frame(void);
+void IN_Move(usercmd_t *);
+void IN_Activate(qboolean);
+void IN_Grabm(int);
+
+void Key_Event(int, qboolean, unsigned);
+void Key_Init(void);
+void Key_WriteBindings(FILE *);
+void Key_SetBinding(int, char *);
+void Key_ClearStates(void);
+int Key_GetKey(void);
+
+qboolean Field_Key(menufield_t *, int);
+void Menu_AddItem(menuframework_t *, void *);
+void Menu_AdjustCursor(menuframework_t *, int);
+void Menu_Center(menuframework_t *);
+void Menu_Draw(menuframework_t *);
+void* Menu_ItemAtCursor(menuframework_t *);
+qboolean Menu_SelectItem(menuframework_t *);
+void Menu_SetStatusBar(menuframework_t *, char *);
+void Menu_SlideItem(menuframework_t *, int);
+int Menu_TallySlots(menuframework_t *);
+void Menu_DrawString(int, int, char *);
+void Menu_DrawStringDark(int, int, char *);
+void Menu_DrawStringR2L(int, int, char *);
+void Menu_DrawStringR2LDark(int, int, char *);
--- a/game/g_ai.c
+++ b/game/g_ai.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
qboolean FindTarget (edict_t *self);
extern cvar_t *maxclients;
--- a/game/g_chase.c
+++ b/game/g_chase.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
void UpdateChaseCam(edict_t *ent)
{
--- a/game/g_cmds.c
+++ b/game/g_cmds.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_player.h"
--- a/game/g_combat.c
+++ b/game/g_combat.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
/*
============
--- a/game/g_func.c
+++ b/game/g_func.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
/*
=========================================================
--- a/game/g_items.c
+++ b/game/g_items.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
qboolean Pickup_Weapon (edict_t *ent, edict_t *other);
--- a/game/g_local.h
+++ /dev/null
@@ -1,1074 +1,0 @@
-// g_local.h -- local definitions for game module
-
-// the "gameversion" client command will print this plus compile date
-#define GAMEVERSION "baseq2"
-
-// view pitching times
-#define DAMAGE_TIME 0.5
-#define FALL_TIME 0.3
-
-
-// edict->spawnflags
-// these are set with checkboxes on each entity in the map editor
-#define SPAWNFLAG_NOT_EASY 0x00000100
-#define SPAWNFLAG_NOT_MEDIUM 0x00000200
-#define SPAWNFLAG_NOT_HARD 0x00000400
-#define SPAWNFLAG_NOT_DEATHMATCH 0x00000800
-#define SPAWNFLAG_NOT_COOP 0x00001000
-
-// edict->flags
-#define FL_FLY 0x00000001
-#define FL_SWIM 0x00000002 // implied immunity to drowining
-#define FL_IMMUNE_LASER 0x00000004
-#define FL_INWATER 0x00000008
-#define FL_GODMODE 0x00000010
-#define FL_NOTARGET 0x00000020
-#define FL_IMMUNE_SLIME 0x00000040
-#define FL_IMMUNE_LAVA 0x00000080
-#define FL_PARTIALGROUND 0x00000100 // not all corners are valid
-#define FL_WATERJUMP 0x00000200 // player jumping out of water
-#define FL_TEAMSLAVE 0x00000400 // not the first on the team
-#define FL_NO_KNOCKBACK 0x00000800
-#define FL_POWER_ARMOR 0x00001000 // power armor (if any) is active
-#define FL_RESPAWN 0x80000000 // used for item respawning
-
-
-#define FRAMETIME 0.1
-
-// memory tags to allow dynamic memory to be cleaned up
-#define TAG_GAME 765 // clear when unloading the dll
-#define TAG_LEVEL 766 // clear when loading a new level
-
-
-#define MELEE_DISTANCE 80
-
-#define BODY_QUEUE_SIZE 8
-
-typedef enum
-{
- DAMAGE_NO,
- DAMAGE_YES, // will take damage if hit
- DAMAGE_AIM // auto targeting recognizes this
-} damage_t;
-
-typedef enum
-{
- WEAPON_READY,
- WEAPON_ACTIVATING,
- WEAPON_DROPPING,
- WEAPON_FIRING
-} weaponstate_t;
-
-typedef enum
-{
- AMMO_BULLETS,
- AMMO_SHELLS,
- AMMO_ROCKETS,
- AMMO_GRENADES,
- AMMO_CELLS,
- AMMO_SLUGS
-} ammo_t;
-
-
-//deadflag
-#define DEAD_NO 0
-#define DEAD_DYING 1
-#define DEAD_DEAD 2
-#define DEAD_RESPAWNABLE 3
-
-//range
-#define RANGE_MELEE 0
-#define RANGE_NEAR 1
-#define RANGE_MID 2
-#define RANGE_FAR 3
-
-//gib types
-#define GIB_ORGANIC 0
-#define GIB_METALLIC 1
-
-//monster ai flags
-#define AI_STAND_GROUND 0x00000001
-#define AI_TEMP_STAND_GROUND 0x00000002
-#define AI_SOUND_TARGET 0x00000004
-#define AI_LOST_SIGHT 0x00000008
-#define AI_PURSUIT_LAST_SEEN 0x00000010
-#define AI_PURSUE_NEXT 0x00000020
-#define AI_PURSUE_TEMP 0x00000040
-#define AI_HOLD_FRAME 0x00000080
-#define AI_GOOD_GUY 0x00000100
-#define AI_BRUTAL 0x00000200
-#define AI_NOSTEP 0x00000400
-#define AI_DUCKED 0x00000800
-#define AI_COMBAT_POINT 0x00001000
-#define AI_MEDIC 0x00002000
-#define AI_RESURRECTING 0x00004000
-
-//monster attack state
-#define AS_STRAIGHT 1
-#define AS_SLIDING 2
-#define AS_MELEE 3
-#define AS_MISSILE 4
-
-// armor types
-#define ARMOR_NONE 0
-#define ARMOR_JACKET 1
-#define ARMOR_COMBAT 2
-#define ARMOR_BODY 3
-#define ARMOR_SHARD 4
-
-// power armor types
-#define POWER_ARMOR_NONE 0
-#define POWER_ARMOR_SCREEN 1
-#define POWER_ARMOR_SHIELD 2
-
-// handedness values
-#define RIGHT_HANDED 0
-#define LEFT_HANDED 1
-#define CENTER_HANDED 2
-
-
-// game.serverflags values
-#define SFL_CROSS_TRIGGER_1 0x00000001
-#define SFL_CROSS_TRIGGER_2 0x00000002
-#define SFL_CROSS_TRIGGER_3 0x00000004
-#define SFL_CROSS_TRIGGER_4 0x00000008
-#define SFL_CROSS_TRIGGER_5 0x00000010
-#define SFL_CROSS_TRIGGER_6 0x00000020
-#define SFL_CROSS_TRIGGER_7 0x00000040
-#define SFL_CROSS_TRIGGER_8 0x00000080
-#define SFL_CROSS_TRIGGER_MASK 0x000000ff
-
-
-// noise types for PlayerNoise
-#define PNOISE_SELF 0
-#define PNOISE_WEAPON 1
-#define PNOISE_IMPACT 2
-
-
-// edict->movetype values
-typedef enum
-{
-MOVETYPE_NONE, // never moves
-MOVETYPE_NOCLIP, // origin and angles change with no interaction
-MOVETYPE_PUSH, // no clip to world, push on box contact
-MOVETYPE_STOP, // no clip to world, stops on box contact
-
-MOVETYPE_WALK, // gravity
-MOVETYPE_STEP, // gravity, special edge handling
-MOVETYPE_FLY,
-MOVETYPE_TOSS, // gravity
-MOVETYPE_FLYMISSILE, // extra size to monsters
-MOVETYPE_BOUNCE
-} movetype_t;
-
-
-
-typedef struct
-{
- int base_count;
- int max_count;
- float normal_protection;
- float energy_protection;
- int armor;
-} gitem_armor_t;
-
-
-// gitem_t->flags
-#define IT_WEAPON 1 // use makes active weapon
-#define IT_AMMO 2
-#define IT_ARMOR 4
-#define IT_STAY_COOP 8
-#define IT_KEY 16
-#define IT_POWERUP 32
-
-// gitem_t->weapmodel for weapons indicates model index
-#define WEAP_BLASTER 1
-#define WEAP_SHOTGUN 2
-#define WEAP_SUPERSHOTGUN 3
-#define WEAP_MACHINEGUN 4
-#define WEAP_CHAINGUN 5
-#define WEAP_GRENADES 6
-#define WEAP_GRENADELAUNCHER 7
-#define WEAP_ROCKETLAUNCHER 8
-#define WEAP_HYPERBLASTER 9
-#define WEAP_RAILGUN 10
-#define WEAP_BFG 11
-
-typedef struct gitem_s
-{
- char *classname; // spawning name
- qboolean (*pickup)(edict_t *ent, edict_t *other);
- void (*use)(edict_t *ent, struct gitem_s *item);
- void (*drop)(edict_t *ent, struct gitem_s *item);
- void (*weaponthink)(edict_t *ent);
- char *pickup_sound;
- char *world_model;
- int world_model_flags;
- char *view_model;
-
- // client side info
- char *icon;
- char *pickup_name; // for printing on pickup
- int count_width; // number of digits to display by icon
-
- int quantity; // for ammo how much, for weapons how much is used per shot
- char *ammo; // for weapons
- int flags; // IT_* flags
-
- int weapmodel; // weapon model index (for weapons)
-
- void *info;
- int tag;
-
- char *precaches; // string of all models, sounds, and images this item will use
-} gitem_t;
-
-
-
-//
-// this structure is left intact through an entire game
-// it should be initialized at dll load time, and read/written to
-// the server.ssv file for savegames
-//
-typedef struct
-{
- char helpmessage1[512];
- char helpmessage2[512];
- int helpchanged; // flash F1 icon if non 0, play sound
- // and increment only if 1, 2, or 3
-
- gclient_t *clients; // [maxclients]
-
- // can't store spawnpoint in level, because
- // it would get overwritten by the savegame restore
- char spawnpoint[512]; // needed for coop respawns
-
- // store latched cvars here that we want to get at often
- int maxclients;
- int maxentities;
-
- // cross level triggers
- int serverflags;
-
- // items
- int num_items;
-
- qboolean autosaved;
-} game_locals_t;
-
-
-//
-// this structure is cleared as each map is entered
-// it is read/written to the level.sav file for savegames
-//
-typedef struct
-{
- int framenum;
- float time;
-
- char level_name[MAX_QPATH]; // the descriptive name (Outer Base, etc)
- char mapname[MAX_QPATH]; // the server name (base1, etc)
- char nextmap[MAX_QPATH]; // go here when fraglimit is hit
-
- // intermission state
- float intermissiontime; // time the intermission was started
- char *changemap;
- int exitintermission;
- vec3_t intermission_origin;
- vec3_t intermission_angle;
-
- edict_t *sight_client; // changed once each frame for coop games
-
- edict_t *sight_entity;
- int sight_entity_framenum;
- edict_t *sound_entity;
- int sound_entity_framenum;
- edict_t *sound2_entity;
- int sound2_entity_framenum;
-
- int pic_health;
-
- int total_secrets;
- int found_secrets;
-
- int total_goals;
- int found_goals;
-
- int total_monsters;
- int killed_monsters;
-
- edict_t *current_entity; // entity running from G_RunFrame
- int body_que; // dead bodies
-
- int power_cubes; // ugly necessity for coop
-} level_locals_t;
-
-
-// spawn_temp_t is only used to hold entity field values that
-// can be set from the editor, but aren't actualy present
-// in edict_t during gameplay
-typedef struct
-{
- // world vars
- char *sky;
- float skyrotate;
- vec3_t skyaxis;
- char *nextmap;
-
- int lip;
- int distance;
- int height;
- char *noise;
- float pausetime;
- char *item;
- char *gravity;
-
- float minyaw;
- float maxyaw;
- float minpitch;
- float maxpitch;
-} spawn_temp_t;
-
-
-typedef struct
-{
- // fixed data
- vec3_t start_origin;
- vec3_t start_angles;
- vec3_t end_origin;
- vec3_t end_angles;
-
- int sound_start;
- int sound_middle;
- int sound_end;
-
- float accel;
- float speed;
- float decel;
- float distance;
-
- float wait;
-
- // state data
- int state;
- vec3_t dir;
- float current_speed;
- float move_speed;
- float next_speed;
- float remaining_distance;
- float decel_distance;
- void (*endfunc)(edict_t *);
-} moveinfo_t;
-
-
-typedef struct
-{
- void (*aifunc)(edict_t *self, float dist);
- float dist;
- void (*thinkfunc)(edict_t *self);
-} mframe_t;
-
-typedef struct
-{
- int firstframe;
- int lastframe;
- mframe_t *frame;
- void (*endfunc)(edict_t *self);
-} mmove_t;
-
-typedef struct
-{
- mmove_t *currentmove;
- int aiflags;
- int nextframe;
- float scale;
-
- void (*stand)(edict_t *self);
- void (*idle)(edict_t *self);
- void (*search)(edict_t *self);
- void (*walk)(edict_t *self);
- void (*run)(edict_t *self);
- void (*dodge)(edict_t *self, edict_t *other, float eta);
- void (*attack)(edict_t *self);
- void (*melee)(edict_t *self);
- void (*sight)(edict_t *self, edict_t *other);
- qboolean (*checkattack)(edict_t *self);
-
- float pausetime;
- float attack_finished;
-
- vec3_t saved_goal;
- float search_time;
- float trail_time;
- vec3_t last_sighting;
- int attack_state;
- int lefty;
- float idle_time;
- int linkcount;
-
- int power_armor_type;
- int power_armor_power;
-} monsterinfo_t;
-
-
-
-extern game_locals_t game;
-extern level_locals_t level;
-extern game_import_t gi;
-extern game_export_t globals;
-extern spawn_temp_t st;
-
-extern int sm_meat_index;
-extern int snd_fry;
-
-
-// means of death
-#define MOD_UNKNOWN 0
-#define MOD_BLASTER 1
-#define MOD_SHOTGUN 2
-#define MOD_SSHOTGUN 3
-#define MOD_MACHINEGUN 4
-#define MOD_CHAINGUN 5
-#define MOD_GRENADE 6
-#define MOD_G_SPLASH 7
-#define MOD_ROCKET 8
-#define MOD_R_SPLASH 9
-#define MOD_HYPERBLASTER 10
-#define MOD_RAILGUN 11
-#define MOD_BFG_LASER 12
-#define MOD_BFG_BLAST 13
-#define MOD_BFG_EFFECT 14
-#define MOD_HANDGRENADE 15
-#define MOD_HG_SPLASH 16
-#define MOD_WATER 17
-#define MOD_SLIME 18
-#define MOD_LAVA 19
-#define MOD_CRUSH 20
-#define MOD_TELEFRAG 21
-#define MOD_FALLING 22
-#define MOD_SUICIDE 23
-#define MOD_HELD_GRENADE 24
-#define MOD_EXPLOSIVE 25
-#define MOD_BARREL 26
-#define MOD_BOMB 27
-#define MOD_EXIT 28
-#define MOD_SPLASH 29
-#define MOD_TARGET_LASER 30
-#define MOD_TRIGGER_HURT 31
-#define MOD_HIT 32
-#define MOD_TARGET_BLASTER 33
-#define MOD_FRIENDLY_FIRE 0x8000000
-
-extern int meansOfDeath;
-
-
-extern edict_t *g_edicts;
-
-#define FOFS(x) (uintptr)&(((edict_t *)0)->x)
-#define STOFS(x) (uintptr)&(((spawn_temp_t *)0)->x)
-#define LLOFS(x) (uintptr)&(((level_locals_t *)0)->x)
-#define CLOFS(x) (uintptr)&(((gclient_t *)0)->x)
-
-#define qrandom() ((rand () & 0x7fff) / ((float)0x7fff)) /* >_< arrrrggghh */
-#define crandom() (2.0 * (qrandom() - 0.5))
-
-extern cvar_t *maxentities;
-extern cvar_t *deathmatch;
-extern cvar_t *coop;
-extern cvar_t *dmflags;
-extern cvar_t *skill;
-extern cvar_t *fraglimit;
-extern cvar_t *timelimit;
-extern cvar_t *password;
-extern cvar_t *spectator_password;
-extern cvar_t *g_select_empty;
-extern cvar_t *dedicated;
-
-extern cvar_t *filterban;
-
-extern cvar_t *sv_gravity;
-extern cvar_t *sv_maxvelocity;
-
-extern cvar_t *gun_x, *gun_y, *gun_z;
-extern cvar_t *sv_rollspeed;
-extern cvar_t *sv_rollangle;
-
-extern cvar_t *run_pitch;
-extern cvar_t *run_roll;
-extern cvar_t *bob_up;
-extern cvar_t *bob_pitch;
-extern cvar_t *bob_roll;
-
-extern cvar_t *sv_cheats;
-extern cvar_t *maxclients;
-extern cvar_t *maxspectators;
-
-extern cvar_t *flood_msgs;
-extern cvar_t *flood_persecond;
-extern cvar_t *flood_waitdelay;
-
-extern cvar_t *sv_maplist;
-
-#define WORLD (&g_edicts[0])
-
-// item spawnflags
-#define ITEM_TRIGGER_SPAWN 0x00000001
-#define ITEM_NO_TOUCH 0x00000002
-// 6 bits reserved for editor flags
-// 8 bits used as power cube id bits for coop games
-#define DROPPED_ITEM 0x00010000
-#define DROPPED_PLAYER_ITEM 0x00020000
-#define ITEM_TARGETS_USED 0x00040000
-
-//
-// fields are needed for spawning from the entity string
-// and saving / loading games
-//
-#define FFL_SPAWNTEMP 1
-#define FFL_NOSPAWN 2
-
-typedef enum {
- F_INT,
- F_FLOAT,
- F_LSTRING, // string on disk, pointer in memory, TAG_LEVEL
- F_GSTRING, // string on disk, pointer in memory, TAG_GAME
- F_VECTOR,
- F_ANGLEHACK,
- F_EDICT, // index on disk, pointer in memory
- F_ITEM, // index on disk, pointer in memory
- F_CLIENT, // index on disk, pointer in memory
- F_FUNCTION,
- F_MMOVE,
- F_IGNORE
-} fieldtype_t;
-
-typedef struct
-{
- char *name;
- int ofs;
- fieldtype_t type;
- int flags;
-} field_t;
-
-
-extern field_t fields[];
-extern gitem_t itemlist[];
-
-
-//
-// g_cmds.c
-//
-void Cmd_Help_f (edict_t *ent);
-void Cmd_Score_f (edict_t *ent);
-
-//
-// g_items.c
-//
-void PrecacheItem (gitem_t *it);
-void InitItems (void);
-void SetItemNames (void);
-gitem_t *FindItem (char *pickup_name);
-gitem_t *FindItemByClassname (char *classname);
-#define ITEM_INDEX(x) ((x)-itemlist)
-edict_t *Drop_Item (edict_t *ent, gitem_t *item);
-void SetRespawn (edict_t *ent, float delay);
-void ChangeWeapon (edict_t *ent);
-void SpawnItem (edict_t *ent, gitem_t *item);
-void Think_Weapon (edict_t *ent);
-int ArmorIndex (edict_t *ent);
-int PowerArmorType (edict_t *ent);
-gitem_t *GetItemByIndex (int index);
-qboolean Add_Ammo (edict_t *ent, gitem_t *item, int count);
-void Touch_Item (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf);
-
-//
-// g_utils.c
-//
-qboolean KillBox (edict_t *ent);
-void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result);
-edict_t *G_Find (edict_t *from, int fieldofs, char *match);
-edict_t *findradius (edict_t *from, vec3_t org, float rad);
-edict_t *G_PickTarget (char *targetname);
-void G_UseTargets (edict_t *ent, edict_t *activator);
-void G_SetMovedir (vec3_t angles, vec3_t movedir);
-
-void G_InitEdict (edict_t *e);
-edict_t *G_Spawn (void);
-void G_FreeEdict (edict_t *e);
-
-void G_TouchTriggers (edict_t *ent);
-void G_TouchSolids (edict_t *ent);
-
-char *G_CopyString (char *in);
-
-float *tv (float x, float y, float z);
-char *vtos (vec3_t v);
-
-float vectoyaw (vec3_t vec);
-void vectoangles (vec3_t vec, vec3_t angles);
-
-//
-// g_combat.c
-//
-qboolean OnSameTeam (edict_t *ent1, edict_t *ent2);
-qboolean CanDamage (edict_t *targ, edict_t *inflictor);
-void T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod);
-void T_RadiusDamage (edict_t *inflictor, edict_t *attacker, float damage, edict_t *ignore, float radius, int mod);
-
-// damage flags
-#define DAMAGE_RADIUS 0x00000001 // damage was indirect
-#define DAMAGE_NO_ARMOR 0x00000002 // armour does not protect from this damage
-#define DAMAGE_ENERGY 0x00000004 // damage is from an energy based weapon
-#define DAMAGE_NO_KNOCKBACK 0x00000008 // do not affect velocity, just view angles
-#define DAMAGE_BULLET 0x00000010 // damage is from a bullet (used for ricochets)
-#define DAMAGE_NO_PROTECTION 0x00000020 // armor, shields, invulnerability, and godmode have no effect
-
-#define DEFAULT_BULLET_HSPREAD 300
-#define DEFAULT_BULLET_VSPREAD 500
-#define DEFAULT_SHOTGUN_HSPREAD 1000
-#define DEFAULT_SHOTGUN_VSPREAD 500
-#define DEFAULT_DEATHMATCH_SHOTGUN_COUNT 12
-#define DEFAULT_SHOTGUN_COUNT 12
-#define DEFAULT_SSHOTGUN_COUNT 20
-
-//
-// g_monster.c
-//
-void monster_fire_bullet (edict_t *self, vec3_t start, vec3_t dir, int damage, int kick, int hspread, int vspread, int flashtype);
-void monster_fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int flashtype);
-void monster_fire_blaster (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype, int effect);
-void monster_fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int flashtype);
-void monster_fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, int flashtype);
-void monster_fire_railgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int flashtype);
-void monster_fire_bfg (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int kick, float damage_radius, int flashtype);
-void M_droptofloor (edict_t *ent);
-void monster_think (edict_t *self);
-void walkmonster_start (edict_t *self);
-void swimmonster_start (edict_t *self);
-void flymonster_start (edict_t *self);
-void AttackFinished (edict_t *self, float time);
-void monster_death_use (edict_t *self);
-void M_CatagorizePosition (edict_t *ent);
-qboolean M_CheckAttack (edict_t *self);
-void M_FlyCheck (edict_t *self);
-void M_CheckGround (edict_t *ent);
-
-//
-// g_misc.c
-//
-void ThrowHead (edict_t *self, char *gibname, int damage, int type);
-void ThrowClientHead (edict_t *self, int damage);
-void ThrowGib (edict_t *self, char *gibname, int damage, int type);
-void BecomeExplosion1(edict_t *self);
-
-//
-// g_ai.c
-//
-void AI_SetSightClient (void);
-
-void ai_stand (edict_t *self, float dist);
-void ai_move (edict_t *self, float dist);
-void ai_walk (edict_t *self, float dist);
-void ai_turn (edict_t *self, float dist);
-void ai_run (edict_t *self, float dist);
-void ai_charge (edict_t *self, float dist);
-int range (edict_t *self, edict_t *other);
-
-void FoundTarget (edict_t *self);
-qboolean infront (edict_t *self, edict_t *other);
-qboolean visible (edict_t *self, edict_t *other);
-qboolean FacingIdeal(edict_t *self);
-
-//
-// g_weapon.c
-//
-void ThrowDebris (edict_t *self, char *modelname, float speed, vec3_t origin);
-qboolean fire_hit (edict_t *self, vec3_t aim, int damage, int kick);
-void fire_bullet (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int mod);
-void fire_shotgun (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int hspread, int vspread, int count, int mod);
-void fire_blaster (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, int effect, qboolean hyper);
-void fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius);
-void fire_grenade2 (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius, qboolean held);
-void fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage);
-void fire_rail (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick);
-void fire_bfg (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius);
-
-//
-// g_ptrail.c
-//
-void PlayerTrail_Init (void);
-void PlayerTrail_Add (vec3_t spot);
-void PlayerTrail_New (vec3_t spot);
-edict_t *PlayerTrail_PickFirst (edict_t *self);
-edict_t *PlayerTrail_PickNext (edict_t *self);
-edict_t *PlayerTrail_LastSpot (void);
-
-//
-// g_client.c
-//
-void respawn (edict_t *ent);
-void BeginIntermission (edict_t *targ);
-void PutClientInServer (edict_t *ent);
-void InitClientPersistant (gclient_t *client);
-void InitClientResp (gclient_t *client);
-void InitBodyQue (void);
-void ClientBeginServerFrame (edict_t *ent);
-
-//
-// g_player.c
-//
-void player_pain (edict_t *self, edict_t *other, float kick, int damage);
-void player_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
-
-//
-// g_svcmds.c
-//
-void ServerCommand (void);
-qboolean SV_FilterPacket (char *from);
-
-//
-// p_view.c
-//
-void ClientEndServerFrame (edict_t *ent);
-
-//
-// p_hud.c
-//
-void MoveClientToIntermission (edict_t *client);
-void G_SetStats (edict_t *ent);
-void G_SetSpectatorStats (edict_t *ent);
-void G_CheckChaseStats (edict_t *ent);
-void ValidateSelectedItem (edict_t *ent);
-void DeathmatchScoreboardMessage (edict_t *client, edict_t *killer);
-
-//
-// g_pweapon.c
-//
-void PlayerNoise(edict_t *who, vec3_t where, int type);
-
-//
-// m_move.c
-//
-qboolean M_CheckBottom (edict_t *ent);
-qboolean M_walkmove (edict_t *ent, float yaw, float dist);
-void M_MoveToGoal (edict_t *ent, float dist);
-void M_ChangeYaw (edict_t *ent);
-
-//
-// g_phys.c
-//
-void G_RunEntity (edict_t *ent);
-
-//
-// g_main.c
-//
-void SaveClientData (void);
-void FetchClientEntData (edict_t *ent);
-
-//
-// g_chase.c
-//
-void UpdateChaseCam(edict_t *ent);
-void ChaseNext(edict_t *ent);
-void ChasePrev(edict_t *ent);
-void GetChaseTarget(edict_t *ent);
-
-//============================================================================
-
-// client_t->anim_priority
-#define ANIM_BASIC 0 // stand / run
-#define ANIM_WAVE 1
-#define ANIM_JUMP 2
-#define ANIM_PAIN 3
-#define ANIM_ATTACK 4
-#define ANIM_DEATH 5
-#define ANIM_REVERSE 6
-
-
-// client data that stays across multiple level loads
-typedef struct
-{
- char userinfo[MAX_INFO_STRING];
- char netname[16];
- int hand;
-
- qboolean connected; // a loadgame will leave valid entities that
- // just don't have a connection yet
-
- // values saved and restored from edicts when changing levels
- int health;
- int max_health;
- int savedFlags;
-
- int selected_item;
- int inventory[MAX_ITEMS];
-
- // ammo capacities
- int max_bullets;
- int max_shells;
- int max_rockets;
- int max_grenades;
- int max_cells;
- int max_slugs;
-
- gitem_t *weapon;
- gitem_t *lastweapon;
-
- int power_cubes; // used for tracking the cubes in coop games
- int score; // for calculating total unit score in coop games
-
- int game_helpchanged;
- int helpchanged;
-
- qboolean spectator; // client is a spectator
-} client_persistant_t;
-
-// client data that stays across deathmatch respawns
-typedef struct
-{
- client_persistant_t coop_respawn; // what to set client->pers to on a respawn
- int enterframe; // level.framenum the client entered the game
- int score; // frags, etc
- vec3_t cmd_angles; // angles sent over in the last command
-
- qboolean spectator; // client is a spectator
-} client_respawn_t;
-
-// this structure is cleared on each PutClientInServer(),
-// except for 'client->pers'
-struct gclient_t
-{
- // known to server
- player_state_t ps; // communicated by server to clients
- int ping;
-
-// the server expects the first part
-// of gclient_s to be a player_state_t
-// but the rest of it is opaque
-
- // DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER
- // EXPECTS THE FIELDS IN THAT ORDER!
- //================================
-
- client_persistant_t pers;
- client_respawn_t resp;
- pmove_state_t old_pmove; // for detecting out-of-pmove changes
-
- qboolean showscores; // set layout stat
- qboolean showinventory; // set layout stat
- qboolean showhelp;
- qboolean showhelpicon;
-
- int ammo_index;
-
- int buttons;
- int oldbuttons;
- int latched_buttons;
-
- qboolean weapon_thunk;
-
- gitem_t *newweapon;
-
- // sum up damage over an entire frame, so
- // shotgun blasts give a single big kick
- int damage_armor; // damage absorbed by armor
- int damage_parmor; // damage absorbed by power armor
- int damage_blood; // damage taken out of health
- int damage_knockback; // impact damage
- vec3_t damage_from; // origin for vector calculation
-
- float killer_yaw; // when dead, look at killer
-
- weaponstate_t weaponstate;
- vec3_t kick_angles; // weapon kicks
- vec3_t kick_origin;
- float v_dmg_roll, v_dmg_pitch, v_dmg_time; // damage kicks
- float fall_time, fall_value; // for view drop on fall
- float damage_alpha;
- float bonus_alpha;
- vec3_t damage_blend;
- vec3_t v_angle; // aiming direction
- float bobtime; // so off-ground doesn't change it
- vec3_t oldviewangles;
- vec3_t oldvelocity;
-
- float next_drown_time;
- int old_waterlevel;
- int breather_sound;
-
- int machinegun_shots; // for weapon raising
-
- // animation vars
- int anim_end;
- int anim_priority;
- qboolean anim_duck;
- qboolean anim_run;
-
- // powerup timers
- float quad_framenum;
- float invincible_framenum;
- float breather_framenum;
- float enviro_framenum;
-
- qboolean grenade_blew_up;
- float grenade_time;
- int silencer_shots;
- int weapon_sound;
-
- float pickup_msg_time;
-
- float flood_locktill; // locked from talking
- float flood_when[10]; // when messages were said
- int flood_whenhead; // head pointer for when said
-
- float respawn_time; // can respawn when time > this
-
- edict_t *chase_target; // player we are chasing
- qboolean update_chase; // need to update chase info?
-};
-
-
-struct edict_t
-{
- entity_state_t s;
- gclient_t *client; // NULL if not a player
-
- qboolean inuse;
- int linkcount;
-
- // FIXME: move these fields to a server private sv_entity_t
- link_t area; // linked to a division node or leaf
-
- int num_clusters; // if -1, use headnode instead
- int clusternums[MAX_ENT_CLUSTERS];
- int headnode; // unused if num_clusters != -1
- int areanum, areanum2;
-
- //================================
-
- int svflags; // SCF_NOCLIENT, SVF_DEADMONSTER, SVF_MONSTER, etc.
- vec3_t mins, maxs;
- vec3_t absmin, absmax, size;
- solid_t solid;
- int clipmask;
- edict_t *owner;
-
- // DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER
- // EXPECTS THE FIELDS IN THAT ORDER!
- //================================
-
- int movetype;
- int flags;
-
- char *model;
- float freetime; // sv.time when the object was freed
-
- //
- // only used locally in game, not by server
- //
- char *message;
- char *classname;
- int spawnflags;
-
- float timestamp;
-
- float angle; // set in qe3, -1 = up, -2 = down
- char *target;
- char *targetname;
- char *killtarget;
- char *team;
- char *pathtarget;
- char *deathtarget;
- char *combattarget;
- edict_t *target_ent;
-
- float speed, accel, decel;
- vec3_t movedir;
- vec3_t pos1, pos2;
-
- vec3_t velocity;
- vec3_t avelocity;
- int mass;
- float air_finished;
- float gravity; // per entity gravity multiplier (1.0 is normal)
- // use for lowgrav artifact, flares
-
- edict_t *goalentity;
- edict_t *movetarget;
- float yaw_speed;
- float ideal_yaw;
-
- float nextthink;
- void (*prethink) (edict_t *ent);
- void (*think)(edict_t *self);
- void (*blocked)(edict_t *self, edict_t *other); //move to moveinfo?
- void (*touch)(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf);
- void (*use)(edict_t *self, edict_t *other, edict_t *activator);
- void (*pain)(edict_t *self, edict_t *other, float kick, int damage);
- void (*die)(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
-
- float touch_debounce_time; // are all these legit? do we need more/less of them?
- float pain_debounce_time;
- float damage_debounce_time;
- float fly_sound_debounce_time; //move to clientinfo
- float last_move_time;
-
- int health;
- int max_health;
- int gib_health;
- int deadflag;
- qboolean show_hostile;
-
- float powerarmor_time;
-
- char *map; // target_changelevel
-
- int viewheight; // height above origin where eyesight is determined
- int takedamage;
- int dmg;
- int radius_dmg;
- float dmg_radius;
- int sounds; //make this a spawntemp var?
- int count;
-
- edict_t *chain;
- edict_t *enemy;
- edict_t *oldenemy;
- edict_t *activator;
- edict_t *groundentity;
- int groundentity_linkcount;
- edict_t *teamchain;
- edict_t *teammaster;
-
- edict_t *mynoise; // can go in client only
- edict_t *mynoise2;
-
- int noise_index;
- int noise_index2;
- float volume;
- float attenuation;
-
- // timing variables
- float wait;
- float delay; // before firing targets
- float random;
-
- float teleport_time;
-
- int watertype;
- int waterlevel;
-
- vec3_t move_origin;
- vec3_t move_angles;
-
- // move this to clientinfo?
- int light_level;
-
- int style; // also used as areaportal number
-
- gitem_t *item; // for bonus items
-
- // common data blocks
- moveinfo_t moveinfo;
- monsterinfo_t monsterinfo;
-};
--- a/game/g_main.c
+++ b/game/g_main.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
game_locals_t game;
level_locals_t level;
--- a/game/g_misc.c
+++ b/game/g_misc.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
/*QUAKED func_group (0 0 0) ?
--- a/game/g_monster.c
+++ b/game/g_monster.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
//
--- a/game/g_phys.c
+++ b/game/g_phys.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
/*
--- a/game/g_save.c
+++ b/game/g_save.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#define Function(f) {#f, f}
--- a/game/g_spawn.c
+++ b/game/g_spawn.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
typedef struct
{
--- a/game/g_svcmds.c
+++ b/game/g_svcmds.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
void Svcmd_Test_f (void)
--- a/game/g_target.c
+++ b/game/g_target.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
/*QUAKED target_temp_entity (1 0 0) (-8 -8 -8) (8 8 8)
Fire an origin based temp entity event to the clients.
--- a/game/g_trigger.c
+++ b/game/g_trigger.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
void InitTrigger (edict_t *self)
--- a/game/g_turret.c
+++ b/game/g_turret.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
void AnglesNormalize(vec3_t vec)
--- a/game/g_utils.c
+++ b/game/g_utils.c
@@ -3,7 +3,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
--- a/game/g_weapon.c
+++ b/game/g_weapon.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
/*
--- a/game/game.h
+++ b/game/game.h
@@ -1,173 +1,974 @@
-// game.h -- game dll information visible to server
+typedef struct link_t link_t;
+typedef struct game_import_t game_import_t;
+typedef struct game_export_t game_export_t;
+typedef struct gitem_armor_t gitem_armor_t;
+typedef struct gitem_t gitem_t;
+typedef struct game_locals_t game_locals_t;
+typedef struct level_locals_t level_locals_t;
+typedef struct spawn_temp_t spawn_temp_t;
+typedef struct moveinfo_t moveinfo_t;
+typedef struct mframe_t mframe_t;
+typedef struct mmove_t mmove_t;
+typedef struct monsterinfo_t monsterinfo_t;
+typedef struct field_t field_t;
+typedef struct client_persistant_t client_persistant_t;
+typedef struct client_respawn_t client_respawn_t;
+typedef struct edict_t edict_t;
+typedef struct gclient_t gclient_t;
-#define GAME_API_VERSION 3
+extern cvar_t *maxentities;
+extern cvar_t *deathmatch;
+extern cvar_t *coop;
+extern cvar_t *dmflags;
+extern cvar_t *skill;
+extern cvar_t *fraglimit;
+extern cvar_t *timelimit;
+extern cvar_t *password;
+extern cvar_t *spectator_password;
+extern cvar_t *g_select_empty;
+extern cvar_t *dedicated;
+extern cvar_t *filterban;
+extern cvar_t *sv_gravity;
+extern cvar_t *sv_maxvelocity;
+extern cvar_t *gun_x, *gun_y, *gun_z;
+extern cvar_t *sv_rollspeed;
+extern cvar_t *sv_rollangle;
+extern cvar_t *run_pitch;
+extern cvar_t *run_roll;
+extern cvar_t *bob_up;
+extern cvar_t *bob_pitch;
+extern cvar_t *bob_roll;
+extern cvar_t *sv_cheats;
+extern cvar_t *maxclients;
+extern cvar_t *maxspectators;
+extern cvar_t *flood_msgs;
+extern cvar_t *flood_persecond;
+extern cvar_t *flood_waitdelay;
+extern cvar_t *sv_maplist;
-// edict->svflags
+enum{
+ GAME_API_VERSION = 3,
-#define SVF_NOCLIENT 0x00000001 // don't send entity to clients, even if it has effects
-#define SVF_DEADMONSTER 0x00000002 // treat as CONTENTS_DEADMONSTER for collision
-#define SVF_MONSTER 0x00000004 // treat as CONTENTS_MONSTER for collision
+ /* edict->svflags */
+ SVF_NOCLIENT = 1<<0, // don't send entity to clients, even if it has effects
+ SVF_DEADMONSTER = 1<<1, // treat as CONTENTS_DEADMONSTER for collision
+ SVF_MONSTER = 1<<2, // treat as CONTENTS_MONSTER for collision
-// edict->solid values
+ MAX_ENT_CLUSTERS = 16
+};
-typedef enum
-{
-SOLID_NOT, // no interaction with other objects
-SOLID_TRIGGER, // only touch when inside, after moving
-SOLID_BBOX, // touch on edge
-SOLID_BSP // bsp clip, touch on edge
-} solid_t;
+/* edict->solid values */
+typedef enum solid_t{
+ SOLID_NOT, // no interaction with other objects
+ SOLID_TRIGGER, // only touch when inside, after moving
+ SOLID_BBOX, // touch on edge
+ SOLID_BSP // bsp clip, touch on edge
+}solid_t;
+
+/* link_t is only used for entity area links now */
+struct link_t{
+ link_t *prev;
+ link_t *next;
+};
+
+struct game_import_t{
+ void (*bprintf)(int, char *, ...);
+ void (*dprintf)(char *, ...);
+ void (*cprintf)(edict_t *, int, char *, ...);
+ void (*centerprintf)(edict_t *, char *, ...);
+ void (*sound)(edict_t *, int, int, float, float, float);
+ void (*positioned_sound)(vec3_t, edict_t *, int, int, float, float, float);
+ /* config strings hold all the index strings, the lightstyles, and misc
+ * data like the sky definition and cdtrack. all of the current
+ * configstrings are sent to clients when they connect, and changes are
+ * sent to all connected clients. */
+ void (*configstring)(int, char *);
+ void (*error)(char *, ...);
+ /* the *index functions create configstrings and some internal server
+ * state */
+ int (*modelindex)(char *);
+ int (*soundindex)(char *);
+ int (*imageindex)(char *);
+ void (*setmodel)(edict_t *, char *);
+ /* collision detection */
+ trace_t (*trace)(vec3_t, vec3_t, vec3_t, vec3_t, edict_t *, int);
+ int (*pointcontents)(vec3_t);
+ qboolean (*inPVS)(vec3_t, vec3_t);
+ qboolean (*inPHS)(vec3_t, vec3_t);
+ void (*SetAreaPortalState)(int, qboolean);
+ qboolean (*AreasConnected)(int, int);
+ /* an entity will never be sent to a client or used for collision if it
+ * is not passed to linkentity. If the size, position, or solidity
+ * changes, it must be relinked. */
+ void (*linkentity)(edict_t *);
+ /* call before removing an interactive edict */
+ void (*unlinkentity)(edict_t *);
+ int (*BoxEdicts)(vec3_t, vec3_t, edict_t **, int, int);
+ /* player movement code common with client prediction */
+ void (*Pmove)(pmove_t *);
+ /* network messaging */
+ void (*multicast)(vec3_t, multicast_t);
+ void (*unicast)(edict_t *, qboolean);
+ void (*WriteChar)(int);
+ void (*WriteByte)(int);
+ void (*WriteShort)(int);
+ void (*WriteLong)(int);
+ void (*WriteFloat)(float);
+ void (*WriteString)(char *);
+ void (*WritePosition)(vec3_t); // some fractional bits
+ void (*WriteDir)(vec3_t); // single byte encoded, very coarse
+ void (*WriteAngle)(float);
+ /* managed memory allocation */
+ void* (*TagMalloc)(int, int);
+ void (*TagFree)(void *);
+ void (*FreeTags)(int);
+ /* console variable interaction */
+ cvar_t* (*cvar)(char *, char *, int);
+ cvar_t* (*cvar_set)(char *, char *);
+ cvar_t* (*cvar_forceset)(char *, char *);
+ /* ClientCommand and ServerCommand parameter access */
+ int (*argc)(void);
+ char* (*argv)(int);
+ char* (*args)(void); // concatenation of all argv >= 1
+ /* add commands to the server console as if they were typed in for map
+ * changing, etc */
+ void (*AddCommandString)(char *);
+ void (*DebugGraph)(float, int);
+};
+extern game_import_t gi;
+
+struct game_export_t{
+ int apiversion;
+ /* the init function will only be called when a game starts, not each
+ * time a level is loaded. Persistant data for clients and the server
+ * can be allocated in init */
+ void (*Init)(void);
+ void (*Shutdown)(void);
+ /* each new level entered will cause a call to SpawnEntities */
+ void (*SpawnEntities)(char *, char *, char *);
+ /* Read/Write Game is for storing persistant cross level information
+ * about the world state and the clients. WriteGame is called every
+ * time a level is exited. ReadGame is called on a loadgame. */
+ void (*WriteGame)(char *, qboolean);
+ void (*ReadGame)(char *);
+ /* ReadLevel is called after the default map information has been
+ * loaded with SpawnEntities */
+ void (*WriteLevel)(char *);
+ void (*ReadLevel)(char *);
+ qboolean (*ClientConnect)(edict_t *, char *);
+ void (*ClientBegin)(edict_t *);
+ void (*ClientUserinfoChanged)(edict_t *, char *);
+ void (*ClientDisconnect)(edict_t *);
+ void (*ClientCommand)(edict_t *);
+ void (*ClientThink)(edict_t *, usercmd_t *);
+ void (*RunFrame)(void);
+ /* ServerCommand will be called when an "sv <command>" command is
+ * issued on the server console. the game can issue gi.argc() or
+ * gi.argv() commands to get the rest of the parameters */
+ void (*ServerCommand)(void);
+ /* global variables shared between game and server: the edict array is
+ * allocated in the game dll so it can vary in size from one game to
+ * another. the size will be fixed when ge->Init() is called */
+ edict_t *edicts;
+ int edict_size;
+ int num_edicts; // current number, <= max_edicts
+ int max_edicts;
+};
+extern game_export_t globals;
-//===============================================================
+game_export_t *GetGameAPI(game_import_t *);
-// link_t is only used for entity area links now
-typedef struct link_s
-{
- struct link_s *prev, *next;
-} link_t;
+#define GAMEVERSION "baseq2"
+#define DAMAGE_TIME 0.5 // view pitching times
+#define FALL_TIME 0.3
+#define FRAMETIME 0.1
+enum{
+ /* edict->spawnflags */
+ SPAWNFLAG_NOT_EASY = 1<<8,
+ SPAWNFLAG_NOT_MEDIUM = 1<<9,
+ SPAWNFLAG_NOT_HARD = 1<<10,
+ SPAWNFLAG_NOT_DEATHMATCH = 1<<11,
+ SPAWNFLAG_NOT_COOP = 1<<12,
+ /* edict->flags */
+ FL_FLY = 1<<0,
+ FL_SWIM = 1<<1, // implied immunity to drowining
+ FL_IMMUNE_LASER = 1<<2,
+ FL_INWATER = 1<<3,
+ FL_GODMODE = 1<<4,
+ FL_NOTARGET = 1<<5,
+ FL_IMMUNE_SLIME = 1<<6,
+ FL_IMMUNE_LAVA = 1<<7,
+ FL_PARTIALGROUND = 1<<8, // not all corners are valid
+ FL_WATERJUMP = 1<<9, // player jumping out of water
+ FL_TEAMSLAVE = 1<<10, // not the first on the team
+ FL_NO_KNOCKBACK = 1<<11,
+ FL_POWER_ARMOR = 1<<12, // power armor (if any) is active
+ FL_RESPAWN = 1<<31, // used for item respawning
-#define MAX_ENT_CLUSTERS 16
+ /* memory tags to allow dynamic memory to be cleaned up */
+ TAG_GAME = 765, // clear when unloading the dll
+ TAG_LEVEL = 766, // clear when loading a new level
+ MELEE_DISTANCE = 80,
+ BODY_QUEUE_SIZE = 8,
-typedef struct edict_t edict_t;
-typedef struct gclient_t gclient_t;
+ /* deadflag */
+ DEAD_NO = 0,
+ DEAD_DYING = 1,
+ DEAD_DEAD = 2,
+ DEAD_RESPAWNABLE = 3,
+ /* range */
+ RANGE_MELEE = 0,
+ RANGE_NEAR = 1,
+ RANGE_MID = 2,
+ RANGE_FAR = 3,
+ /* gib types */
+ GIB_ORGANIC = 0,
+ GIB_METALLIC = 1,
+ /* monster ai flags */
+ AI_STAND_GROUND = 1<<0,
+ AI_TEMP_STAND_GROUND = 1<<1,
+ AI_SOUND_TARGET = 1<<2,
+ AI_LOST_SIGHT = 1<<3,
+ AI_PURSUIT_LAST_SEEN = 1<<4,
+ AI_PURSUE_NEXT = 1<<5,
+ AI_PURSUE_TEMP = 1<<6,
+ AI_HOLD_FRAME = 1<<7,
+ AI_GOOD_GUY = 1<<8,
+ AI_BRUTAL = 1<<9,
+ AI_NOSTEP = 1<<10,
+ AI_DUCKED = 1<<11,
+ AI_COMBAT_POINT = 1<<12,
+ AI_MEDIC = 1<<13,
+ AI_RESURRECTING = 1<<14,
+ /* monster attack state */
+ AS_STRAIGHT = 1,
+ AS_SLIDING = 2,
+ AS_MELEE = 3,
+ AS_MISSILE = 4,
+ /* armor types */
+ ARMOR_NONE = 0,
+ ARMOR_JACKET = 1,
+ ARMOR_COMBAT = 2,
+ ARMOR_BODY = 3,
+ ARMOR_SHARD = 4,
+ /* power armor types */
+ POWER_ARMOR_NONE = 0,
+ POWER_ARMOR_SCREEN = 1,
+ POWER_ARMOR_SHIELD = 2,
+ /* handedness values */
+ RIGHT_HANDED = 0,
+ LEFT_HANDED = 1,
+ CENTER_HANDED = 2,
+ /* game.serverflags values */
+ SFL_CROSS_TRIGGER_1 = 1<<0,
+ SFL_CROSS_TRIGGER_2 = 1<<1,
+ SFL_CROSS_TRIGGER_3 = 1<<2,
+ SFL_CROSS_TRIGGER_4 = 1<<3,
+ SFL_CROSS_TRIGGER_5 = 1<<4,
+ SFL_CROSS_TRIGGER_6 = 1<<5,
+ SFL_CROSS_TRIGGER_7 = 1<<6,
+ SFL_CROSS_TRIGGER_8 = 1<<7,
+ SFL_CROSS_TRIGGER_MASK = 0xff,
+ /* noise types for PlayerNoise */
+ PNOISE_SELF = 0,
+ PNOISE_WEAPON = 1,
+ PNOISE_IMPACT = 2,
+};
+typedef enum damage_t{
+ DAMAGE_NO,
+ DAMAGE_YES, // will take damage if hit
+ DAMAGE_AIM // auto targeting recognizes this
+}damage_t;
+typedef enum weaponstate_t{
+ WEAPON_READY,
+ WEAPON_ACTIVATING,
+ WEAPON_DROPPING,
+ WEAPON_FIRING
+}weaponstate_t;
+typedef enum ammo_t{
+ AMMO_BULLETS,
+ AMMO_SHELLS,
+ AMMO_ROCKETS,
+ AMMO_GRENADES,
+ AMMO_CELLS,
+ AMMO_SLUGS
+}ammo_t;
-//===============================================================
+/* edict->movetype values */
+typedef enum movetype_t{
+ MOVETYPE_NONE, // never moves
+ MOVETYPE_NOCLIP, // origin and angles change with no interaction
+ MOVETYPE_PUSH, // no clip to world, push on box contact
+ MOVETYPE_STOP, // no clip to world, stops on box contact
+ MOVETYPE_WALK, // gravity
+ MOVETYPE_STEP, // gravity, special edge handling
+ MOVETYPE_FLY,
+ MOVETYPE_TOSS, // gravity
+ MOVETYPE_FLYMISSILE, // extra size to monsters
+ MOVETYPE_BOUNCE
+}movetype_t;
-//
-// functions provided by the main engine
-//
-typedef struct
-{
- // special messages
- void (*bprintf) (int printlevel, char *fmt, ...);
- void (*dprintf) (char *fmt, ...);
- void (*cprintf) (edict_t *ent, int printlevel, char *fmt, ...);
- void (*centerprintf) (edict_t *ent, char *fmt, ...);
- void (*sound) (edict_t *ent, int channel, int soundindex, float volume, float attenuation, float timeofs);
- void (*positioned_sound) (vec3_t origin, edict_t *ent, int channel, int soundinedex, float volume, float attenuation, float timeofs);
+struct gitem_armor_t{
+ int base_count;
+ int max_count;
+ float normal_protection;
+ float energy_protection;
+ int armor;
+};
- // config strings hold all the index strings, the lightstyles,
- // and misc data like the sky definition and cdtrack.
- // All of the current configstrings are sent to clients when
- // they connect, and changes are sent to all connected clients.
- void (*configstring) (int num, char *string);
+enum{
+ /* gitem_t->flags */
+ IT_WEAPON = 1<<0, // use makes active weapon
+ IT_AMMO = 1<<1,
+ IT_ARMOR = 1<<2,
+ IT_STAY_COOP = 1<<3,
+ IT_KEY = 1<<4,
+ IT_POWERUP = 1<<5,
+ /* gitem_t->weapmodel for weapons indicates model index */
+ WEAP_BLASTER = 1,
+ WEAP_SHOTGUN = 2,
+ WEAP_SUPERSHOTGUN = 3,
+ WEAP_MACHINEGUN = 4,
+ WEAP_CHAINGUN = 5,
+ WEAP_GRENADES = 6,
+ WEAP_GRENADELAUNCHER = 7,
+ WEAP_ROCKETLAUNCHER = 8,
+ WEAP_HYPERBLASTER = 9,
+ WEAP_RAILGUN = 10,
+ WEAP_BFG = 11
+};
+struct gitem_t{
+ char *classname; // spawning name
+ qboolean (*pickup)(edict_t *, edict_t *);
+ void (*use)(edict_t *, gitem_t *);
+ void (*drop)(edict_t *, gitem_t *);
+ void (*weaponthink)(edict_t *);
+ char *pickup_sound;
+ char *world_model;
+ int world_model_flags;
+ char *view_model;
+ /* client side info */
+ char *icon;
+ char *pickup_name; // for printing on pickup
+ int count_width; // number of digits to display by icon
+ int quantity; // for ammo how much, for weapons how much is used per shot
+ char *ammo; // for weapons
+ int flags; // IT_* flags
+ int weapmodel; // weapon model index (for weapons)
+ void *info;
+ int tag;
+ /* string of all models, sounds, and images this item will use */
+ char *precaches;
+};
+extern gitem_t itemlist[];
- void (*error) (char *fmt, ...);
+/* this structure is left intact through an entire game it should be
+ * initialized at dll load time, and read/written to the server.ssv file for
+ * savegames */
+struct game_locals_t{
+ char helpmessage1[512];
+ char helpmessage2[512];
+ /* flash F1 icon if non 0, play sound and increment only if 1, 2, or 3 */
+ int helpchanged;
+ gclient_t *clients; // [maxclients]
+ /* can't store spawnpoint in level, because it would get overwritten
+ * by the savegame restore */
+ char spawnpoint[512]; // needed for coop respawns
+ /* store latched cvars here that we want to get at often */
+ int maxclients;
+ int maxentities;
+ /* cross level triggers */
+ int serverflags;
+ int num_items;
+ qboolean autosaved;
+};
+extern game_locals_t game;
- // the *index functions create configstrings and some internal server state
- int (*modelindex) (char *name);
- int (*soundindex) (char *name);
- int (*imageindex) (char *name);
+/* this structure is cleared as each map is entered; it is read/written to the
+ * level.sav file for savegames */
+struct level_locals_t{
+ int framenum;
+ float time;
+ char level_name[MAX_QPATH]; // the descriptive name (Outer Base, etc)
+ char mapname[MAX_QPATH]; // the server name (base1, etc)
+ char nextmap[MAX_QPATH]; // go here when fraglimit is hit
+ /* intermission state */
+ float intermissiontime; // time the intermission was started
+ char *changemap;
+ int exitintermission;
+ vec3_t intermission_origin;
+ vec3_t intermission_angle;
+ edict_t *sight_client; // changed once each frame for coop games
+ edict_t *sight_entity;
+ int sight_entity_framenum;
+ edict_t *sound_entity;
+ int sound_entity_framenum;
+ edict_t *sound2_entity;
+ int sound2_entity_framenum;
+ int pic_health;
+ int total_secrets;
+ int found_secrets;
+ int total_goals;
+ int found_goals;
+ int total_monsters;
+ int killed_monsters;
+ edict_t *current_entity; // entity running from G_RunFrame
+ int body_que; // dead bodies
+ int power_cubes; // ugly necessity for coop
+};
+extern level_locals_t level;
- void (*setmodel) (edict_t *ent, char *name);
+/* spawn_temp_t is only used to hold entity field values that can be set from
+ * the editor, but aren't actualy present in edict_t during gameplay */
+struct spawn_temp_t{
+ /* world vars */
+ char *sky;
+ float skyrotate;
+ vec3_t skyaxis;
+ char *nextmap;
- // collision detection
- trace_t (*trace) (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passent, int contentmask);
- int (*pointcontents) (vec3_t point);
- qboolean (*inPVS) (vec3_t p1, vec3_t p2);
- qboolean (*inPHS) (vec3_t p1, vec3_t p2);
- void (*SetAreaPortalState) (int portalnum, qboolean open);
- qboolean (*AreasConnected) (int area1, int area2);
+ int lip;
+ int distance;
+ int height;
+ char *noise;
+ float pausetime;
+ char *item;
+ char *gravity;
+ float minyaw;
+ float maxyaw;
+ float minpitch;
+ float maxpitch;
+};
+extern spawn_temp_t st;
- // an entity will never be sent to a client or used for collision
- // if it is not passed to linkentity. If the size, position, or
- // solidity changes, it must be relinked.
- void (*linkentity) (edict_t *ent);
- void (*unlinkentity) (edict_t *ent); // call before removing an interactive edict
- int (*BoxEdicts) (vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int areatype);
- void (*Pmove) (pmove_t *pmove); // player movement code common with client prediction
+struct moveinfo_t{
+ /* fixed data */
+ vec3_t start_origin;
+ vec3_t start_angles;
+ vec3_t end_origin;
+ vec3_t end_angles;
+ int sound_start;
+ int sound_middle;
+ int sound_end;
+ float accel;
+ float speed;
+ float decel;
+ float distance;
+ float wait;
+ /* state data */
+ int state;
+ vec3_t dir;
+ float current_speed;
+ float move_speed;
+ float next_speed;
+ float remaining_distance;
+ float decel_distance;
+ void (*endfunc)(edict_t *);
+};
- // network messaging
- void (*multicast) (vec3_t origin, multicast_t to);
- void (*unicast) (edict_t *ent, qboolean reliable);
- void (*WriteChar) (int c);
- void (*WriteByte) (int c);
- void (*WriteShort) (int c);
- void (*WriteLong) (int c);
- void (*WriteFloat) (float f);
- void (*WriteString) (char *s);
- void (*WritePosition) (vec3_t pos); // some fractional bits
- void (*WriteDir) (vec3_t pos); // single byte encoded, very coarse
- void (*WriteAngle) (float f);
+struct mframe_t{
+ void (*aifunc)(edict_t *, float);
+ float dist;
+ void (*thinkfunc)(edict_t *);
+};
- // managed memory allocation
- void *(*TagMalloc) (int size, int tag);
- void (*TagFree) (void *block);
- void (*FreeTags) (int tag);
+struct mmove_t{
+ int firstframe;
+ int lastframe;
+ mframe_t *frame;
+ void (*endfunc)(edict_t *);
+};
- // console variable interaction
- cvar_t *(*cvar) (char *var_name, char *value, int flags);
- cvar_t *(*cvar_set) (char *var_name, char *value);
- cvar_t *(*cvar_forceset) (char *var_name, char *value);
+struct monsterinfo_t{
+ mmove_t *currentmove;
+ int aiflags;
+ int nextframe;
+ float scale;
+ void (*stand)(edict_t *);
+ void (*idle)(edict_t *);
+ void (*search)(edict_t *);
+ void (*walk)(edict_t *);
+ void (*run)(edict_t *);
+ void (*dodge)(edict_t *, edict_t *, float);
+ void (*attack)(edict_t *);
+ void (*melee)(edict_t *);
+ void (*sight)(edict_t *, edict_t *);
+ qboolean (*checkattack)(edict_t *);
+ float pausetime;
+ float attack_finished;
+ vec3_t saved_goal;
+ float search_time;
+ float trail_time;
+ vec3_t last_sighting;
+ int attack_state;
+ int lefty;
+ float idle_time;
+ int linkcount;
+ int power_armor_type;
+ int power_armor_power;
+};
- // ClientCommand and ServerCommand parameter access
- int (*argc) (void);
- char *(*argv) (int n);
- char *(*args) (void); // concatenation of all argv >= 1
+extern int sm_meat_index;
+extern int snd_fry;
- // add commands to the server console as if they were typed in
- // for map changing, etc
- void (*AddCommandString) (char *text);
+/* means of death */
+enum{
+ MOD_UNKNOWN = 0,
+ MOD_BLASTER = 1,
+ MOD_SHOTGUN = 2,
+ MOD_SSHOTGUN = 3,
+ MOD_MACHINEGUN = 4,
+ MOD_CHAINGUN = 5,
+ MOD_GRENADE = 6,
+ MOD_G_SPLASH = 7,
+ MOD_ROCKET = 8,
+ MOD_R_SPLASH = 9,
+ MOD_HYPERBLASTER = 10,
+ MOD_RAILGUN = 11,
+ MOD_BFG_LASER = 12,
+ MOD_BFG_BLAST = 13,
+ MOD_BFG_EFFECT = 14,
+ MOD_HANDGRENADE = 15,
+ MOD_HG_SPLASH = 16,
+ MOD_WATER = 17,
+ MOD_SLIME = 18,
+ MOD_LAVA = 19,
+ MOD_CRUSH = 20,
+ MOD_TELEFRAG = 21,
+ MOD_FALLING = 22,
+ MOD_SUICIDE = 23,
+ MOD_HELD_GRENADE = 24,
+ MOD_EXPLOSIVE = 25,
+ MOD_BARREL = 26,
+ MOD_BOMB = 27,
+ MOD_EXIT = 28,
+ MOD_SPLASH = 29,
+ MOD_TARGET_LASER = 30,
+ MOD_TRIGGER_HURT = 31,
+ MOD_HIT = 32,
+ MOD_TARGET_BLASTER = 33,
+ MOD_FRIENDLY_FIRE = 1<<31
+};
+extern int meansOfDeath;
- void (*DebugGraph) (float value, int color);
-} game_import_t;
+enum{
+ /* item spawnflags */
+ ITEM_TRIGGER_SPAWN = 1<<0,
+ ITEM_NO_TOUCH = 1<<1,
+ /* 6 bits reserved for editor flags; 8 bits used as power cube id bits
+ * for coop games */
+ DROPPED_ITEM = 1<<16,
+ DROPPED_PLAYER_ITEM = 1<<17,
+ ITEM_TARGETS_USED = 1<<18,
+ /* fields are needed for spawning from the entity string and saving or
+ * loading games */
+ FFL_SPAWNTEMP = 1,
+ FFL_NOSPAWN = 2
+};
+typedef enum fieldtype_t{
+ F_INT,
+ F_FLOAT,
+ F_LSTRING, // string on disk, pointer in memory, TAG_LEVEL
+ F_GSTRING, // string on disk, pointer in memory, TAG_GAME
+ F_VECTOR,
+ F_ANGLEHACK,
+ F_EDICT, // index on disk, pointer in memory
+ F_ITEM, // index on disk, pointer in memory
+ F_CLIENT, // index on disk, pointer in memory
+ F_FUNCTION,
+ F_MMOVE,
+ F_IGNORE
+}fieldtype_t;
+struct field_t{
+ char *name;
+ int ofs;
+ fieldtype_t type;
+ int flags;
+};
+extern field_t fields[];
-//
-// functions exported by the game subsystem
-//
-typedef struct
-{
- int apiversion;
+enum{
+ /* damage flags */
+ DAMAGE_RADIUS = 1<<0, // indirect dmg
+ DAMAGE_NO_ARMOR = 1<<1, // not protected by armour
+ DAMAGE_ENERGY = 1<<2, // is from an energy based weapon
+ DAMAGE_NO_KNOCKBACK = 1<<3, // do not affect velocity, just view angles
+ DAMAGE_BULLET = 1<<4, // is from a bullet (used for ricochets)
+ /* no effect from armor, shields, invulnerability, and godmode */
+ DAMAGE_NO_PROTECTION = 1<<5,
- // the init function will only be called when a game starts,
- // not each time a level is loaded. Persistant data for clients
- // and the server can be allocated in init
- void (*Init) (void);
- void (*Shutdown) (void);
+ DEFAULT_BULLET_HSPREAD = 300,
+ DEFAULT_BULLET_VSPREAD = 500,
+ DEFAULT_SHOTGUN_HSPREAD = 1000,
+ DEFAULT_SHOTGUN_VSPREAD = 500,
+ DEFAULT_DEATHMATCH_SHOTGUN_COUNT = 12,
+ DEFAULT_SHOTGUN_COUNT = 12,
+ DEFAULT_SSHOTGUN_COUNT = 20,
- // each new level entered will cause a call to SpawnEntities
- void (*SpawnEntities) (char *mapname, char *entstring, char *spawnpoint);
+ /* client_t->anim_priority */
+ ANIM_BASIC = 0, // stand / run
+ ANIM_WAVE = 1,
+ ANIM_JUMP = 2,
+ ANIM_PAIN = 3,
+ ANIM_ATTACK = 4,
+ ANIM_DEATH = 5,
+ ANIM_REVERSE = 6
+};
- // Read/Write Game is for storing persistant cross level information
- // about the world state and the clients.
- // WriteGame is called every time a level is exited.
- // ReadGame is called on a loadgame.
- void (*WriteGame) (char *filename, qboolean autosave);
- void (*ReadGame) (char *filename);
+/* client data that stays across multiple level loads */
+struct client_persistant_t{
+ char userinfo[MAX_INFO_STRING];
+ char netname[16];
+ int hand;
+ /* a loadgame will leave valid entities that just don't have a connection yet */
+ qboolean connected;
+ /* values saved and restored from edicts when changing levels */
+ int health;
+ int max_health;
+ int savedFlags;
+ int selected_item;
+ int inventory[MAX_ITEMS];
+ int max_bullets;
+ int max_shells;
+ int max_rockets;
+ int max_grenades;
+ int max_cells;
+ int max_slugs;
+ gitem_t *weapon;
+ gitem_t *lastweapon;
+ int power_cubes; // used for tracking the cubes in coop games
+ int score; // for calculating total unit score in coop games
+ int game_helpchanged;
+ int helpchanged;
+ qboolean spectator; // client is a spectator
+};
+/* client data that stays across deathmatch respawns */
+struct client_respawn_t{
+ client_persistant_t coop_respawn; // assigned to client->pers on a respawn
+ int enterframe; // level.framenum the client entered the game
+ int score; // frags, etc
+ vec3_t cmd_angles; // angles sent over in the last command
+ qboolean spectator; // client is a spectator
+};
+/* this structure is cleared on each PutClientInServer(), except for .pers */
+struct gclient_t{
+ /* known to server */
+ player_state_t ps; // communicated by server to clients
+ int ping;
- // ReadLevel is called after the default map information has been
- // loaded with SpawnEntities
- void (*WriteLevel) (char *filename);
- void (*ReadLevel) (char *filename);
+ /* the server expects the first part of gclient_s to be a
+ * player_state_t but the rest of it is opaque
+ * DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER EXPECTS THE FIELDS IN
+ * THAT ORDER! */
- qboolean (*ClientConnect) (edict_t *ent, char *userinfo);
- void (*ClientBegin) (edict_t *ent);
- void (*ClientUserinfoChanged) (edict_t *ent, char *userinfo);
- void (*ClientDisconnect) (edict_t *ent);
- void (*ClientCommand) (edict_t *ent);
- void (*ClientThink) (edict_t *ent, usercmd_t *cmd);
+ client_persistant_t pers;
+ client_respawn_t resp;
+ pmove_state_t old_pmove; // for detecting out-of-pmove changes
+ qboolean showscores; // set layout stat
+ qboolean showinventory; // set layout stat
+ qboolean showhelp;
+ qboolean showhelpicon;
+ int ammo_index;
+ int buttons;
+ int oldbuttons;
+ int latched_buttons;
+ qboolean weapon_thunk;
+ gitem_t *newweapon;
- void (*RunFrame) (void);
+ /* sum up damage over an entire frame, so shotgun blasts give a single
+ * big kick */
+ int damage_armor; // damage absorbed by armor
+ int damage_parmor; // damage absorbed by power armor
+ int damage_blood; // damage taken out of health
+ int damage_knockback; // impact damage
+ vec3_t damage_from; // origin for vector calculation
+ float killer_yaw; // when dead, look at killer
+ weaponstate_t weaponstate;
+ vec3_t kick_angles; // weapon kicks
+ vec3_t kick_origin;
+ float v_dmg_roll; // damage kicks
+ float v_dmg_pitch;
+ float v_dmg_time;
+ float fall_time; // for view drop on fall
+ float fall_value;
+ float damage_alpha;
+ float bonus_alpha;
+ vec3_t damage_blend;
+ vec3_t v_angle; // aiming direction so off-ground doesn't change it
+ float bobtime;
+ vec3_t oldviewangles;
+ vec3_t oldvelocity;
+ float next_drown_time;
+ int old_waterlevel;
+ int breather_sound;
+ int machinegun_shots; // for weapon raising
+ int anim_end;
+ int anim_priority;
+ qboolean anim_duck;
+ qboolean anim_run;
+ /* powerup timers */
+ float quad_framenum;
+ float invincible_framenum;
+ float breather_framenum;
+ float enviro_framenum;
+ qboolean grenade_blew_up;
+ float grenade_time;
+ int silencer_shots;
+ int weapon_sound;
+ float pickup_msg_time;
+ float flood_locktill; // locked from talking
+ float flood_when[10]; // when messages were said
+ int flood_whenhead; // head pointer for when said
+ float respawn_time; // can respawn when time > this
+ edict_t *chase_target; // player we are chasing
+ qboolean update_chase; // need to update chase info?
+};
+struct edict_t{
+ entity_state_t s;
+ gclient_t *client; // nil if not a player
+ qboolean inuse;
+ int linkcount;
+ // FIXME: move these fields to a server private sv_entity_t
+ link_t area; // linked to a division node or leaf
+ int num_clusters; // if -1, use headnode instead
+ int clusternums[MAX_ENT_CLUSTERS];
+ int headnode; // unused if num_clusters != -1
+ int areanum;
+ int areanum2;
+ int svflags; // SCF_NOCLIENT, SVF_DEADMONSTER, SVF_MONSTER, etc.
+ vec3_t mins;
+ vec3_t maxs;
+ vec3_t absmin;
+ vec3_t absmax;
+ vec3_t size;
+ solid_t solid;
+ int clipmask;
+ edict_t *owner;
- // ServerCommand will be called when an "sv <command>" command is issued on the
- // server console.
- // The game can issue gi.argc() / gi.argv() commands to get the rest
- // of the parameters
- void (*ServerCommand) (void);
+ /* DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER EXPECTS THE FIELDS IN
+ * THAT ORDER! */
- //
- // global variables shared between game and server
- //
+ int movetype;
+ int flags;
+ char *model;
+ float freetime; // sv.time when the object was freed
+ /* only used locally in game, not by server */
+ char *message;
+ char *classname;
+ int spawnflags;
+ float timestamp;
+ float angle; // set in qe3, -1 = up, -2 = down
+ char *target;
+ char *targetname;
+ char *killtarget;
+ char *team;
+ char *pathtarget;
+ char *deathtarget;
+ char *combattarget;
+ edict_t *target_ent;
+ float speed;
+ float accel;
+ float decel;
+ vec3_t movedir;
+ vec3_t pos1;
+ vec3_t pos2;
+ vec3_t velocity;
+ vec3_t avelocity;
+ int mass;
+ float air_finished;
+ /* per entity gravity multiplier (1.0 is normal); use for lowgrav
+ * artifact, flares */
+ float gravity;
+ edict_t *goalentity;
+ edict_t *movetarget;
+ float yaw_speed;
+ float ideal_yaw;
+ float nextthink;
+ void (*prethink)(edict_t *);
+ void (*think)(edict_t *);
+ void (*blocked)(edict_t *, edict_t *); //move to moveinfo?
+ void (*touch)(edict_t *, edict_t *, cplane_t *, csurface_t *);
+ void (*use)(edict_t *, edict_t *, edict_t *);
+ void (*pain)(edict_t *, edict_t *, float, int);
+ void (*die)(edict_t *, edict_t *, edict_t *, int, vec3_t);
+ float touch_debounce_time; // are all these legit? do we need more/less of them?
+ float pain_debounce_time;
+ float damage_debounce_time;
+ float fly_sound_debounce_time; //move to clientinfo
+ float last_move_time;
+ int health;
+ int max_health;
+ int gib_health;
+ int deadflag;
+ qboolean show_hostile;
+ float powerarmor_time;
+ char *map; // target_changelevel
+ int viewheight; // height above origin where eyesight is determined
+ int takedamage;
+ int dmg;
+ int radius_dmg;
+ float dmg_radius;
+ int sounds; //make this a spawntemp var?
+ int count;
+ edict_t *chain;
+ edict_t *enemy;
+ edict_t *oldenemy;
+ edict_t *activator;
+ edict_t *groundentity;
+ int groundentity_linkcount;
+ edict_t *teamchain;
+ edict_t *teammaster;
+ edict_t *mynoise; // can go in client only
+ edict_t *mynoise2;
+ int noise_index;
+ int noise_index2;
+ float volume;
+ float attenuation;
+ /* timing variables */
+ float wait;
+ float delay; // before firing targets
+ float random;
+ float teleport_time;
+ int watertype;
+ int waterlevel;
+ vec3_t move_origin;
+ vec3_t move_angles;
+ /* move this to clientinfo? */
+ int light_level;
+ int style; // also used as areaportal number
+ gitem_t *item; // for bonus items
+ /* common data blocks */
+ moveinfo_t moveinfo;
+ monsterinfo_t monsterinfo;
+};
+extern edict_t *g_edicts;
- // The edict array is allocated in the game dll so it
- // can vary in size from one game to another.
- //
- // The size will be fixed when ge->Init() is called
- edict_t *edicts;
- int edict_size;
- int num_edicts; // current number, <= max_edicts
- int max_edicts;
-} game_export_t;
+#define WORLD (&g_edicts[0])
-game_export_t *GetGameAPI (game_import_t *import);
+#define ITEM_INDEX(x) ((x)-itemlist)
+#define FOFS(x) (uintptr)&(((edict_t *)0)->x)
+#define STOFS(x) (uintptr)&(((spawn_temp_t *)0)->x)
+#define LLOFS(x) (uintptr)&(((level_locals_t *)0)->x)
+#define CLOFS(x) (uintptr)&(((gclient_t *)0)->x)
+#define qrandom() ((rand () & 0x7fff) / ((float)0x7fff)) /* >_< arrrrggghh */
+#define crandom() (2.0 * (qrandom() - 0.5))
+
+void Cmd_Help_f(edict_t *);
+void Cmd_Score_f(edict_t *);
+void PrecacheItem(gitem_t *);
+void InitItems(void);
+void SetItemNames(void);
+gitem_t* FindItem(char *);
+gitem_t* FindItemByClassname(char *);
+edict_t* Drop_Item(edict_t *, gitem_t *);
+void SetRespawn(edict_t *, float);
+void ChangeWeapon(edict_t *);
+void SpawnItem(edict_t *, gitem_t *);
+void Think_Weapon(edict_t *);
+int ArmorIndex(edict_t *);
+int PowerArmorType(edict_t *);
+gitem_t* GetItemByIndex(int);
+qboolean Add_Ammo(edict_t *, gitem_t *, int);
+void Touch_Item(edict_t *, edict_t *, cplane_t *, csurface_t *);
+qboolean KillBox(edict_t *);
+void G_ProjectSource(vec3_t, vec3_t, vec3_t, vec3_t, vec3_t);
+edict_t* G_Find(edict_t *, int, char *);
+edict_t* findradius(edict_t *, vec3_t, float);
+edict_t* G_PickTarget(char *);
+void G_UseTargets(edict_t *, edict_t *);
+void G_SetMovedir(vec3_t, vec3_t);
+void G_InitEdict(edict_t *);
+edict_t* G_Spawn(void);
+void G_FreeEdict(edict_t *);
+void G_TouchTriggers(edict_t *);
+void G_TouchSolids(edict_t *);
+char* G_CopyString(char *);
+float* tv(float, float, float);
+char* vtos(vec3_t);
+float vectoyaw(vec3_t);
+void vectoangles(vec3_t, vec3_t);
+qboolean OnSameTeam(edict_t *, edict_t *);
+qboolean CanDamage(edict_t *, edict_t *);
+void T_Damage(edict_t *, edict_t *, edict_t *, vec3_t, vec3_t, vec3_t, int, int, int, int);
+void T_RadiusDamage(edict_t *, edict_t *, float, edict_t *, float, int);
+void monster_fire_bullet(edict_t *, vec3_t, vec3_t, int, int, int, int, int);
+void monster_fire_shotgun(edict_t *, vec3_t, vec3_t, int, int, int, int, int, int);
+void monster_fire_blaster(edict_t *, vec3_t, vec3_t, int, int, int, int);
+void monster_fire_grenade(edict_t *, vec3_t, vec3_t, int, int, int);
+void monster_fire_rocket(edict_t *, vec3_t, vec3_t, int, int, int);
+void monster_fire_railgun(edict_t *, vec3_t, vec3_t, int, int, int);
+void monster_fire_bfg(edict_t *, vec3_t, vec3_t, int, int, int, float, int);
+void M_droptofloor(edict_t *);
+void monster_think(edict_t *);
+void walkmonster_start(edict_t *);
+void swimmonster_start(edict_t *);
+void flymonster_start(edict_t *);
+void AttackFinished(edict_t *, float);
+void monster_death_use(edict_t *);
+void M_CatagorizePosition(edict_t *);
+qboolean M_CheckAttack(edict_t *);
+void M_FlyCheck(edict_t *);
+void M_CheckGround(edict_t *);
+void ThrowHead(edict_t *, char *, int, int);
+void ThrowClientHead(edict_t *, int);
+void ThrowGib(edict_t *, char *, int, int);
+void BecomeExplosion1(edict_t *);
+void AI_SetSightClient(void);
+void ai_stand(edict_t *, float);
+void ai_move(edict_t *, float);
+void ai_walk(edict_t *, float);
+void ai_turn(edict_t *, float);
+void ai_run(edict_t *, float);
+void ai_charge(edict_t *, float);
+int range(edict_t *, edict_t *);
+void FoundTarget(edict_t *);
+qboolean infront(edict_t *, edict_t *);
+qboolean visible(edict_t *, edict_t *);
+qboolean FacingIdeal(edict_t *);
+void ThrowDebris(edict_t *, char *, float, vec3_t);
+qboolean fire_hit(edict_t *, vec3_t, int, int);
+void fire_bullet(edict_t *, vec3_t, vec3_t, int, int, int, int, int);
+void fire_shotgun(edict_t *, vec3_t, vec3_t, int, int, int, int, int, int);
+void fire_blaster(edict_t *, vec3_t, vec3_t, int, int, int, qboolean);
+void fire_grenade(edict_t *, vec3_t, vec3_t, int, int, float, float);
+void fire_grenade2(edict_t *, vec3_t, vec3_t, int, int, float, float, qboolean);
+void fire_rocket(edict_t *, vec3_t, vec3_t, int, int, float, int);
+void fire_rail(edict_t *, vec3_t, vec3_t, int, int);
+void fire_bfg(edict_t *, vec3_t, vec3_t, int, int, float);
+void PlayerTrail_Init(void);
+void PlayerTrail_Add(vec3_t);
+void PlayerTrail_New(vec3_t);
+edict_t* PlayerTrail_PickFirst(edict_t *);
+edict_t* PlayerTrail_PickNext(edict_t *);
+edict_t* PlayerTrail_LastSpot(void);
+void respawn(edict_t *);
+void BeginIntermission(edict_t *);
+void PutClientInServer(edict_t *);
+void InitClientPersistant(gclient_t *);
+void InitClientResp(gclient_t *);
+void InitBodyQue(void);
+void ClientBeginServerFrame(edict_t *);
+void player_pain(edict_t *, edict_t *, float, int);
+void player_die(edict_t *, edict_t *, edict_t *, int, vec3_t);
+void ServerCommand(void);
+qboolean SV_FilterPacket(char *);
+void ClientEndServerFrame(edict_t *);
+void MoveClientToIntermission(edict_t *);
+void G_SetStats(edict_t *);
+void G_SetSpectatorStats(edict_t *);
+void G_CheckChaseStats(edict_t *);
+void ValidateSelectedItem(edict_t *);
+void DeathmatchScoreboardMessage(edict_t *, edict_t *);
+void PlayerNoise(edict_t *, vec3_t, int);
+qboolean M_CheckBottom(edict_t *);
+qboolean M_walkmove(edict_t *, float, float);
+void M_MoveToGoal(edict_t *, float);
+void M_ChangeYaw(edict_t *);
+void G_RunEntity(edict_t *);
+void SaveClientData(void);
+void FetchClientEntData(edict_t *);
+void UpdateChaseCam(edict_t *);
+void ChaseNext(edict_t *);
+void ChasePrev(edict_t *);
+void GetChaseTarget(edict_t *);
--- a/game/m_actor.c
+++ b/game/m_actor.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_actor.h"
#define MAX_ACTOR_NAMES 8
--- a/game/m_berserk.c
+++ b/game/m_berserk.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_berserk.h"
--- a/game/m_boss2.c
+++ b/game/m_boss2.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_boss2.h"
void BossExplode (edict_t *self);
--- a/game/m_boss3.c
+++ b/game/m_boss3.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_boss32.h"
void Use_Boss3 (edict_t *ent, edict_t */*other*/, edict_t */*activator*/)
--- a/game/m_boss31.c
+++ b/game/m_boss31.c
@@ -3,7 +3,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_boss31.h"
extern SP_monster_makron (edict_t *self);
--- a/game/m_boss32.c
+++ b/game/m_boss32.c
@@ -3,7 +3,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_boss32.h"
qboolean visible (edict_t *self, edict_t *other);
--- a/game/m_brain.c
+++ b/game/m_brain.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_brain.h"
--- a/game/m_chick.c
+++ b/game/m_chick.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_chick.h"
qboolean visible (edict_t *self, edict_t *other);
--- a/game/m_flash.c
+++ b/game/m_flash.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
// this file is included in both the game dll and quake2,
// the game needs it to source shot locations, the client
--- a/game/m_flipper.c
+++ b/game/m_flipper.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_flipper.h"
--- a/game/m_float.c
+++ b/game/m_float.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_float.h"
--- a/game/m_flyer.c
+++ b/game/m_flyer.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_flyer.h"
qboolean visible (edict_t *self, edict_t *other);
--- a/game/m_gladiator.c
+++ b/game/m_gladiator.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_gladiator.h"
--- a/game/m_gunner.c
+++ b/game/m_gunner.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_gunner.h"
--- a/game/m_hover.c
+++ b/game/m_hover.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_hover.h"
qboolean visible (edict_t *self, edict_t *other);
--- a/game/m_infantry.c
+++ b/game/m_infantry.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_infantry.h"
void InfantryMachineGun (edict_t *self);
--- a/game/m_insane.c
+++ b/game/m_insane.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_insane.h"
--- a/game/m_medic.c
+++ b/game/m_medic.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_medic.h"
qboolean visible (edict_t *self, edict_t *other);
--- a/game/m_move.c
+++ b/game/m_move.c
@@ -3,7 +3,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#define STEPSIZE 18
--- a/game/m_mutant.c
+++ b/game/m_mutant.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_mutant.h"
--- a/game/m_parasite.c
+++ b/game/m_parasite.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_parasite.h"
--- a/game/m_soldier.c
+++ b/game/m_soldier.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_soldier.h"
--- a/game/m_supertank.c
+++ b/game/m_supertank.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_supertank.h"
qboolean visible (edict_t *self, edict_t *other);
--- a/game/m_tank.c
+++ b/game/m_tank.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_tank.h"
--- a/game/p_client.c
+++ b/game/p_client.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_player.h"
void ClientUserinfoChanged (edict_t *ent, char *userinfo);
--- a/game/p_hud.c
+++ b/game/p_hud.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
/*
======================================================================
--- a/game/p_trail.c
+++ b/game/p_trail.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
/*
--- a/game/p_view.c
+++ b/game/p_view.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_player.h"
--- a/game/p_weapon.c
+++ b/game/p_weapon.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#include "m_player.h"
--- a/game/q_shared.c
+++ b/game/q_shared.c
@@ -1,7 +1,8 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include "../q_shared.h"
+#include "../dat.h"
+#include "../fns.h"
#define DEG2RAD( a ) ( a * M_PI ) / 180.0F
@@ -251,7 +252,7 @@
// this is the slow, general version
-int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
+int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, cplane_t *p)
{
int i;
float dist1, dist2;
@@ -289,7 +290,7 @@
Returns 1, 2, or 1 + 2
==================
*/
-int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
+int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, cplane_t *p)
{
float dist1, dist2;
int sides;
--- /dev/null
+++ b/in.c
@@ -1,0 +1,455 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include <draw.h>
+#include <thread.h>
+#include <mouse.h>
+#include <keyboard.h>
+#include "dat.h"
+#include "fns.h"
+
+extern int resized; /* vid.c */
+extern Point center;
+extern Channel *fuckchan, *tchan; /* sys.c */
+
+cvar_t *in_joystick;
+cvar_t *sensitivity;
+cvar_t *lookstrafe;
+cvar_t *lookspring;
+cvar_t *freelook;
+cvar_t *m_pitch;
+
+static cvar_t *m_filter;
+static cvar_t *m_windowed;
+static cvar_t *m_yaw;
+static cvar_t *m_side;
+static cvar_t *m_forward;
+
+static int mouseon;
+static int mlooking;
+static int dx, dy;
+static int oldmwin;
+
+typedef struct Kev Kev;
+struct Kev{
+ int key;
+ int down;
+};
+enum{
+ Nbuf = 64
+};
+static Channel *kchan, *mchan;
+static int iop = -1, pfd[2];
+static QLock killock;
+
+
+char *
+Sys_ConsoleInput(void)
+{
+ static char buf[256];
+ int n;
+
+ if(dedicated != nil && dedicated->value && iop >= 0){
+ if(flen(pfd[1]) < 1) /* only poll for input */
+ return nil;
+ if((n = read(pfd[1], buf, sizeof buf)) < 0)
+ sysfatal("Sys_ConsoleInput:read: %r");
+ if(n == 0){
+ iop = -1;
+ return nil;
+ }
+ return buf;
+ }
+ return nil;
+}
+
+void
+IN_Grabm(int on)
+{
+ static char nocurs[2*4+2*2*16];
+ static int fd = -1;
+
+ if(mouseon == on)
+ return;
+ if(mouseon = on && m_windowed->value){
+ if((fd = open("/dev/cursor", ORDWR|OCEXEC)) < 0){
+ sysfatal("IN_Grabm:open: %r\n");
+ return;
+ }
+ write(fd, nocurs, sizeof nocurs);
+ }else if(fd >= 0){
+ close(fd);
+ fd = -1;
+ }
+}
+
+void
+IN_Commands(void)
+{
+ /* joystick stuff */
+}
+
+void
+btnev(int btn, ulong msec)
+{
+ static int oldb;
+ int i, b;
+
+ for(i = 0; i < 3; i++){
+ b = 1<<i;
+ if(btn & b && ~oldb & b)
+ Key_Event(K_MOUSE1+i, true, msec);
+ else if(~btn & b && oldb & b)
+ Key_Event(K_MOUSE1+i, false, msec);
+ }
+ oldb = btn;
+ /* mwheelup and mwheeldn buttons are never held down */
+ for(i = 3; i < 5; i++){
+ b = 1<<i;
+ if(btn & b){
+ Key_Event(K_MOUSE1+i, true, msec);
+ Key_Event(K_MOUSE1+i, false, msec);
+ }
+ }
+}
+
+void
+KBD_Update(void)
+{
+ int r;
+ Kev ev;
+ Mouse m;
+
+ if(oldmwin != m_windowed->value){
+ oldmwin = m_windowed->value;
+ IN_Grabm(m_windowed->value);
+ }
+ while((r = nbrecv(kchan, &ev)) > 0)
+ Key_Event(ev.key, ev.down, Sys_Milliseconds());
+ if(r < 0)
+ sysfatal("KBD_Update:nbrecv: %r\n");
+ while((r = nbrecv(mchan, &m)) > 0){
+ dx += m.xy.x;
+ dy += m.xy.y;
+ btnev(m.buttons, m.msec);
+ }
+ if(r < 0)
+ sysfatal("KBD_Update:nbrecv: %r\n");
+}
+
+void
+IN_Move(usercmd_t *cmd)
+{
+ static int oldmx, oldmy;
+ int mx, my;
+
+ if(!mouseon)
+ return;
+
+ if(m_filter->value){
+ mx = (dx + oldmx) * 0.5;
+ my = (dy + oldmy) * 0.5;
+ }else{
+ mx = dx;
+ my = dy;
+ }
+ oldmx = dx;
+ oldmy = dy;
+ dx = dy = 0;
+ if(!mx && !my)
+ return;
+ mx *= sensitivity->value;
+ my *= sensitivity->value;
+
+ /* add mouse x/y movement to cmd */
+ if(in_strafe.state & 1 || lookstrafe->value && mlooking)
+ cmd->sidemove += m_side->value * mx;
+ else
+ cl.viewangles[YAW] -= m_yaw->value * mx;
+ if((mlooking || freelook->value) && ~in_strafe.state & 1)
+ cl.viewangles[PITCH] += m_pitch->value * my;
+ else
+ cmd->forwardmove -= m_forward->value * my;
+}
+
+/* called on focus/unfocus in win32 */
+void
+IN_Activate(qboolean)
+{
+}
+
+/* called every frame even if not generating commands */
+void
+IN_Frame(void)
+{
+}
+
+void
+IN_ForceCenterView(void)
+{
+ cl.viewangles[PITCH] = 0;
+}
+
+void
+IN_MLookDown(void)
+{
+ mlooking = true;
+}
+
+void
+IN_MLookUp(void)
+{
+ mlooking = false;
+ IN_CenterView();
+}
+
+static int
+runetokey(Rune r)
+{
+ int k = 0;
+
+ switch(r){
+ case Kpgup: k = K_PGUP; break;
+ case Kpgdown: k = K_PGDN; break;
+ case Khome: k = K_HOME; break;
+ case Kend: k = K_END; break;
+ case Kleft: k = K_LEFTARROW; break;
+ case Kright: k = K_RIGHTARROW; break;
+ case Kdown: k = K_DOWNARROW; break;
+ case Kup: k = K_UPARROW; break;
+ case Kesc: k = K_ESCAPE; break;
+ case '\n': k = K_ENTER; break;
+ case '\t': k = K_TAB; break;
+ case KF|1: k = K_F1; break;
+ case KF|2: k = K_F2; break;
+ case KF|3: k = K_F3; break;
+ case KF|4: k = K_F4; break;
+ case KF|5: k = K_F5; break;
+ case KF|6: k = K_F6; break;
+ case KF|7: k = K_F7; break;
+ case KF|8: k = K_F8; break;
+ case KF|9: k = K_F9; break;
+ case KF|10: k = K_F10; break;
+ case KF|11: k = K_F11; break;
+ case KF|12: k = K_F12; break;
+ case Kbs: k = K_BACKSPACE; break;
+ case Kdel: k = K_DEL; break;
+ case Kbreak: k = K_PAUSE; break;
+ case Kshift: k = K_SHIFT; break;
+ case Kctl: k = K_CTRL; break;
+ case Kalt:
+ case Kaltgr: k = K_ALT; break;
+ case Kins: k = K_INS; break;
+ default:
+ if(r < 0x80)
+ k = r;
+ };
+ return k;
+}
+
+static void
+kproc(void *)
+{
+ int n, k, fd;
+ char buf[128], kdown[128], *s;
+ Rune r;
+ Kev ev;
+
+ if(threadsetgrp(THin) < 0)
+ sysfatal("kproc:threadsetgrp: %r");
+ if((fd = open("/dev/kbd", OREAD)) < 0)
+ sysfatal("open /dev/kbd: %r");
+
+ kdown[0] = kdown[1] = 0;
+ while((n = read(fd, buf, sizeof buf)) > 0){
+ buf[n-1] = 0;
+ switch(*buf){
+ case 'c':
+ default:
+ continue;
+ case 'k':
+ s = buf+1;
+ while(*s){
+ s += chartorune(&r, s);
+ if(utfrune(kdown+1, r) == nil){
+ if(k = runetokey(r)){
+ ev.key = k;
+ ev.down = true;
+ if(send(kchan, &ev) < 0)
+ sysfatal("kproc:nbsend: %r\n");
+ }
+ }
+ }
+ break;
+ case 'K':
+ s = kdown+1;
+ while(*s){
+ s += chartorune(&r, s);
+ if(utfrune(buf+1, r) == nil){
+ if(k = runetokey(r)){
+ ev.key = k;
+ ev.down = false;
+ if(send(kchan, &ev) < 0)
+ sysfatal("mproc:nbsend: %r\n");
+ }
+ }
+ }
+ break;
+ }
+ strcpy(kdown, buf);
+ }
+ fprint(2, "kproc: %r\n");
+ close(fd);
+}
+
+static void
+mproc(void *)
+{
+ int n, nerr = 0, fd;
+ char buf[1+5*12];
+ Mouse m;
+
+ if(threadsetgrp(THin) < 0)
+ sysfatal("mproc:threadsetgrp: %r");
+ if((fd = open("/dev/mouse", ORDWR)) < 0)
+ sysfatal("open /dev/mouse: %r");
+
+ for(;;){
+ if((n = read(fd, buf, sizeof buf)) != 1+4*12){
+ fprint(2, "mproc:read: bad count %d not 49: %r\n", n);
+ if(n < 0 || ++nerr > 10)
+ break;
+ continue;
+ }
+ nerr = 0;
+ switch(*buf){
+ case 'r':
+ resized = 1;
+ /* fall through */
+ case 'm':
+ if(!mouseon)
+ break;
+
+ m.xy.x = atoi(buf+1+0*12) - center.x;
+ m.xy.y = atoi(buf+1+1*12) - center.y;
+ if(m.xy.x != 0 || m.xy.y != 0)
+ fprint(fd, "m%d %d", center.x, center.y);
+ m.buttons = atoi(buf+1+2*12);
+ m.msec = atoi(buf+1+3*12);
+ if(nbsend(mchan, &m) < 0)
+ sysfatal("mproc:nbsend: %r\n");
+ break;
+ }
+ }
+ fprint(2, "mproc: %r\n");
+ IN_Grabm(0);
+ close(fd);
+}
+
+static void
+tproc(void *) /* stupid select() timeout bullshit */
+{
+ int t, ms, n, r;
+
+ threadsetgrp(THin);
+
+ t = ms = 0;
+ for(;;){
+ sleep(1);
+ t++;
+
+ if((r = nbrecv(tchan, &n)) < 0)
+ sysfatal("tproc:nbrecv: %r");
+ if(r == 0){
+ if(t == ms && nbsend(fuckchan, nil) < 0)
+ sysfatal("tproc:nbsend: %r");
+ continue;
+ }
+ if(n <= 0)
+ ms = 0;
+ else{
+ ms = n;
+ t = 0;
+ }
+ }
+}
+
+static void
+iproc(void *)
+{
+ int n;
+ char s[256];
+
+ threadsetgrp(THin);
+
+ if((iop = pipe(pfd)) < 0)
+ sysfatal("iproc:pipe: %r");
+ for(;;){
+ if((n = read(0, s, sizeof s)) <= 0)
+ break;
+ s[n-1] = 0;
+ if((write(pfd[0], s, n)) != n)
+ break;
+ if(nbsend(fuckchan, nil) < 0)
+ sysfatal("iproc:nbsend: %r");
+ }
+ fprint(2, "iproc %d: %r\n", threadpid(threadid()));
+ iop = -1;
+}
+
+void
+IN_Shutdown(void)
+{
+ qlock(&killock); /* there can be only one */
+ IN_Grabm(0);
+ threadkillgrp(THin);
+ iop = -1;
+ close(pfd[0]);
+ close(pfd[1]);
+ if(kchan != nil){
+ chanfree(kchan);
+ kchan = nil;
+ }
+ if(mchan != nil){
+ chanfree(mchan);
+ mchan = nil;
+ }
+ qunlock(&killock);
+}
+
+void
+IN_Init(void)
+{
+ if(dedicated->value){
+ if(proccreate(iproc, nil, 8192) < 0)
+ sysfatal("proccreate iproc: %r");
+ if(proccreate(tproc, nil, 8192) < 0)
+ sysfatal("proccreate tproc: %r");
+ return;
+ }
+ in_joystick = Cvar_Get("in_joystick", "0", CVAR_ARCHIVE);
+ sensitivity = Cvar_Get("sensitivity", "3", CVAR_ARCHIVE);
+ freelook = Cvar_Get("freelook", "0", CVAR_ARCHIVE);
+ lookspring = Cvar_Get("lookspring", "0", CVAR_ARCHIVE);
+ lookstrafe = Cvar_Get("lookstrafe", "0", CVAR_ARCHIVE);
+ m_pitch = Cvar_Get("m_pitch", "0.022", CVAR_ARCHIVE);
+
+ m_yaw = Cvar_Get("m_yaw", "0.022", 0);
+ m_forward = Cvar_Get("m_forward", "1", 0);
+ m_side = Cvar_Get("m_side", "0.8", 0);
+ m_windowed = Cvar_Get("m_windowed", "0", CVAR_ARCHIVE);
+ m_filter = Cvar_Get("m_filter", "0", 0);
+
+ Cmd_AddCommand("+mlook", IN_MLookDown);
+ Cmd_AddCommand("-mlook", IN_MLookUp);
+ Cmd_AddCommand("force_centerview", IN_ForceCenterView);
+
+ if((kchan = chancreate(sizeof(Kev), Nbuf)) == nil)
+ sysfatal("chancreate kchan: %r");
+ if(proccreate(kproc, nil, 8192) < 0)
+ sysfatal("proccreate kproc: %r");
+ if((mchan = chancreate(sizeof(Mouse), Nbuf)) == nil)
+ sysfatal("chancreate kchan: %r");
+ if(proccreate(mproc, nil, 8192) < 0)
+ sysfatal("proccreate mproc: %r");
+}
--- /dev/null
+++ b/keys.c
@@ -1,0 +1,928 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/*
+
+key up events are sent even if in console mode
+
+*/
+
+
+#define MAXCMDLINE 256
+char key_lines[32][MAXCMDLINE];
+int key_linepos;
+int shift_down=false;
+int anykeydown;
+
+int edit_line=0;
+int history_line=0;
+
+int key_waiting;
+char *keybindings[256];
+qboolean consolekeys[256]; // if true, can't be rebound while in console
+qboolean menubound[256]; // if true, can't be rebound while in menu
+int keyshift[256]; // key to map to if shift held down in console
+int key_repeats[256]; // if > 1, it is autorepeating
+qboolean keydown[256];
+
+typedef struct
+{
+ char *name;
+ int keynum;
+} keyname_t;
+
+keyname_t keynames[] =
+{
+ {"TAB", K_TAB},
+ {"ENTER", K_ENTER},
+ {"ESCAPE", K_ESCAPE},
+ {"SPACE", K_SPACE},
+ {"BACKSPACE", K_BACKSPACE},
+ {"UPARROW", K_UPARROW},
+ {"DOWNARROW", K_DOWNARROW},
+ {"LEFTARROW", K_LEFTARROW},
+ {"RIGHTARROW", K_RIGHTARROW},
+
+ {"ALT", K_ALT},
+ {"CTRL", K_CTRL},
+ {"SHIFT", K_SHIFT},
+
+ {"F1", K_F1},
+ {"F2", K_F2},
+ {"F3", K_F3},
+ {"F4", K_F4},
+ {"F5", K_F5},
+ {"F6", K_F6},
+ {"F7", K_F7},
+ {"F8", K_F8},
+ {"F9", K_F9},
+ {"F10", K_F10},
+ {"F11", K_F11},
+ {"F12", K_F12},
+
+ {"INS", K_INS},
+ {"DEL", K_DEL},
+ {"PGDN", K_PGDN},
+ {"PGUP", K_PGUP},
+ {"HOME", K_HOME},
+ {"END", K_END},
+
+ {"MOUSE1", K_MOUSE1},
+ {"MOUSE2", K_MOUSE2},
+ {"MOUSE3", K_MOUSE3},
+
+ {"JOY1", K_JOY1},
+ {"JOY2", K_JOY2},
+ {"JOY3", K_JOY3},
+ {"JOY4", K_JOY4},
+
+ {"AUX1", K_AUX1},
+ {"AUX2", K_AUX2},
+ {"AUX3", K_AUX3},
+ {"AUX4", K_AUX4},
+ {"AUX5", K_AUX5},
+ {"AUX6", K_AUX6},
+ {"AUX7", K_AUX7},
+ {"AUX8", K_AUX8},
+ {"AUX9", K_AUX9},
+ {"AUX10", K_AUX10},
+ {"AUX11", K_AUX11},
+ {"AUX12", K_AUX12},
+ {"AUX13", K_AUX13},
+ {"AUX14", K_AUX14},
+ {"AUX15", K_AUX15},
+ {"AUX16", K_AUX16},
+ {"AUX17", K_AUX17},
+ {"AUX18", K_AUX18},
+ {"AUX19", K_AUX19},
+ {"AUX20", K_AUX20},
+ {"AUX21", K_AUX21},
+ {"AUX22", K_AUX22},
+ {"AUX23", K_AUX23},
+ {"AUX24", K_AUX24},
+ {"AUX25", K_AUX25},
+ {"AUX26", K_AUX26},
+ {"AUX27", K_AUX27},
+ {"AUX28", K_AUX28},
+ {"AUX29", K_AUX29},
+ {"AUX30", K_AUX30},
+ {"AUX31", K_AUX31},
+ {"AUX32", K_AUX32},
+
+ {"KP_HOME", K_KP_HOME },
+ {"KP_UPARROW", K_KP_UPARROW },
+ {"KP_PGUP", K_KP_PGUP },
+ {"KP_LEFTARROW", K_KP_LEFTARROW },
+ {"KP_5", K_KP_5 },
+ {"KP_RIGHTARROW", K_KP_RIGHTARROW },
+ {"KP_END", K_KP_END },
+ {"KP_DOWNARROW", K_KP_DOWNARROW },
+ {"KP_PGDN", K_KP_PGDN },
+ {"KP_ENTER", K_KP_ENTER },
+ {"KP_INS", K_KP_INS },
+ {"KP_DEL", K_KP_DEL },
+ {"KP_SLASH", K_KP_SLASH },
+ {"KP_MINUS", K_KP_MINUS },
+ {"KP_PLUS", K_KP_PLUS },
+
+ {"MWHEELUP", K_MWHEELUP },
+ {"MWHEELDOWN", K_MWHEELDOWN },
+
+ {"PAUSE", K_PAUSE},
+
+ {"SEMICOLON", ';'}, // because a raw semicolon seperates commands
+
+ {NULL,0}
+};
+
+/*
+==============================================================================
+
+ LINE TYPING INTO THE CONSOLE
+
+==============================================================================
+*/
+
+void CompleteCommand (void)
+{
+ char *cmd, *s;
+
+ s = key_lines[edit_line]+1;
+ if (*s == '\\' || *s == '/')
+ s++;
+
+ cmd = Cmd_CompleteCommand (s);
+ if (!cmd)
+ cmd = Cvar_CompleteVariable (s);
+ if (cmd)
+ {
+ key_lines[edit_line][1] = '/';
+ strcpy (key_lines[edit_line]+2, cmd);
+ key_linepos = strlen(cmd)+2;
+ key_lines[edit_line][key_linepos] = ' ';
+ key_linepos++;
+ key_lines[edit_line][key_linepos] = 0;
+ return;
+ }
+}
+
+/*
+====================
+Key_Console
+
+Interactive line editing and console scrollback
+====================
+*/
+void Key_Console (int key)
+{
+
+ switch ( key )
+ {
+ case K_KP_SLASH:
+ key = '/';
+ break;
+ case K_KP_MINUS:
+ key = '-';
+ break;
+ case K_KP_PLUS:
+ key = '+';
+ break;
+ case K_KP_HOME:
+ key = '7';
+ break;
+ case K_KP_UPARROW:
+ key = '8';
+ break;
+ case K_KP_PGUP:
+ key = '9';
+ break;
+ case K_KP_LEFTARROW:
+ key = '4';
+ break;
+ case K_KP_5:
+ key = '5';
+ break;
+ case K_KP_RIGHTARROW:
+ key = '6';
+ break;
+ case K_KP_END:
+ key = '1';
+ break;
+ case K_KP_DOWNARROW:
+ key = '2';
+ break;
+ case K_KP_PGDN:
+ key = '3';
+ break;
+ case K_KP_INS:
+ key = '0';
+ break;
+ case K_KP_DEL:
+ key = '.';
+ break;
+ }
+
+ if ( ( toupper( key ) == 'V' && keydown[K_CTRL] ) ||
+ ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keydown[K_SHIFT] ) )
+ {
+ char *cbd;
+
+ if ( ( cbd = Sys_GetClipboardData() ) != 0 )
+ {
+ int i;
+
+ strtok( cbd, "\n\r\b" );
+
+ i = strlen( cbd );
+ if ( i + key_linepos >= MAXCMDLINE)
+ i= MAXCMDLINE - key_linepos;
+
+ if ( i > 0 )
+ {
+ cbd[i]=0;
+ strcat( key_lines[edit_line], cbd );
+ key_linepos += i;
+ }
+ free( cbd );
+ }
+
+ return;
+ }
+
+ if ( key == 'l' )
+ {
+ if ( keydown[K_CTRL] )
+ {
+ Cbuf_AddText ("clear\n");
+ return;
+ }
+ }
+
+ if ( key == K_ENTER || key == K_KP_ENTER )
+ { // backslash text are commands, else chat
+ if (key_lines[edit_line][1] == '\\' || key_lines[edit_line][1] == '/')
+ Cbuf_AddText (key_lines[edit_line]+2); // skip the >
+ else
+ Cbuf_AddText (key_lines[edit_line]+1); // valid command
+
+ Cbuf_AddText ("\n");
+ Com_Printf ("%s\n",key_lines[edit_line]);
+ edit_line = (edit_line + 1) & 31;
+ history_line = edit_line;
+ key_lines[edit_line][0] = ']';
+ key_linepos = 1;
+ if (cls.state == ca_disconnected)
+ SCR_UpdateScreen (); // force an update, because the command
+ // may take some time
+ return;
+ }
+
+ if (key == K_TAB)
+ { // command completion
+ CompleteCommand ();
+ return;
+ }
+
+ if ( ( key == K_BACKSPACE ) || ( key == K_LEFTARROW ) || ( key == K_KP_LEFTARROW ) || ( ( key == 'h' ) && ( keydown[K_CTRL] ) ) )
+ {
+ if (key_linepos > 1)
+ key_linepos--;
+ return;
+ }
+
+ if ( ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
+ ( ( key == 'p' ) && keydown[K_CTRL] ) )
+ {
+ do
+ {
+ history_line = (history_line - 1) & 31;
+ } while (history_line != edit_line
+ && !key_lines[history_line][1]);
+ if (history_line == edit_line)
+ history_line = (edit_line+1)&31;
+ strcpy(key_lines[edit_line], key_lines[history_line]);
+ key_linepos = strlen(key_lines[edit_line]);
+ return;
+ }
+
+ if ( ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ||
+ ( ( key == 'n' ) && keydown[K_CTRL] ) )
+ {
+ if (history_line == edit_line) return;
+ do
+ {
+ history_line = (history_line + 1) & 31;
+ }
+ while (history_line != edit_line
+ && !key_lines[history_line][1]);
+ if (history_line == edit_line)
+ {
+ key_lines[edit_line][0] = ']';
+ key_linepos = 1;
+ }
+ else
+ {
+ strcpy(key_lines[edit_line], key_lines[history_line]);
+ key_linepos = strlen(key_lines[edit_line]);
+ }
+ return;
+ }
+
+ if (key == K_PGUP || key == K_KP_PGUP )
+ {
+ con.display -= 2;
+ return;
+ }
+
+ if (key == K_PGDN || key == K_KP_PGDN )
+ {
+ con.display += 2;
+ if (con.display > con.current)
+ con.display = con.current;
+ return;
+ }
+
+ if (key == K_HOME || key == K_KP_HOME )
+ {
+ con.display = con.current - con.totallines + 10;
+ return;
+ }
+
+ if (key == K_END || key == K_KP_END )
+ {
+ con.display = con.current;
+ return;
+ }
+
+ if (key < 32 || key > 127)
+ return; // non printable
+
+ if (key_linepos < MAXCMDLINE-1)
+ {
+ key_lines[edit_line][key_linepos] = key;
+ key_linepos++;
+ key_lines[edit_line][key_linepos] = 0;
+ }
+
+}
+
+//============================================================================
+
+qboolean chat_team;
+char chat_buffer[MAXCMDLINE];
+int chat_bufferlen = 0;
+
+void Key_Message (int key)
+{
+
+ if ( key == K_ENTER || key == K_KP_ENTER )
+ {
+ if (chat_team)
+ Cbuf_AddText ("say_team \"");
+ else
+ Cbuf_AddText ("say \"");
+ Cbuf_AddText(chat_buffer);
+ Cbuf_AddText("\"\n");
+
+ cls.key_dest = key_game;
+ chat_bufferlen = 0;
+ chat_buffer[0] = 0;
+ return;
+ }
+
+ if (key == K_ESCAPE)
+ {
+ cls.key_dest = key_game;
+ chat_bufferlen = 0;
+ chat_buffer[0] = 0;
+ return;
+ }
+
+ if (key < 32 || key > 127)
+ return; // non printable
+
+ if (key == K_BACKSPACE)
+ {
+ if (chat_bufferlen)
+ {
+ chat_bufferlen--;
+ chat_buffer[chat_bufferlen] = 0;
+ }
+ return;
+ }
+
+ if (chat_bufferlen == sizeof(chat_buffer)-1)
+ return; // all full
+
+ chat_buffer[chat_bufferlen++] = key;
+ chat_buffer[chat_bufferlen] = 0;
+}
+
+//============================================================================
+
+
+/*
+===================
+Key_StringToKeynum
+
+Returns a key number to be used to index keybindings[] by looking at
+the given string. Single ascii characters return themselves, while
+the K_* names are matched up.
+===================
+*/
+int Key_StringToKeynum (char *str)
+{
+ keyname_t *kn;
+
+ if (!str || !str[0])
+ return -1;
+ if (!str[1])
+ return str[0];
+
+ for (kn=keynames ; kn->name ; kn++)
+ {
+ if (!cistrcmp(str,kn->name))
+ return kn->keynum;
+ }
+ return -1;
+}
+
+/*
+===================
+Key_KeynumToString
+
+Returns a string (either a single ascii char, or a K_* name) for the
+given keynum.
+FIXME: handle quote special (general escape sequence?)
+===================
+*/
+char *Key_KeynumToString (int keynum)
+{
+ keyname_t *kn;
+ static char tinystr[2];
+
+ if (keynum == -1)
+ return "<KEY NOT FOUND>";
+ if (keynum > 32 && keynum < 127)
+ { // printable ascii
+ tinystr[0] = keynum;
+ tinystr[1] = 0;
+ return tinystr;
+ }
+
+ for (kn=keynames ; kn->name ; kn++)
+ if (keynum == kn->keynum)
+ return kn->name;
+
+ return "<UNKNOWN KEYNUM>";
+}
+
+
+/*
+===================
+Key_SetBinding
+===================
+*/
+void Key_SetBinding (int keynum, char *binding)
+{
+ char *new;
+ int l;
+
+ if (keynum == -1)
+ return;
+
+// free old bindings
+ if (keybindings[keynum])
+ {
+ Z_Free (keybindings[keynum]);
+ keybindings[keynum] = NULL;
+ }
+
+// allocate memory for new binding
+ l = strlen (binding);
+ new = Z_Malloc (l+1);
+ strcpy (new, binding);
+ new[l] = 0;
+ keybindings[keynum] = new;
+}
+
+/*
+===================
+Key_Unbind_f
+===================
+*/
+void Key_Unbind_f (void)
+{
+ int b;
+
+ if (Cmd_Argc() != 2)
+ {
+ Com_Printf ("unbind <key> : remove commands from a key\n");
+ return;
+ }
+
+ b = Key_StringToKeynum (Cmd_Argv(1));
+ if (b==-1)
+ {
+ Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
+ return;
+ }
+
+ Key_SetBinding (b, "");
+}
+
+void Key_Unbindall_f (void)
+{
+ int i;
+
+ for (i=0 ; i<256 ; i++)
+ if (keybindings[i])
+ Key_SetBinding (i, "");
+}
+
+
+/*
+===================
+Key_Bind_f
+===================
+*/
+void Key_Bind_f (void)
+{
+ int i, c, b;
+ char cmd[1024];
+
+ c = Cmd_Argc();
+
+ if (c < 2)
+ {
+ Com_Printf ("bind <key> [command] : attach a command to a key\n");
+ return;
+ }
+ b = Key_StringToKeynum (Cmd_Argv(1));
+ if (b==-1)
+ {
+ Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
+ return;
+ }
+
+ if (c == 2)
+ {
+ if (keybindings[b])
+ Com_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] );
+ else
+ Com_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );
+ return;
+ }
+
+// copy the rest of the command line
+ cmd[0] = 0; // start out with a null string
+ for (i=2 ; i< c ; i++)
+ {
+ strcat (cmd, Cmd_Argv(i));
+ if (i != (c-1))
+ strcat (cmd, " ");
+ }
+
+ Key_SetBinding (b, cmd);
+}
+
+/*
+============
+Key_WriteBindings
+
+Writes lines containing "bind key value"
+============
+*/
+void Key_WriteBindings (FILE *f)
+{
+ int i;
+
+ for (i=0 ; i<256 ; i++)
+ if (keybindings[i] && keybindings[i][0])
+ fprintf (f, "bind %s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
+}
+
+
+/*
+============
+Key_Bindlist_f
+
+============
+*/
+void Key_Bindlist_f (void)
+{
+ int i;
+
+ for (i=0 ; i<256 ; i++)
+ if (keybindings[i] && keybindings[i][0])
+ Com_Printf ("%s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
+}
+
+
+/*
+===================
+Key_Init
+===================
+*/
+void Key_Init (void)
+{
+ int i;
+
+ for (i=0 ; i<32 ; i++)
+ {
+ key_lines[i][0] = ']';
+ key_lines[i][1] = 0;
+ }
+ key_linepos = 1;
+
+//
+// init ascii characters in console mode
+//
+ for (i=32 ; i<128 ; i++)
+ consolekeys[i] = true;
+ consolekeys[K_ENTER] = true;
+ consolekeys[K_KP_ENTER] = true;
+ consolekeys[K_TAB] = true;
+ consolekeys[K_LEFTARROW] = true;
+ consolekeys[K_KP_LEFTARROW] = true;
+ consolekeys[K_RIGHTARROW] = true;
+ consolekeys[K_KP_RIGHTARROW] = true;
+ consolekeys[K_UPARROW] = true;
+ consolekeys[K_KP_UPARROW] = true;
+ consolekeys[K_DOWNARROW] = true;
+ consolekeys[K_KP_DOWNARROW] = true;
+ consolekeys[K_BACKSPACE] = true;
+ consolekeys[K_HOME] = true;
+ consolekeys[K_KP_HOME] = true;
+ consolekeys[K_END] = true;
+ consolekeys[K_KP_END] = true;
+ consolekeys[K_PGUP] = true;
+ consolekeys[K_KP_PGUP] = true;
+ consolekeys[K_PGDN] = true;
+ consolekeys[K_KP_PGDN] = true;
+ consolekeys[K_SHIFT] = true;
+ consolekeys[K_INS] = true;
+ consolekeys[K_KP_INS] = true;
+ consolekeys[K_KP_DEL] = true;
+ consolekeys[K_KP_SLASH] = true;
+ consolekeys[K_KP_PLUS] = true;
+ consolekeys[K_KP_MINUS] = true;
+ consolekeys[K_KP_5] = true;
+
+ consolekeys['`'] = false;
+ consolekeys['~'] = false;
+
+ for (i=0 ; i<256 ; i++)
+ keyshift[i] = i;
+ for (i='a' ; i<='z' ; i++)
+ keyshift[i] = i - 'a' + 'A';
+ keyshift['1'] = '!';
+ keyshift['2'] = '@';
+ keyshift['3'] = '#';
+ keyshift['4'] = '$';
+ keyshift['5'] = '%';
+ keyshift['6'] = '^';
+ keyshift['7'] = '&';
+ keyshift['8'] = '*';
+ keyshift['9'] = '(';
+ keyshift['0'] = ')';
+ keyshift['-'] = '_';
+ keyshift['='] = '+';
+ keyshift[','] = '<';
+ keyshift['.'] = '>';
+ keyshift['/'] = '?';
+ keyshift[';'] = ':';
+ keyshift['\''] = '"';
+ keyshift['['] = '{';
+ keyshift[']'] = '}';
+ keyshift['`'] = '~';
+ keyshift['\\'] = '|';
+
+ menubound[K_ESCAPE] = true;
+ for (i=0 ; i<12 ; i++)
+ menubound[K_F1+i] = true;
+
+//
+// register our functions
+//
+ Cmd_AddCommand ("bind",Key_Bind_f);
+ Cmd_AddCommand ("unbind",Key_Unbind_f);
+ Cmd_AddCommand ("unbindall",Key_Unbindall_f);
+ Cmd_AddCommand ("bindlist",Key_Bindlist_f);
+}
+
+/*
+===================
+Key_Event
+
+Called by the system between frames for both key up and key down events
+Should NOT be called during an interrupt!
+===================
+*/
+void Key_Event (int key, qboolean down, unsigned time)
+{
+ char *kb;
+ char cmd[1024];
+
+ // hack for modal presses
+ if (key_waiting == -1)
+ {
+ if (down)
+ key_waiting = key;
+ return;
+ }
+
+ // update auto-repeat status
+ if (down)
+ {
+ key_repeats[key]++;
+ if (key != K_BACKSPACE
+ && key != K_PAUSE
+ && key != K_PGUP
+ && key != K_KP_PGUP
+ && key != K_PGDN
+ && key != K_KP_PGDN
+ && key_repeats[key] > 1)
+ return; // ignore most autorepeats
+
+ if (key >= 200 && !keybindings[key])
+ Com_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) );
+ }
+ else
+ {
+ key_repeats[key] = 0;
+ }
+
+ if (key == K_SHIFT)
+ shift_down = down;
+
+ // console key is hardcoded, so the user can never unbind it
+ if (key == '`' || key == '~')
+ {
+ if (!down)
+ return;
+ Con_ToggleConsole_f ();
+ return;
+ }
+
+ // any key during the attract mode will bring up the menu
+ if (cl.attractloop && cls.key_dest != key_menu)
+ key = K_ESCAPE;
+
+ // menu key is hardcoded, so the user can never unbind it
+ if (key == K_ESCAPE)
+ {
+ if (!down)
+ return;
+
+ if (cl.frame.playerstate.stats[STAT_LAYOUTS] && cls.key_dest == key_game)
+ { // put away help computer / inventory
+ Cbuf_AddText ("cmd putaway\n");
+ return;
+ }
+ switch (cls.key_dest)
+ {
+ case key_message:
+ Key_Message (key);
+ break;
+ case key_menu:
+ M_Keydown (key);
+ break;
+ case key_game:
+ case key_console:
+ M_Menu_Main_f ();
+ break;
+ default:
+ Com_Error (ERR_FATAL, "Bad cls.key_dest");
+ }
+ return;
+ }
+
+ // track if any key is down for BUTTON_ANY
+ keydown[key] = down;
+ if (down)
+ {
+ if (key_repeats[key] == 1)
+ anykeydown++;
+ }
+ else
+ {
+ anykeydown--;
+ if (anykeydown < 0)
+ anykeydown = 0;
+ }
+
+//
+// key up events only generate commands if the game key binding is
+// a button command (leading + sign). These will occur even in console mode,
+// to keep the character from continuing an action started before a console
+// switch. Button commands include the kenum as a parameter, so multiple
+// downs can be matched with ups
+//
+ if (!down)
+ {
+ kb = keybindings[key];
+ if (kb && kb[0] == '+')
+ {
+ Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
+ Cbuf_AddText (cmd);
+ }
+ if (keyshift[key] != key)
+ {
+ kb = keybindings[keyshift[key]];
+ if (kb && kb[0] == '+')
+ {
+ Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
+ Cbuf_AddText (cmd);
+ }
+ }
+ return;
+ }
+
+//
+// if not a consolekey, send to the interpreter no matter what mode is
+//
+ if ( (cls.key_dest == key_menu && menubound[key])
+ || (cls.key_dest == key_console && !consolekeys[key])
+ || (cls.key_dest == key_game && ( cls.state == ca_active || !consolekeys[key] ) ) )
+ {
+ kb = keybindings[key];
+ if (kb)
+ {
+ if (kb[0] == '+')
+ { // button commands add keynum and time as a parm
+ Com_sprintf (cmd, sizeof(cmd), "%s %i %i\n", kb, key, time);
+ Cbuf_AddText (cmd);
+ }
+ else
+ {
+ Cbuf_AddText (kb);
+ Cbuf_AddText ("\n");
+ }
+ }
+ return;
+ }
+
+ if (!down)
+ return; // other systems only care about key down events
+
+ if (shift_down)
+ key = keyshift[key];
+
+ switch (cls.key_dest)
+ {
+ case key_message:
+ Key_Message (key);
+ break;
+ case key_menu:
+ M_Keydown (key);
+ break;
+
+ case key_game:
+ case key_console:
+ Key_Console (key);
+ break;
+ default:
+ Com_Error (ERR_FATAL, "Bad cls.key_dest");
+ }
+}
+
+/*
+===================
+Key_ClearStates
+===================
+*/
+void Key_ClearStates (void)
+{
+ int i;
+
+ anykeydown = false;
+
+ for (i=0 ; i<256 ; i++)
+ {
+ if ( keydown[i] || key_repeats[i] )
+ Key_Event( i, false, 0 );
+ keydown[i] = 0;
+ key_repeats[i] = 0;
+ }
+}
+
+
+/*
+===================
+Key_GetKey
+===================
+*/
+int Key_GetKey (void)
+{
+ key_waiting = -1;
+
+ while (key_waiting == -1)
+ Sys_SendKeyEvents ();
+
+ return key_waiting;
+}
+
--- /dev/null
+++ b/md4.c
@@ -1,0 +1,276 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef unsigned short int UINT2;
+
+/* UINT4 defines a four byte word */
+typedef unsigned long int UINT4;
+
+
+/* MD4.H - header file for MD4C.C */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991.
+
+All rights reserved.
+
+License to copy and use this software is granted provided that it is identified as the �RSA Data Security, Inc. MD4 Message-Digest Algorithm� in all material mentioning or referencing this software or this function.
+License is also granted to make and use derivative works provided that such works are identified as �derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm� in all material mentioning or referencing the derived work.
+RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided �as is� without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this documentation and/or software. */
+
+/* MD4 context. */
+typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD4_CTX;
+
+void MD4Init (MD4_CTX *);
+void MD4Update (MD4_CTX *, unsigned char *, unsigned int);
+void MD4Final (unsigned char [16], MD4_CTX *);
+
+
+
+/* MD4C.C - RSA Data Security, Inc., MD4 message-digest algorithm */
+/* Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
+
+License to copy and use this software is granted provided that it is identified as the
+RSA Data Security, Inc. MD4 Message-Digest Algorithm
+ in all material mentioning or referencing this software or this function.
+License is also granted to make and use derivative works provided that such works are identified as
+derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm
+in all material mentioning or referencing the derived work.
+RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided
+as is without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this documentation and/or software. */
+
+/* Constants for MD4Transform routine. */
+#define S11 3
+#define S12 7
+#define S13 11
+#define S14 19
+#define S21 3
+#define S22 5
+#define S23 9
+#define S24 13
+#define S31 3
+#define S32 9
+#define S33 11
+#define S34 15
+
+static void MD4Transform (UINT4 [4], unsigned char [64]);
+static void Encode (unsigned char *, UINT4 *, unsigned int);
+static void Decode (UINT4 *, unsigned char *, unsigned int);
+
+static unsigned char PADDING[64] = {
+0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G and H are basic MD4 functions. */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/* ROTATE_LEFT rotates x left n bits. */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG and HH are transformations for rounds 1, 2 and 3 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s) {(a) += F ((b), (c), (d)) + (x); (a) = ROTATE_LEFT ((a), (s));}
+
+#define GG(a, b, c, d, x, s) {(a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; (a) = ROTATE_LEFT ((a), (s));}
+
+#define HH(a, b, c, d, x, s) {(a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; (a) = ROTATE_LEFT ((a), (s));}
+
+
+/* MD4 initialization. Begins an MD4 operation, writing a new context. */
+void MD4Init (MD4_CTX *context)
+{
+ context->count[0] = context->count[1] = 0;
+
+/* Load magic initialization constants.*/
+context->state[0] = 0x67452301;
+context->state[1] = 0xefcdab89;
+context->state[2] = 0x98badcfe;
+context->state[3] = 0x10325476;
+}
+
+/* MD4 block update operation. Continues an MD4 message-digest operation, processing another message block, and updating the context. */
+void MD4Update (MD4_CTX *context, unsigned char *input, unsigned int inputLen)
+{
+ unsigned int i, index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))< ((UINT4)inputLen << 3))
+ context->count[1]++;
+
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.*/
+ if (inputLen >= partLen)
+ {
+ memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen);
+ MD4Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD4Transform (context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ memcpy ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);
+}
+
+
+/* MD4 finalization. Ends an MD4 message-digest operation, writing the the message digest and zeroizing the context. */
+void MD4Final (unsigned char digest[16], MD4_CTX *context)
+{
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.*/
+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ MD4Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD4Update (context, bits, 8);
+
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.*/
+ memset ((POINTER)context, 0, sizeof (*context));
+}
+
+
+/* MD4 basic transformation. Transforms state based on block. */
+static void MD4Transform (UINT4 state[4], unsigned char block[64])
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+/* Round 1 */
+FF (a, b, c, d, x[ 0], S11); /* 1 */
+FF (d, a, b, c, x[ 1], S12); /* 2 */
+FF (c, d, a, b, x[ 2], S13); /* 3 */
+FF (b, c, d, a, x[ 3], S14); /* 4 */
+FF (a, b, c, d, x[ 4], S11); /* 5 */
+FF (d, a, b, c, x[ 5], S12); /* 6 */
+FF (c, d, a, b, x[ 6], S13); /* 7 */
+FF (b, c, d, a, x[ 7], S14); /* 8 */
+FF (a, b, c, d, x[ 8], S11); /* 9 */
+FF (d, a, b, c, x[ 9], S12); /* 10 */
+FF (c, d, a, b, x[10], S13); /* 11 */
+FF (b, c, d, a, x[11], S14); /* 12 */
+FF (a, b, c, d, x[12], S11); /* 13 */
+FF (d, a, b, c, x[13], S12); /* 14 */
+FF (c, d, a, b, x[14], S13); /* 15 */
+FF (b, c, d, a, x[15], S14); /* 16 */
+
+/* Round 2 */
+GG (a, b, c, d, x[ 0], S21); /* 17 */
+GG (d, a, b, c, x[ 4], S22); /* 18 */
+GG (c, d, a, b, x[ 8], S23); /* 19 */
+GG (b, c, d, a, x[12], S24); /* 20 */
+GG (a, b, c, d, x[ 1], S21); /* 21 */
+GG (d, a, b, c, x[ 5], S22); /* 22 */
+GG (c, d, a, b, x[ 9], S23); /* 23 */
+GG (b, c, d, a, x[13], S24); /* 24 */
+GG (a, b, c, d, x[ 2], S21); /* 25 */
+GG (d, a, b, c, x[ 6], S22); /* 26 */
+GG (c, d, a, b, x[10], S23); /* 27 */
+GG (b, c, d, a, x[14], S24); /* 28 */
+GG (a, b, c, d, x[ 3], S21); /* 29 */
+GG (d, a, b, c, x[ 7], S22); /* 30 */
+GG (c, d, a, b, x[11], S23); /* 31 */
+GG (b, c, d, a, x[15], S24); /* 32 */
+
+/* Round 3 */
+HH (a, b, c, d, x[ 0], S31); /* 33 */
+HH (d, a, b, c, x[ 8], S32); /* 34 */
+HH (c, d, a, b, x[ 4], S33); /* 35 */
+HH (b, c, d, a, x[12], S34); /* 36 */
+HH (a, b, c, d, x[ 2], S31); /* 37 */
+HH (d, a, b, c, x[10], S32); /* 38 */
+HH (c, d, a, b, x[ 6], S33); /* 39 */
+HH (b, c, d, a, x[14], S34); /* 40 */
+HH (a, b, c, d, x[ 1], S31); /* 41 */
+HH (d, a, b, c, x[ 9], S32); /* 42 */
+HH (c, d, a, b, x[ 5], S33); /* 43 */
+HH (b, c, d, a, x[13], S34); /* 44 */
+HH (a, b, c, d, x[ 3], S31); /* 45 */
+HH (d, a, b, c, x[11], S32); /* 46 */
+HH (c, d, a, b, x[ 7], S33); /* 47 */
+HH (b, c, d, a, x[15], S34); /* 48 */
+
+state[0] += a;
+state[1] += b;
+state[2] += c;
+state[3] += d;
+
+ /* Zeroize sensitive information.*/
+ memset ((POINTER)x, 0, sizeof (x));
+}
+
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is a multiple of 4. */
+static void Encode (unsigned char *output, UINT4 *input, unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4. */
+static void Decode (UINT4 *output, unsigned char *input, unsigned int len)
+{
+unsigned int i, j;
+
+for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+//===================================================================
+
+unsigned Com_BlockChecksum (void *buffer, int length)
+{
+ int digest[4];
+ unsigned val;
+ MD4_CTX ctx;
+
+ MD4Init (&ctx);
+ MD4Update (&ctx, (unsigned char *)buffer, length);
+ MD4Final ( (unsigned char *)digest, &ctx);
+
+ val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3];
+
+ return val;
+}
--- /dev/null
+++ b/menu.c
@@ -1,0 +1,3998 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "dat.h"
+#include "fns.h"
+
+static int m_main_cursor;
+
+#define NUM_CURSOR_FRAMES 15
+
+static char *menu_in_sound = "misc/menu1.wav";
+static char *menu_move_sound = "misc/menu2.wav";
+static char *menu_out_sound = "misc/menu3.wav";
+
+void M_Menu_Main_f (void);
+ void M_Menu_Game_f (void);
+ void M_Menu_LoadGame_f (void);
+ void M_Menu_SaveGame_f (void);
+ void M_Menu_PlayerConfig_f (void);
+ void M_Menu_DownloadOptions_f (void);
+ void M_Menu_Credits_f( void );
+ void M_Menu_Multiplayer_f( void );
+ void M_Menu_JoinServer_f (void);
+ void M_Menu_AddressBook_f( void );
+ void M_Menu_StartServer_f (void);
+ void M_Menu_DMOptions_f (void);
+ void M_Menu_Video_f (void);
+ void M_Menu_Options_f (void);
+ void M_Menu_Keys_f (void);
+ void M_Menu_Quit_f (void);
+
+ void M_Menu_Credits( void );
+
+qboolean m_entersound; // play after drawing a frame, so caching
+ // won't disrupt the sound
+
+void (*m_drawfunc) (void);
+char *(*m_keyfunc) (int key);
+
+//=============================================================================
+/* Support Routines */
+
+#define MAX_MENU_DEPTH 8
+
+
+typedef struct
+{
+ void (*draw) (void);
+ char *(*key) (int k);
+} menulayer_t;
+
+menulayer_t m_layers[MAX_MENU_DEPTH];
+int m_menudepth;
+
+static void M_Banner( char *name )
+{
+ int w, h;
+
+ re.DrawGetPicSize (&w, &h, name );
+ re.DrawPic( vid.width / 2 - w / 2, vid.height / 2 - 110, name );
+}
+
+void M_PushMenu ( void (*draw) (void), char *(*key) (int k) )
+{
+ int i;
+
+ if (Cvar_VariableValue ("maxclients") == 1
+ && Com_ServerState ())
+ Cvar_Set ("paused", "1");
+
+ // if this menu is already present, drop back to that level
+ // to avoid stacking menus by hotkeys
+ for (i=0 ; i<m_menudepth ; i++)
+ if (m_layers[i].draw == draw &&
+ m_layers[i].key == key)
+ {
+ m_menudepth = i;
+ }
+
+ if (i == m_menudepth)
+ {
+ if (m_menudepth >= MAX_MENU_DEPTH)
+ Com_Error (ERR_FATAL, "M_PushMenu: MAX_MENU_DEPTH");
+ m_layers[m_menudepth].draw = m_drawfunc;
+ m_layers[m_menudepth].key = m_keyfunc;
+ m_menudepth++;
+ }
+
+ m_drawfunc = draw;
+ m_keyfunc = key;
+
+ m_entersound = true;
+
+ cls.key_dest = key_menu;
+}
+
+void M_ForceMenuOff (void)
+{
+ m_drawfunc = 0;
+ m_keyfunc = 0;
+ cls.key_dest = key_game;
+ m_menudepth = 0;
+ Key_ClearStates ();
+ Cvar_Set ("paused", "0");
+ IN_Grabm (1);
+}
+
+void M_PopMenu (void)
+{
+ S_StartLocalSound( menu_out_sound );
+ if (m_menudepth < 1)
+ Com_Error (ERR_FATAL, "M_PopMenu: depth < 1");
+ m_menudepth--;
+
+ m_drawfunc = m_layers[m_menudepth].draw;
+ m_keyfunc = m_layers[m_menudepth].key;
+
+ if (!m_menudepth)
+ M_ForceMenuOff ();
+}
+
+
+char *Default_MenuKey( menuframework_t *m, int key )
+{
+ char *sound = nil;
+ menucommon_t *item;
+
+ if ( m )
+ {
+ if ( ( item = Menu_ItemAtCursor( m ) ) != 0 )
+ {
+ if ( item->type == MTYPE_FIELD )
+ {
+ if ( Field_Key( ( menufield_t * ) item, key ) )
+ return NULL;
+ }
+ }
+ }
+
+ switch ( key )
+ {
+ case K_ESCAPE:
+ M_PopMenu();
+ return menu_out_sound;
+ case K_KP_UPARROW:
+ case K_UPARROW:
+ if ( m )
+ {
+ m->cursor--;
+ Menu_AdjustCursor( m, -1 );
+ sound = menu_move_sound;
+ }
+ break;
+ case K_TAB:
+ if ( m )
+ {
+ m->cursor++;
+ Menu_AdjustCursor( m, 1 );
+ sound = menu_move_sound;
+ }
+ break;
+ case K_KP_DOWNARROW:
+ case K_DOWNARROW:
+ if ( m )
+ {
+ m->cursor++;
+ Menu_AdjustCursor( m, 1 );
+ sound = menu_move_sound;
+ }
+ break;
+ case K_KP_LEFTARROW:
+ case K_LEFTARROW:
+ if ( m )
+ {
+ Menu_SlideItem( m, -1 );
+ sound = menu_move_sound;
+ }
+ break;
+ case K_KP_RIGHTARROW:
+ case K_RIGHTARROW:
+ if ( m )
+ {
+ Menu_SlideItem( m, 1 );
+ sound = menu_move_sound;
+ }
+ break;
+
+ case K_MOUSE1:
+ case K_MOUSE2:
+ case K_MOUSE3:
+ case K_JOY1:
+ case K_JOY2:
+ case K_JOY3:
+ case K_JOY4:
+ case K_AUX1:
+ case K_AUX2:
+ case K_AUX3:
+ case K_AUX4:
+ case K_AUX5:
+ case K_AUX6:
+ case K_AUX7:
+ case K_AUX8:
+ case K_AUX9:
+ case K_AUX10:
+ case K_AUX11:
+ case K_AUX12:
+ case K_AUX13:
+ case K_AUX14:
+ case K_AUX15:
+ case K_AUX16:
+ case K_AUX17:
+ case K_AUX18:
+ case K_AUX19:
+ case K_AUX20:
+ case K_AUX21:
+ case K_AUX22:
+ case K_AUX23:
+ case K_AUX24:
+ case K_AUX25:
+ case K_AUX26:
+ case K_AUX27:
+ case K_AUX28:
+ case K_AUX29:
+ case K_AUX30:
+ case K_AUX31:
+ case K_AUX32:
+
+ case K_KP_ENTER:
+ case K_ENTER:
+ if ( m )
+ Menu_SelectItem( m );
+ sound = menu_move_sound;
+ break;
+ }
+
+ return sound;
+}
+
+//=============================================================================
+
+/*
+================
+M_DrawCharacter
+
+Draws one solid graphics character
+cx and cy are in 320*240 coordinates, and will be centered on
+higher res screens.
+================
+*/
+void M_DrawCharacter (int cx, int cy, int num)
+{
+ re.DrawChar ( cx + ((vid.width - 320)>>1), cy + ((vid.height - 240)>>1), num);
+}
+
+void M_Print (int cx, int cy, char *str)
+{
+ while (*str)
+ {
+ M_DrawCharacter (cx, cy, (*str)+128);
+ str++;
+ cx += 8;
+ }
+}
+
+void M_PrintWhite (int cx, int cy, char *str)
+{
+ while (*str)
+ {
+ M_DrawCharacter (cx, cy, *str);
+ str++;
+ cx += 8;
+ }
+}
+
+void M_DrawPic (int x, int y, char *pic)
+{
+ re.DrawPic (x + ((vid.width - 320)>>1), y + ((vid.height - 240)>>1), pic);
+}
+
+
+/*
+=============
+M_DrawCursor
+
+Draws an animating cursor with the point at
+x,y. The pic will extend to the left of x,
+and both above and below y.
+=============
+*/
+void M_DrawCursor( int x, int y, int f )
+{
+ char cursorname[80];
+ static qboolean cached;
+
+ if ( !cached )
+ {
+ int i;
+
+ for ( i = 0; i < NUM_CURSOR_FRAMES; i++ )
+ {
+ Com_sprintf( cursorname, sizeof( cursorname ), "m_cursor%d", i );
+
+ re.RegisterPic( cursorname );
+ }
+ cached = true;
+ }
+
+ Com_sprintf( cursorname, sizeof(cursorname), "m_cursor%d", f );
+ re.DrawPic( x, y, cursorname );
+}
+
+void M_DrawTextBox (int x, int y, int width, int lines)
+{
+ int cx, cy;
+ int n;
+
+ // draw left side
+ cx = x;
+ cy = y;
+ M_DrawCharacter (cx, cy, 1);
+ for (n = 0; n < lines; n++)
+ {
+ cy += 8;
+ M_DrawCharacter (cx, cy, 4);
+ }
+ M_DrawCharacter (cx, cy+8, 7);
+
+ // draw middle
+ cx += 8;
+ while (width > 0)
+ {
+ cy = y;
+ M_DrawCharacter (cx, cy, 2);
+ for (n = 0; n < lines; n++)
+ {
+ cy += 8;
+ M_DrawCharacter (cx, cy, 5);
+ }
+ M_DrawCharacter (cx, cy+8, 8);
+ width -= 1;
+ cx += 8;
+ }
+
+ // draw right side
+ cy = y;
+ M_DrawCharacter (cx, cy, 3);
+ for (n = 0; n < lines; n++)
+ {
+ cy += 8;
+ M_DrawCharacter (cx, cy, 6);
+ }
+ M_DrawCharacter (cx, cy+8, 9);
+}
+
+
+/*
+=======================================================================
+
+MAIN MENU
+
+=======================================================================
+*/
+#define MAIN_ITEMS 5
+
+
+void M_Main_Draw (void)
+{
+ int i;
+ int w, h;
+ int ystart;
+ int xoffset;
+ int widest = -1;
+ int totalheight = 0;
+ char litname[80];
+ char *names[] =
+ {
+ "m_main_game",
+ "m_main_multiplayer",
+ "m_main_options",
+ "m_main_video",
+ "m_main_quit",
+ 0
+ };
+
+ for ( i = 0; names[i] != 0; i++ )
+ {
+ re.DrawGetPicSize( &w, &h, names[i] );
+
+ if ( w > widest )
+ widest = w;
+ totalheight += ( h + 12 );
+ }
+
+ ystart = ( vid.height / 2 - 110 );
+ xoffset = ( vid.width - widest + 70 ) / 2;
+
+ for ( i = 0; names[i] != 0; i++ )
+ {
+ if ( i != m_main_cursor )
+ re.DrawPic( xoffset, ystart + i * 40 + 13, names[i] );
+ }
+ strcpy( litname, names[m_main_cursor] );
+ strcat( litname, "_sel" );
+ re.DrawPic( xoffset, ystart + m_main_cursor * 40 + 13, litname );
+
+ M_DrawCursor( xoffset - 25, ystart + m_main_cursor * 40 + 11, (int)(cls.realtime / 100)%NUM_CURSOR_FRAMES );
+
+ re.DrawGetPicSize( &w, &h, "m_main_plaque" );
+ re.DrawPic( xoffset - 30 - w, ystart, "m_main_plaque" );
+
+ re.DrawPic( xoffset - 30 - w, ystart + h + 5, "m_main_logo" );
+}
+
+
+char *M_Main_Key (int key)
+{
+ char *sound = menu_move_sound;
+
+ switch (key)
+ {
+ case K_ESCAPE:
+ M_PopMenu ();
+ break;
+
+ case K_KP_DOWNARROW:
+ case K_DOWNARROW:
+ if (++m_main_cursor >= MAIN_ITEMS)
+ m_main_cursor = 0;
+ return sound;
+
+ case K_KP_UPARROW:
+ case K_UPARROW:
+ if (--m_main_cursor < 0)
+ m_main_cursor = MAIN_ITEMS - 1;
+ return sound;
+
+ case K_KP_ENTER:
+ case K_ENTER:
+ m_entersound = true;
+
+ switch (m_main_cursor)
+ {
+ case 0:
+ M_Menu_Game_f ();
+ break;
+
+ case 1:
+ M_Menu_Multiplayer_f();
+ break;
+
+ case 2:
+ M_Menu_Options_f ();
+ break;
+
+ case 3:
+ M_Menu_Video_f ();
+ break;
+
+ case 4:
+ M_Menu_Quit_f ();
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+
+void M_Menu_Main_f (void)
+{
+ IN_Grabm (0);
+ M_PushMenu (M_Main_Draw, M_Main_Key);
+}
+
+/*
+=======================================================================
+
+MULTIPLAYER MENU
+
+=======================================================================
+*/
+static menuframework_t s_multiplayer_menu;
+static menuaction_t s_join_network_server_action;
+static menuaction_t s_start_network_server_action;
+static menuaction_t s_player_setup_action;
+
+static void Multiplayer_MenuDraw (void)
+{
+ M_Banner( "m_banner_multiplayer" );
+
+ Menu_AdjustCursor( &s_multiplayer_menu, 1 );
+ Menu_Draw( &s_multiplayer_menu );
+}
+
+static void PlayerSetupFunc( void * )
+{
+ M_Menu_PlayerConfig_f();
+}
+
+static void JoinNetworkServerFunc( void * )
+{
+ M_Menu_JoinServer_f();
+}
+
+static void StartNetworkServerFunc( void * )
+{
+ M_Menu_StartServer_f ();
+}
+
+void Multiplayer_MenuInit( void )
+{
+ s_multiplayer_menu.x = vid.width * 0.50 - 64;
+ s_multiplayer_menu.nitems = 0;
+
+ s_join_network_server_action.generic.type = MTYPE_ACTION;
+ s_join_network_server_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_join_network_server_action.generic.x = 0;
+ s_join_network_server_action.generic.y = 0;
+ s_join_network_server_action.generic.name = " join network server";
+ s_join_network_server_action.generic.callback = JoinNetworkServerFunc;
+
+ s_start_network_server_action.generic.type = MTYPE_ACTION;
+ s_start_network_server_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_start_network_server_action.generic.x = 0;
+ s_start_network_server_action.generic.y = 10;
+ s_start_network_server_action.generic.name = " start network server";
+ s_start_network_server_action.generic.callback = StartNetworkServerFunc;
+
+ s_player_setup_action.generic.type = MTYPE_ACTION;
+ s_player_setup_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_player_setup_action.generic.x = 0;
+ s_player_setup_action.generic.y = 20;
+ s_player_setup_action.generic.name = " player setup";
+ s_player_setup_action.generic.callback = PlayerSetupFunc;
+
+ Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_join_network_server_action );
+ Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_start_network_server_action );
+ Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_player_setup_action );
+
+ Menu_SetStatusBar( &s_multiplayer_menu, NULL );
+
+ Menu_Center( &s_multiplayer_menu );
+}
+
+char *Multiplayer_MenuKey( int key )
+{
+ return Default_MenuKey( &s_multiplayer_menu, key );
+}
+
+void M_Menu_Multiplayer_f( void )
+{
+ Multiplayer_MenuInit();
+ M_PushMenu( Multiplayer_MenuDraw, Multiplayer_MenuKey );
+}
+
+/*
+=======================================================================
+
+KEYS MENU
+
+=======================================================================
+*/
+char *bindnames[][2] =
+{
+{"+attack", "attack"},
+{"weapnext", "next weapon"},
+{"+forward", "walk forward"},
+{"+back", "backpedal"},
+{"+left", "turn left"},
+{"+right", "turn right"},
+{"+speed", "run"},
+{"+moveleft", "step left"},
+{"+moveright", "step right"},
+{"+strafe", "sidestep"},
+{"+lookup", "look up"},
+{"+lookdown", "look down"},
+{"centerview", "center view"},
+{"+mlook", "mouse look"},
+{"+klook", "keyboard look"},
+{"+moveup", "up / jump"},
+{"+movedown", "down / crouch"},
+
+{"inven", "inventory"},
+{"invuse", "use item"},
+{"invdrop", "drop item"},
+{"invprev", "prev item"},
+{"invnext", "next item"},
+
+{"cmd help", "help computer" },
+{ 0, 0 }
+};
+
+int keys_cursor;
+static int bind_grab;
+
+static menuframework_t s_keys_menu;
+static menuaction_t s_keys_attack_action;
+static menuaction_t s_keys_change_weapon_action;
+static menuaction_t s_keys_walk_forward_action;
+static menuaction_t s_keys_backpedal_action;
+static menuaction_t s_keys_turn_left_action;
+static menuaction_t s_keys_turn_right_action;
+static menuaction_t s_keys_run_action;
+static menuaction_t s_keys_step_left_action;
+static menuaction_t s_keys_step_right_action;
+static menuaction_t s_keys_sidestep_action;
+static menuaction_t s_keys_look_up_action;
+static menuaction_t s_keys_look_down_action;
+static menuaction_t s_keys_center_view_action;
+static menuaction_t s_keys_mouse_look_action;
+static menuaction_t s_keys_keyboard_look_action;
+static menuaction_t s_keys_move_up_action;
+static menuaction_t s_keys_move_down_action;
+static menuaction_t s_keys_inventory_action;
+static menuaction_t s_keys_inv_use_action;
+static menuaction_t s_keys_inv_drop_action;
+static menuaction_t s_keys_inv_prev_action;
+static menuaction_t s_keys_inv_next_action;
+
+static menuaction_t s_keys_help_computer_action;
+
+static void M_UnbindCommand (char *command)
+{
+ int j;
+ int l;
+ char *b;
+
+ l = strlen(command);
+
+ for (j=0 ; j<256 ; j++)
+ {
+ b = keybindings[j];
+ if (!b)
+ continue;
+ if (!strncmp (b, command, l) )
+ Key_SetBinding (j, "");
+ }
+}
+
+static void M_FindKeysForCommand (char *command, int *twokeys)
+{
+ int count;
+ int j;
+ int l;
+ char *b;
+
+ twokeys[0] = twokeys[1] = -1;
+ l = strlen(command);
+ count = 0;
+
+ for (j=0 ; j<256 ; j++)
+ {
+ b = keybindings[j];
+ if (!b)
+ continue;
+ if (!strncmp (b, command, l) )
+ {
+ twokeys[count] = j;
+ count++;
+ if (count == 2)
+ break;
+ }
+ }
+}
+
+static void KeyCursorDrawFunc( menuframework_t *menu )
+{
+ if ( bind_grab )
+ re.DrawChar( menu->x, menu->y + menu->cursor * 9, '=' );
+ else
+ re.DrawChar( menu->x, menu->y + menu->cursor * 9, 12 + ( ( int ) ( Sys_Milliseconds() / 250 ) & 1 ) );
+}
+
+static void DrawKeyBindingFunc( void *self )
+{
+ int keys[2];
+ menuaction_t *a = ( menuaction_t * ) self;
+
+ M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys);
+
+ if (keys[0] == -1)
+ {
+ Menu_DrawString( a->generic.x + a->generic.parent->x + 16, a->generic.y + a->generic.parent->y, "???" );
+ }
+ else
+ {
+ int x;
+ char *name;
+
+ name = Key_KeynumToString (keys[0]);
+
+ Menu_DrawString( a->generic.x + a->generic.parent->x + 16, a->generic.y + a->generic.parent->y, name );
+
+ x = strlen(name) * 8;
+
+ if (keys[1] != -1)
+ {
+ Menu_DrawString( a->generic.x + a->generic.parent->x + 24 + x, a->generic.y + a->generic.parent->y, "or" );
+ Menu_DrawString( a->generic.x + a->generic.parent->x + 48 + x, a->generic.y + a->generic.parent->y, Key_KeynumToString (keys[1]) );
+ }
+ }
+}
+
+static void KeyBindingFunc( void *self )
+{
+ menuaction_t *a = ( menuaction_t * ) self;
+ int keys[2];
+
+ M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys );
+
+ if (keys[1] != -1)
+ M_UnbindCommand( bindnames[a->generic.localdata[0]][0]);
+
+ bind_grab = true;
+
+ Menu_SetStatusBar( &s_keys_menu, "press a key or button for this action" );
+}
+
+static void Keys_MenuInit( void )
+{
+ int y = 0;
+ int i = 0;
+
+ s_keys_menu.x = vid.width * 0.50;
+ s_keys_menu.nitems = 0;
+ s_keys_menu.cursordraw = KeyCursorDrawFunc;
+
+ s_keys_attack_action.generic.type = MTYPE_ACTION;
+ s_keys_attack_action.generic.flags = QMF_GRAYED;
+ s_keys_attack_action.generic.x = 0;
+ s_keys_attack_action.generic.y = y;
+ s_keys_attack_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_attack_action.generic.localdata[0] = i;
+ s_keys_attack_action.generic.name = bindnames[s_keys_attack_action.generic.localdata[0]][1];
+
+ s_keys_change_weapon_action.generic.type = MTYPE_ACTION;
+ s_keys_change_weapon_action.generic.flags = QMF_GRAYED;
+ s_keys_change_weapon_action.generic.x = 0;
+ s_keys_change_weapon_action.generic.y = y += 9;
+ s_keys_change_weapon_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_change_weapon_action.generic.localdata[0] = ++i;
+ s_keys_change_weapon_action.generic.name = bindnames[s_keys_change_weapon_action.generic.localdata[0]][1];
+
+ s_keys_walk_forward_action.generic.type = MTYPE_ACTION;
+ s_keys_walk_forward_action.generic.flags = QMF_GRAYED;
+ s_keys_walk_forward_action.generic.x = 0;
+ s_keys_walk_forward_action.generic.y = y += 9;
+ s_keys_walk_forward_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_walk_forward_action.generic.localdata[0] = ++i;
+ s_keys_walk_forward_action.generic.name = bindnames[s_keys_walk_forward_action.generic.localdata[0]][1];
+
+ s_keys_backpedal_action.generic.type = MTYPE_ACTION;
+ s_keys_backpedal_action.generic.flags = QMF_GRAYED;
+ s_keys_backpedal_action.generic.x = 0;
+ s_keys_backpedal_action.generic.y = y += 9;
+ s_keys_backpedal_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_backpedal_action.generic.localdata[0] = ++i;
+ s_keys_backpedal_action.generic.name = bindnames[s_keys_backpedal_action.generic.localdata[0]][1];
+
+ s_keys_turn_left_action.generic.type = MTYPE_ACTION;
+ s_keys_turn_left_action.generic.flags = QMF_GRAYED;
+ s_keys_turn_left_action.generic.x = 0;
+ s_keys_turn_left_action.generic.y = y += 9;
+ s_keys_turn_left_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_turn_left_action.generic.localdata[0] = ++i;
+ s_keys_turn_left_action.generic.name = bindnames[s_keys_turn_left_action.generic.localdata[0]][1];
+
+ s_keys_turn_right_action.generic.type = MTYPE_ACTION;
+ s_keys_turn_right_action.generic.flags = QMF_GRAYED;
+ s_keys_turn_right_action.generic.x = 0;
+ s_keys_turn_right_action.generic.y = y += 9;
+ s_keys_turn_right_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_turn_right_action.generic.localdata[0] = ++i;
+ s_keys_turn_right_action.generic.name = bindnames[s_keys_turn_right_action.generic.localdata[0]][1];
+
+ s_keys_run_action.generic.type = MTYPE_ACTION;
+ s_keys_run_action.generic.flags = QMF_GRAYED;
+ s_keys_run_action.generic.x = 0;
+ s_keys_run_action.generic.y = y += 9;
+ s_keys_run_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_run_action.generic.localdata[0] = ++i;
+ s_keys_run_action.generic.name = bindnames[s_keys_run_action.generic.localdata[0]][1];
+
+ s_keys_step_left_action.generic.type = MTYPE_ACTION;
+ s_keys_step_left_action.generic.flags = QMF_GRAYED;
+ s_keys_step_left_action.generic.x = 0;
+ s_keys_step_left_action.generic.y = y += 9;
+ s_keys_step_left_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_step_left_action.generic.localdata[0] = ++i;
+ s_keys_step_left_action.generic.name = bindnames[s_keys_step_left_action.generic.localdata[0]][1];
+
+ s_keys_step_right_action.generic.type = MTYPE_ACTION;
+ s_keys_step_right_action.generic.flags = QMF_GRAYED;
+ s_keys_step_right_action.generic.x = 0;
+ s_keys_step_right_action.generic.y = y += 9;
+ s_keys_step_right_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_step_right_action.generic.localdata[0] = ++i;
+ s_keys_step_right_action.generic.name = bindnames[s_keys_step_right_action.generic.localdata[0]][1];
+
+ s_keys_sidestep_action.generic.type = MTYPE_ACTION;
+ s_keys_sidestep_action.generic.flags = QMF_GRAYED;
+ s_keys_sidestep_action.generic.x = 0;
+ s_keys_sidestep_action.generic.y = y += 9;
+ s_keys_sidestep_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_sidestep_action.generic.localdata[0] = ++i;
+ s_keys_sidestep_action.generic.name = bindnames[s_keys_sidestep_action.generic.localdata[0]][1];
+
+ s_keys_look_up_action.generic.type = MTYPE_ACTION;
+ s_keys_look_up_action.generic.flags = QMF_GRAYED;
+ s_keys_look_up_action.generic.x = 0;
+ s_keys_look_up_action.generic.y = y += 9;
+ s_keys_look_up_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_look_up_action.generic.localdata[0] = ++i;
+ s_keys_look_up_action.generic.name = bindnames[s_keys_look_up_action.generic.localdata[0]][1];
+
+ s_keys_look_down_action.generic.type = MTYPE_ACTION;
+ s_keys_look_down_action.generic.flags = QMF_GRAYED;
+ s_keys_look_down_action.generic.x = 0;
+ s_keys_look_down_action.generic.y = y += 9;
+ s_keys_look_down_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_look_down_action.generic.localdata[0] = ++i;
+ s_keys_look_down_action.generic.name = bindnames[s_keys_look_down_action.generic.localdata[0]][1];
+
+ s_keys_center_view_action.generic.type = MTYPE_ACTION;
+ s_keys_center_view_action.generic.flags = QMF_GRAYED;
+ s_keys_center_view_action.generic.x = 0;
+ s_keys_center_view_action.generic.y = y += 9;
+ s_keys_center_view_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_center_view_action.generic.localdata[0] = ++i;
+ s_keys_center_view_action.generic.name = bindnames[s_keys_center_view_action.generic.localdata[0]][1];
+
+ s_keys_mouse_look_action.generic.type = MTYPE_ACTION;
+ s_keys_mouse_look_action.generic.flags = QMF_GRAYED;
+ s_keys_mouse_look_action.generic.x = 0;
+ s_keys_mouse_look_action.generic.y = y += 9;
+ s_keys_mouse_look_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_mouse_look_action.generic.localdata[0] = ++i;
+ s_keys_mouse_look_action.generic.name = bindnames[s_keys_mouse_look_action.generic.localdata[0]][1];
+
+ s_keys_keyboard_look_action.generic.type = MTYPE_ACTION;
+ s_keys_keyboard_look_action.generic.flags = QMF_GRAYED;
+ s_keys_keyboard_look_action.generic.x = 0;
+ s_keys_keyboard_look_action.generic.y = y += 9;
+ s_keys_keyboard_look_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_keyboard_look_action.generic.localdata[0] = ++i;
+ s_keys_keyboard_look_action.generic.name = bindnames[s_keys_keyboard_look_action.generic.localdata[0]][1];
+
+ s_keys_move_up_action.generic.type = MTYPE_ACTION;
+ s_keys_move_up_action.generic.flags = QMF_GRAYED;
+ s_keys_move_up_action.generic.x = 0;
+ s_keys_move_up_action.generic.y = y += 9;
+ s_keys_move_up_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_move_up_action.generic.localdata[0] = ++i;
+ s_keys_move_up_action.generic.name = bindnames[s_keys_move_up_action.generic.localdata[0]][1];
+
+ s_keys_move_down_action.generic.type = MTYPE_ACTION;
+ s_keys_move_down_action.generic.flags = QMF_GRAYED;
+ s_keys_move_down_action.generic.x = 0;
+ s_keys_move_down_action.generic.y = y += 9;
+ s_keys_move_down_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_move_down_action.generic.localdata[0] = ++i;
+ s_keys_move_down_action.generic.name = bindnames[s_keys_move_down_action.generic.localdata[0]][1];
+
+ s_keys_inventory_action.generic.type = MTYPE_ACTION;
+ s_keys_inventory_action.generic.flags = QMF_GRAYED;
+ s_keys_inventory_action.generic.x = 0;
+ s_keys_inventory_action.generic.y = y += 9;
+ s_keys_inventory_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_inventory_action.generic.localdata[0] = ++i;
+ s_keys_inventory_action.generic.name = bindnames[s_keys_inventory_action.generic.localdata[0]][1];
+
+ s_keys_inv_use_action.generic.type = MTYPE_ACTION;
+ s_keys_inv_use_action.generic.flags = QMF_GRAYED;
+ s_keys_inv_use_action.generic.x = 0;
+ s_keys_inv_use_action.generic.y = y += 9;
+ s_keys_inv_use_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_inv_use_action.generic.localdata[0] = ++i;
+ s_keys_inv_use_action.generic.name = bindnames[s_keys_inv_use_action.generic.localdata[0]][1];
+
+ s_keys_inv_drop_action.generic.type = MTYPE_ACTION;
+ s_keys_inv_drop_action.generic.flags = QMF_GRAYED;
+ s_keys_inv_drop_action.generic.x = 0;
+ s_keys_inv_drop_action.generic.y = y += 9;
+ s_keys_inv_drop_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_inv_drop_action.generic.localdata[0] = ++i;
+ s_keys_inv_drop_action.generic.name = bindnames[s_keys_inv_drop_action.generic.localdata[0]][1];
+
+ s_keys_inv_prev_action.generic.type = MTYPE_ACTION;
+ s_keys_inv_prev_action.generic.flags = QMF_GRAYED;
+ s_keys_inv_prev_action.generic.x = 0;
+ s_keys_inv_prev_action.generic.y = y += 9;
+ s_keys_inv_prev_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_inv_prev_action.generic.localdata[0] = ++i;
+ s_keys_inv_prev_action.generic.name = bindnames[s_keys_inv_prev_action.generic.localdata[0]][1];
+
+ s_keys_inv_next_action.generic.type = MTYPE_ACTION;
+ s_keys_inv_next_action.generic.flags = QMF_GRAYED;
+ s_keys_inv_next_action.generic.x = 0;
+ s_keys_inv_next_action.generic.y = y += 9;
+ s_keys_inv_next_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_inv_next_action.generic.localdata[0] = ++i;
+ s_keys_inv_next_action.generic.name = bindnames[s_keys_inv_next_action.generic.localdata[0]][1];
+
+ s_keys_help_computer_action.generic.type = MTYPE_ACTION;
+ s_keys_help_computer_action.generic.flags = QMF_GRAYED;
+ s_keys_help_computer_action.generic.x = 0;
+ s_keys_help_computer_action.generic.y = y += 9;
+ s_keys_help_computer_action.generic.ownerdraw = DrawKeyBindingFunc;
+ s_keys_help_computer_action.generic.localdata[0] = ++i;
+ s_keys_help_computer_action.generic.name = bindnames[s_keys_help_computer_action.generic.localdata[0]][1];
+
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_attack_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_change_weapon_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_walk_forward_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_backpedal_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_turn_left_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_turn_right_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_run_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_step_left_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_step_right_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_sidestep_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_look_up_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_look_down_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_center_view_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_mouse_look_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_keyboard_look_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_move_up_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_move_down_action );
+
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inventory_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_use_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_drop_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_prev_action );
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_next_action );
+
+ Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_help_computer_action );
+
+ Menu_SetStatusBar( &s_keys_menu, "enter to change, backspace to clear" );
+ Menu_Center( &s_keys_menu );
+}
+
+static void Keys_MenuDraw (void)
+{
+ Menu_AdjustCursor( &s_keys_menu, 1 );
+ Menu_Draw( &s_keys_menu );
+}
+
+static char *Keys_MenuKey( int key )
+{
+ menuaction_t *item = ( menuaction_t * ) Menu_ItemAtCursor( &s_keys_menu );
+
+ if ( bind_grab )
+ {
+ if ( key != K_ESCAPE && key != '`' )
+ {
+ char cmd[1024];
+
+ Com_sprintf (cmd, sizeof(cmd), "bind \"%s\" \"%s\"\n", Key_KeynumToString(key), bindnames[item->generic.localdata[0]][0]);
+ Cbuf_InsertText (cmd);
+ }
+
+ Menu_SetStatusBar( &s_keys_menu, "enter to change, backspace to clear" );
+ bind_grab = false;
+ return menu_out_sound;
+ }
+
+ switch ( key )
+ {
+ case K_KP_ENTER:
+ case K_ENTER:
+ KeyBindingFunc( item );
+ return menu_in_sound;
+ case K_BACKSPACE: // delete bindings
+ case K_DEL: // delete bindings
+ case K_KP_DEL:
+ M_UnbindCommand( bindnames[item->generic.localdata[0]][0] );
+ return menu_out_sound;
+ default:
+ return Default_MenuKey( &s_keys_menu, key );
+ }
+}
+
+void M_Menu_Keys_f (void)
+{
+ Keys_MenuInit();
+ M_PushMenu( Keys_MenuDraw, Keys_MenuKey );
+}
+
+
+/*
+=======================================================================
+
+CONTROLS MENU
+
+=======================================================================
+*/
+static cvar_t *win_noalttab;
+
+static menuframework_t s_options_menu;
+static menuaction_t s_options_defaults_action;
+static menuaction_t s_options_customize_options_action;
+static menuslider_t s_options_sensitivity_slider;
+static menulist_t s_options_freelook_box;
+static menulist_t s_options_noalttab_box;
+static menulist_t s_options_alwaysrun_box;
+static menulist_t s_options_invertmouse_box;
+static menulist_t s_options_lookspring_box;
+static menulist_t s_options_lookstrafe_box;
+static menulist_t s_options_crosshair_box;
+static menuslider_t s_options_sfxvolume_slider;
+static menulist_t s_options_joystick_box;
+static menulist_t s_options_cdvolume_box;
+static menulist_t s_options_quality_list;
+static menulist_t s_options_compatibility_list;
+static menulist_t s_options_console_action;
+
+static void CrosshairFunc( void * )
+{
+ Cvar_SetValue( "crosshair", s_options_crosshair_box.curvalue );
+}
+
+static void JoystickFunc( void * )
+{
+ Cvar_SetValue( "in_joystick", s_options_joystick_box.curvalue );
+}
+
+static void CustomizeControlsFunc( void * )
+{
+ M_Menu_Keys_f();
+}
+
+static void AlwaysRunFunc( void * )
+{
+ Cvar_SetValue( "cl_run", s_options_alwaysrun_box.curvalue );
+}
+
+static void FreeLookFunc( void * )
+{
+ Cvar_SetValue( "freelook", s_options_freelook_box.curvalue );
+}
+
+static void MouseSpeedFunc( void * )
+{
+ Cvar_SetValue( "sensitivity", s_options_sensitivity_slider.curvalue / 2.0F );
+}
+
+static void NoAltTabFunc( void * )
+{
+ Cvar_SetValue( "win_noalttab", s_options_noalttab_box.curvalue );
+}
+
+static float ClampCvar( float min, float max, float value )
+{
+ if ( value < min ) return min;
+ if ( value > max ) return max;
+ return value;
+}
+
+static void ControlsSetMenuItemValues( void )
+{
+ s_options_sfxvolume_slider.curvalue = Cvar_VariableValue( "s_volume" ) * 10;
+ s_options_cdvolume_box.curvalue = !Cvar_VariableValue("cd_nocd");
+ s_options_quality_list.curvalue = !Cvar_VariableValue( "s_loadas8bit" );
+ s_options_sensitivity_slider.curvalue = ( sensitivity->value ) * 2;
+
+ Cvar_SetValue( "cl_run", ClampCvar( 0, 1, cl_run->value ) );
+ s_options_alwaysrun_box.curvalue = cl_run->value;
+
+ s_options_invertmouse_box.curvalue = m_pitch->value < 0;
+
+ Cvar_SetValue( "lookspring", ClampCvar( 0, 1, lookspring->value ) );
+ s_options_lookspring_box.curvalue = lookspring->value;
+
+ Cvar_SetValue( "lookstrafe", ClampCvar( 0, 1, lookstrafe->value ) );
+ s_options_lookstrafe_box.curvalue = lookstrafe->value;
+
+ Cvar_SetValue( "freelook", ClampCvar( 0, 1, freelook->value ) );
+ s_options_freelook_box.curvalue = freelook->value;
+
+ Cvar_SetValue( "crosshair", ClampCvar( 0, 3, crosshair->value ) );
+ s_options_crosshair_box.curvalue = crosshair->value;
+
+ Cvar_SetValue( "in_joystick", ClampCvar( 0, 1, in_joystick->value ) );
+ s_options_joystick_box.curvalue = in_joystick->value;
+
+ s_options_noalttab_box.curvalue = win_noalttab->value;
+}
+
+static void ControlsResetDefaultsFunc( void * )
+{
+ Cbuf_AddText ("exec default.cfg\n");
+ Cbuf_Execute();
+
+ ControlsSetMenuItemValues();
+}
+
+static void InvertMouseFunc( void * )
+{
+ if ( s_options_invertmouse_box.curvalue == 0 )
+ {
+ Cvar_SetValue( "m_pitch", fabs( m_pitch->value ) );
+ }
+ else
+ {
+ Cvar_SetValue( "m_pitch", -fabs( m_pitch->value ) );
+ }
+}
+
+static void LookspringFunc( void * )
+{
+ Cvar_SetValue( "lookspring", s_options_lookspring_box.curvalue );
+}
+
+static void LookstrafeFunc( void * )
+{
+ Cvar_SetValue( "lookstrafe", s_options_lookstrafe_box.curvalue );
+}
+
+static void UpdateVolumeFunc( void * )
+{
+ Cvar_SetValue( "s_volume", s_options_sfxvolume_slider.curvalue / 10 );
+}
+
+static void UpdateCDVolumeFunc( void * )
+{
+ Cvar_SetValue( "cd_nocd", !s_options_cdvolume_box.curvalue );
+}
+
+static void ConsoleFunc( void * )
+{
+ /*
+ ** the proper way to do this is probably to have ToggleConsole_f accept a parameter
+ */
+ extern void Key_ClearTyping( void );
+
+ if ( cl.attractloop )
+ {
+ Cbuf_AddText ("killserver\n");
+ return;
+ }
+
+ Key_ClearTyping ();
+ Con_ClearNotify ();
+
+ M_ForceMenuOff ();
+ cls.key_dest = key_console;
+}
+
+static void UpdateSoundQualityFunc( void * )
+{
+ if ( s_options_quality_list.curvalue )
+ {
+ Cvar_SetValue( "s_khz", 22 );
+ Cvar_SetValue( "s_loadas8bit", false );
+ }
+ else
+ {
+ Cvar_SetValue( "s_khz", 11 );
+ Cvar_SetValue( "s_loadas8bit", true );
+ }
+
+ Cvar_SetValue( "s_primary", s_options_compatibility_list.curvalue );
+
+ M_DrawTextBox( 8, 120 - 48, 36, 3 );
+ M_Print( 16 + 16, 120 - 48 + 8, "Restarting the sound system. This" );
+ M_Print( 16 + 16, 120 - 48 + 16, "could take up to a minute, so" );
+ M_Print( 16 + 16, 120 - 48 + 24, "please be patient." );
+
+ // the text box won't show up unless we do a buffer swap
+ re.EndFrame();
+
+ CL_Snd_Restart_f();
+}
+
+void Options_MenuInit( void )
+{
+ static char *cd_music_items[] =
+ {
+ "disabled",
+ "enabled",
+ 0
+ };
+ static char *quality_items[] =
+ {
+ "low", "high", 0
+ };
+
+ static char *compatibility_items[] =
+ {
+ "max compatibility", "max performance", 0
+ };
+
+ static char *yesno_names[] =
+ {
+ "no",
+ "yes",
+ 0
+ };
+
+ static char *crosshair_names[] =
+ {
+ "none",
+ "cross",
+ "dot",
+ "angle",
+ 0
+ };
+
+ win_noalttab = Cvar_Get( "win_noalttab", "0", CVAR_ARCHIVE );
+
+ /*
+ ** configure controls menu and menu items
+ */
+ s_options_menu.x = vid.width / 2;
+ s_options_menu.y = vid.height / 2 - 58;
+ s_options_menu.nitems = 0;
+
+ s_options_sfxvolume_slider.generic.type = MTYPE_SLIDER;
+ s_options_sfxvolume_slider.generic.x = 0;
+ s_options_sfxvolume_slider.generic.y = 0;
+ s_options_sfxvolume_slider.generic.name = "effects volume";
+ s_options_sfxvolume_slider.generic.callback = UpdateVolumeFunc;
+ s_options_sfxvolume_slider.minvalue = 0;
+ s_options_sfxvolume_slider.maxvalue = 10;
+ s_options_sfxvolume_slider.curvalue = Cvar_VariableValue( "s_volume" ) * 10;
+
+ s_options_cdvolume_box.generic.type = MTYPE_SPINCONTROL;
+ s_options_cdvolume_box.generic.x = 0;
+ s_options_cdvolume_box.generic.y = 10;
+ s_options_cdvolume_box.generic.name = "CD music";
+ s_options_cdvolume_box.generic.callback = UpdateCDVolumeFunc;
+ s_options_cdvolume_box.itemnames = cd_music_items;
+ s_options_cdvolume_box.curvalue = !Cvar_VariableValue("cd_nocd");
+
+ s_options_quality_list.generic.type = MTYPE_SPINCONTROL;
+ s_options_quality_list.generic.x = 0;
+ s_options_quality_list.generic.y = 20;;
+ s_options_quality_list.generic.name = "sound quality";
+ s_options_quality_list.generic.callback = UpdateSoundQualityFunc;
+ s_options_quality_list.itemnames = quality_items;
+ s_options_quality_list.curvalue = !Cvar_VariableValue( "s_loadas8bit" );
+
+ s_options_compatibility_list.generic.type = MTYPE_SPINCONTROL;
+ s_options_compatibility_list.generic.x = 0;
+ s_options_compatibility_list.generic.y = 30;
+ s_options_compatibility_list.generic.name = "sound compatibility";
+ s_options_compatibility_list.generic.callback = UpdateSoundQualityFunc;
+ s_options_compatibility_list.itemnames = compatibility_items;
+ s_options_compatibility_list.curvalue = Cvar_VariableValue( "s_primary" );
+
+ s_options_sensitivity_slider.generic.type = MTYPE_SLIDER;
+ s_options_sensitivity_slider.generic.x = 0;
+ s_options_sensitivity_slider.generic.y = 50;
+ s_options_sensitivity_slider.generic.name = "mouse speed";
+ s_options_sensitivity_slider.generic.callback = MouseSpeedFunc;
+ s_options_sensitivity_slider.minvalue = 2;
+ s_options_sensitivity_slider.maxvalue = 22;
+
+ s_options_alwaysrun_box.generic.type = MTYPE_SPINCONTROL;
+ s_options_alwaysrun_box.generic.x = 0;
+ s_options_alwaysrun_box.generic.y = 60;
+ s_options_alwaysrun_box.generic.name = "always run";
+ s_options_alwaysrun_box.generic.callback = AlwaysRunFunc;
+ s_options_alwaysrun_box.itemnames = yesno_names;
+
+ s_options_invertmouse_box.generic.type = MTYPE_SPINCONTROL;
+ s_options_invertmouse_box.generic.x = 0;
+ s_options_invertmouse_box.generic.y = 70;
+ s_options_invertmouse_box.generic.name = "invert mouse";
+ s_options_invertmouse_box.generic.callback = InvertMouseFunc;
+ s_options_invertmouse_box.itemnames = yesno_names;
+
+ s_options_lookspring_box.generic.type = MTYPE_SPINCONTROL;
+ s_options_lookspring_box.generic.x = 0;
+ s_options_lookspring_box.generic.y = 80;
+ s_options_lookspring_box.generic.name = "lookspring";
+ s_options_lookspring_box.generic.callback = LookspringFunc;
+ s_options_lookspring_box.itemnames = yesno_names;
+
+ s_options_lookstrafe_box.generic.type = MTYPE_SPINCONTROL;
+ s_options_lookstrafe_box.generic.x = 0;
+ s_options_lookstrafe_box.generic.y = 90;
+ s_options_lookstrafe_box.generic.name = "lookstrafe";
+ s_options_lookstrafe_box.generic.callback = LookstrafeFunc;
+ s_options_lookstrafe_box.itemnames = yesno_names;
+
+ s_options_freelook_box.generic.type = MTYPE_SPINCONTROL;
+ s_options_freelook_box.generic.x = 0;
+ s_options_freelook_box.generic.y = 100;
+ s_options_freelook_box.generic.name = "free look";
+ s_options_freelook_box.generic.callback = FreeLookFunc;
+ s_options_freelook_box.itemnames = yesno_names;
+
+ s_options_crosshair_box.generic.type = MTYPE_SPINCONTROL;
+ s_options_crosshair_box.generic.x = 0;
+ s_options_crosshair_box.generic.y = 110;
+ s_options_crosshair_box.generic.name = "crosshair";
+ s_options_crosshair_box.generic.callback = CrosshairFunc;
+ s_options_crosshair_box.itemnames = crosshair_names;
+/*
+ s_options_noalttab_box.generic.type = MTYPE_SPINCONTROL;
+ s_options_noalttab_box.generic.x = 0;
+ s_options_noalttab_box.generic.y = 110;
+ s_options_noalttab_box.generic.name = "disable alt-tab";
+ s_options_noalttab_box.generic.callback = NoAltTabFunc;
+ s_options_noalttab_box.itemnames = yesno_names;
+*/
+ s_options_joystick_box.generic.type = MTYPE_SPINCONTROL;
+ s_options_joystick_box.generic.x = 0;
+ s_options_joystick_box.generic.y = 120;
+ s_options_joystick_box.generic.name = "use joystick";
+ s_options_joystick_box.generic.callback = JoystickFunc;
+ s_options_joystick_box.itemnames = yesno_names;
+
+ s_options_customize_options_action.generic.type = MTYPE_ACTION;
+ s_options_customize_options_action.generic.x = 0;
+ s_options_customize_options_action.generic.y = 140;
+ s_options_customize_options_action.generic.name = "customize controls";
+ s_options_customize_options_action.generic.callback = CustomizeControlsFunc;
+
+ s_options_defaults_action.generic.type = MTYPE_ACTION;
+ s_options_defaults_action.generic.x = 0;
+ s_options_defaults_action.generic.y = 150;
+ s_options_defaults_action.generic.name = "reset defaults";
+ s_options_defaults_action.generic.callback = ControlsResetDefaultsFunc;
+
+ s_options_console_action.generic.type = MTYPE_ACTION;
+ s_options_console_action.generic.x = 0;
+ s_options_console_action.generic.y = 160;
+ s_options_console_action.generic.name = "go to console";
+ s_options_console_action.generic.callback = ConsoleFunc;
+
+ ControlsSetMenuItemValues();
+
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_sfxvolume_slider );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_cdvolume_box );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_quality_list );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_compatibility_list );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_sensitivity_slider );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_alwaysrun_box );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_invertmouse_box );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_lookspring_box );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_lookstrafe_box );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_freelook_box );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_crosshair_box );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_joystick_box );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_customize_options_action );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_defaults_action );
+ Menu_AddItem( &s_options_menu, ( void * ) &s_options_console_action );
+}
+
+void Options_MenuDraw (void)
+{
+ M_Banner( "m_banner_options" );
+ Menu_AdjustCursor( &s_options_menu, 1 );
+ Menu_Draw( &s_options_menu );
+}
+
+char *Options_MenuKey( int key )
+{
+ return Default_MenuKey( &s_options_menu, key );
+}
+
+void M_Menu_Options_f (void)
+{
+ Options_MenuInit();
+ M_PushMenu ( Options_MenuDraw, Options_MenuKey );
+}
+
+/*
+=======================================================================
+
+VIDEO MENU
+
+=======================================================================
+*/
+
+void M_Menu_Video_f (void)
+{
+ VID_MenuInit();
+ M_PushMenu( VID_MenuDraw, VID_MenuKey );
+}
+
+/*
+=============================================================================
+
+END GAME MENU
+
+=============================================================================
+*/
+static int credits_start_time;
+static char **credits;
+static char *creditsIndex[256];
+static char *creditsBuffer;
+static char *idcredits[] =
+{
+ "+QUAKE II BY ID SOFTWARE",
+ "",
+ "+PROGRAMMING",
+ "John Carmack",
+ "John Cash",
+ "Brian Hook",
+ "",
+ "+ART",
+ "Adrian Carmack",
+ "Kevin Cloud",
+ "Paul Steed",
+ "",
+ "+LEVEL DESIGN",
+ "Tim Willits",
+ "American McGee",
+ "Christian Antkow",
+ "Paul Jaquays",
+ "Brandon James",
+ "",
+ "+BIZ",
+ "Todd Hollenshead",
+ "Barrett (Bear) Alexander",
+ "Donna Jackson",
+ "",
+ "",
+ "+SPECIAL THANKS",
+ "Ben Donges for beta testing",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "+ADDITIONAL SUPPORT",
+ "",
+ "+LINUX PORT AND CTF",
+ "Dave \"Zoid\" Kirsch",
+ "",
+ "+CINEMATIC SEQUENCES",
+ "Ending Cinematic by Blur Studio - ",
+ "Venice, CA",
+ "",
+ "Environment models for Introduction",
+ "Cinematic by Karl Dolgener",
+ "",
+ "Assistance with environment design",
+ "by Cliff Iwai",
+ "",
+ "+SOUND EFFECTS AND MUSIC",
+ "Sound Design by Soundelux Media Labs.",
+ "Music Composed and Produced by",
+ "Soundelux Media Labs. Special thanks",
+ "to Bill Brown, Tom Ozanich, Brian",
+ "Celano, Jeff Eisner, and The Soundelux",
+ "Players.",
+ "",
+ "\"Level Music\" by Sonic Mayhem",
+ "www.sonicmayhem.com",
+ "",
+ "\"Quake II Theme Song\"",
+ "(C) 1997 Rob Zombie. All Rights",
+ "Reserved.",
+ "",
+ "Track 10 (\"Climb\") by Jer Sypult",
+ "",
+ "Voice of computers by",
+ "Carly Staehlin-Taylor",
+ "",
+ "+THANKS TO ACTIVISION",
+ "+IN PARTICULAR:",
+ "",
+ "John Tam",
+ "Steve Rosenthal",
+ "Marty Stratton",
+ "Henk Hartong",
+ "",
+ "Quake II(tm) (C)1997 Id Software, Inc.",
+ "All Rights Reserved. Distributed by",
+ "Activision, Inc. under license.",
+ "Quake II(tm), the Id Software name,",
+ "the \"Q II\"(tm) logo and id(tm)",
+ "logo are trademarks of Id Software,",
+ "Inc. Activision(R) is a registered",
+ "trademark of Activision, Inc. All",
+ "other trademarks and trade names are",
+ "properties of their respective owners.",
+ 0
+};
+
+static char *xatcredits[] =
+{
+ "+QUAKE II MISSION PACK: THE RECKONING",
+ "+BY",
+ "+XATRIX ENTERTAINMENT, INC.",
+ "",
+ "+DESIGN AND DIRECTION",
+ "Drew Markham",
+ "",
+ "+PRODUCED BY",
+ "Greg Goodrich",
+ "",
+ "+PROGRAMMING",
+ "Rafael Paiz",
+ "",
+ "+LEVEL DESIGN / ADDITIONAL GAME DESIGN",
+ "Alex Mayberry",
+ "",
+ "+LEVEL DESIGN",
+ "Mal Blackwell",
+ "Dan Koppel",
+ "",
+ "+ART DIRECTION",
+ "Michael \"Maxx\" Kaufman",
+ "",
+ "+COMPUTER GRAPHICS SUPERVISOR AND",
+ "+CHARACTER ANIMATION DIRECTION",
+ "Barry Dempsey",
+ "",
+ "+SENIOR ANIMATOR AND MODELER",
+ "Jason Hoover",
+ "",
+ "+CHARACTER ANIMATION AND",
+ "+MOTION CAPTURE SPECIALIST",
+ "Amit Doron",
+ "",
+ "+ART",
+ "Claire Praderie-Markham",
+ "Viktor Antonov",
+ "Corky Lehmkuhl",
+ "",
+ "+INTRODUCTION ANIMATION",
+ "Dominique Drozdz",
+ "",
+ "+ADDITIONAL LEVEL DESIGN",
+ "Aaron Barber",
+ "Rhett Baldwin",
+ "",
+ "+3D CHARACTER ANIMATION TOOLS",
+ "Gerry Tyra, SA Technology",
+ "",
+ "+ADDITIONAL EDITOR TOOL PROGRAMMING",
+ "Robert Duffy",
+ "",
+ "+ADDITIONAL PROGRAMMING",
+ "Ryan Feltrin",
+ "",
+ "+PRODUCTION COORDINATOR",
+ "Victoria Sylvester",
+ "",
+ "+SOUND DESIGN",
+ "Gary Bradfield",
+ "",
+ "+MUSIC BY",
+ "Sonic Mayhem",
+ "",
+ "",
+ "",
+ "+SPECIAL THANKS",
+ "+TO",
+ "+OUR FRIENDS AT ID SOFTWARE",
+ "",
+ "John Carmack",
+ "John Cash",
+ "Brian Hook",
+ "Adrian Carmack",
+ "Kevin Cloud",
+ "Paul Steed",
+ "Tim Willits",
+ "Christian Antkow",
+ "Paul Jaquays",
+ "Brandon James",
+ "Todd Hollenshead",
+ "Barrett (Bear) Alexander",
+ "Dave \"Zoid\" Kirsch",
+ "Donna Jackson",
+ "",
+ "",
+ "",
+ "+THANKS TO ACTIVISION",
+ "+IN PARTICULAR:",
+ "",
+ "Marty Stratton",
+ "Henk \"The Original Ripper\" Hartong",
+ "Kevin Kraff",
+ "Jamey Gottlieb",
+ "Chris Hepburn",
+ "",
+ "+AND THE GAME TESTERS",
+ "",
+ "Tim Vanlaw",
+ "Doug Jacobs",
+ "Steven Rosenthal",
+ "David Baker",
+ "Chris Campbell",
+ "Aaron Casillas",
+ "Steve Elwell",
+ "Derek Johnstone",
+ "Igor Krinitskiy",
+ "Samantha Lee",
+ "Michael Spann",
+ "Chris Toft",
+ "Juan Valdes",
+ "",
+ "+THANKS TO INTERGRAPH COMPUTER SYTEMS",
+ "+IN PARTICULAR:",
+ "",
+ "Michael T. Nicolaou",
+ "",
+ "",
+ "Quake II Mission Pack: The Reckoning",
+ "(tm) (C)1998 Id Software, Inc. All",
+ "Rights Reserved. Developed by Xatrix",
+ "Entertainment, Inc. for Id Software,",
+ "Inc. Distributed by Activision Inc.",
+ "under license. Quake(R) is a",
+ "registered trademark of Id Software,",
+ "Inc. Quake II Mission Pack: The",
+ "Reckoning(tm), Quake II(tm), the Id",
+ "Software name, the \"Q II\"(tm) logo",
+ "and id(tm) logo are trademarks of Id",
+ "Software, Inc. Activision(R) is a",
+ "registered trademark of Activision,",
+ "Inc. Xatrix(R) is a registered",
+ "trademark of Xatrix Entertainment,",
+ "Inc. All other trademarks and trade",
+ "names are properties of their",
+ "respective owners.",
+ 0
+};
+
+static char *roguecredits[] =
+{
+ "+QUAKE II MISSION PACK 2: GROUND ZERO",
+ "+BY",
+ "+ROGUE ENTERTAINMENT, INC.",
+ "",
+ "+PRODUCED BY",
+ "Jim Molinets",
+ "",
+ "+PROGRAMMING",
+ "Peter Mack",
+ "Patrick Magruder",
+ "",
+ "+LEVEL DESIGN",
+ "Jim Molinets",
+ "Cameron Lamprecht",
+ "Berenger Fish",
+ "Robert Selitto",
+ "Steve Tietze",
+ "Steve Thoms",
+ "",
+ "+ART DIRECTION",
+ "Rich Fleider",
+ "",
+ "+ART",
+ "Rich Fleider",
+ "Steve Maines",
+ "Won Choi",
+ "",
+ "+ANIMATION SEQUENCES",
+ "Creat Studios",
+ "Steve Maines",
+ "",
+ "+ADDITIONAL LEVEL DESIGN",
+ "Rich Fleider",
+ "Steve Maines",
+ "Peter Mack",
+ "",
+ "+SOUND",
+ "James Grunke",
+ "",
+ "+GROUND ZERO THEME",
+ "+AND",
+ "+MUSIC BY",
+ "Sonic Mayhem",
+ "",
+ "+VWEP MODELS",
+ "Brent \"Hentai\" Dill",
+ "",
+ "",
+ "",
+ "+SPECIAL THANKS",
+ "+TO",
+ "+OUR FRIENDS AT ID SOFTWARE",
+ "",
+ "John Carmack",
+ "John Cash",
+ "Brian Hook",
+ "Adrian Carmack",
+ "Kevin Cloud",
+ "Paul Steed",
+ "Tim Willits",
+ "Christian Antkow",
+ "Paul Jaquays",
+ "Brandon James",
+ "Todd Hollenshead",
+ "Barrett (Bear) Alexander",
+ "Katherine Anna Kang",
+ "Donna Jackson",
+ "Dave \"Zoid\" Kirsch",
+ "",
+ "",
+ "",
+ "+THANKS TO ACTIVISION",
+ "+IN PARTICULAR:",
+ "",
+ "Marty Stratton",
+ "Henk Hartong",
+ "Mitch Lasky",
+ "Steve Rosenthal",
+ "Steve Elwell",
+ "",
+ "+AND THE GAME TESTERS",
+ "",
+ "The Ranger Clan",
+ "Dave \"Zoid\" Kirsch",
+ "Nihilistic Software",
+ "Robert Duffy",
+ "",
+ "And Countless Others",
+ "",
+ "",
+ "",
+ "Quake II Mission Pack 2: Ground Zero",
+ "(tm) (C)1998 Id Software, Inc. All",
+ "Rights Reserved. Developed by Rogue",
+ "Entertainment, Inc. for Id Software,",
+ "Inc. Distributed by Activision Inc.",
+ "under license. Quake(R) is a",
+ "registered trademark of Id Software,",
+ "Inc. Quake II Mission Pack 2: Ground",
+ "Zero(tm), Quake II(tm), the Id",
+ "Software name, the \"Q II\"(tm) logo",
+ "and id(tm) logo are trademarks of Id",
+ "Software, Inc. Activision(R) is a",
+ "registered trademark of Activision,",
+ "Inc. Rogue(R) is a registered",
+ "trademark of Rogue Entertainment,",
+ "Inc. All other trademarks and trade",
+ "names are properties of their",
+ "respective owners.",
+ 0
+};
+
+
+void M_Credits_MenuDraw( void )
+{
+ int i, y;
+
+ /*
+ ** draw the credits
+ */
+ for ( i = 0, y = vid.height - ( ( cls.realtime - credits_start_time ) / 40.0F ); credits[i] && y < vid.height; y += 10, i++ )
+ {
+ int j, stringoffset;
+ int bold;
+
+ if ( y <= -8 )
+ continue;
+
+ if ( credits[i][0] == '+' )
+ {
+ bold = true;
+ stringoffset = 1;
+ }
+ else
+ {
+ bold = false;
+ stringoffset = 0;
+ }
+
+ for ( j = 0; credits[i][j+stringoffset]; j++ )
+ {
+ int x;
+
+ x = ( vid.width - strlen( credits[i] ) * 8 - stringoffset * 8 ) / 2 + ( j + stringoffset ) * 8;
+
+ if ( bold )
+ re.DrawChar( x, y, credits[i][j+stringoffset] + 128 );
+ else
+ re.DrawChar( x, y, credits[i][j+stringoffset] );
+ }
+ }
+
+ if ( y < 0 )
+ credits_start_time = cls.realtime;
+}
+
+char *M_Credits_Key( int key )
+{
+ switch (key)
+ {
+ case K_ESCAPE:
+ if (creditsBuffer)
+ FS_FreeFile (creditsBuffer);
+ M_PopMenu ();
+ break;
+ }
+
+ return menu_out_sound;
+
+}
+
+extern int Developer_searchpath (int who);
+
+void M_Menu_Credits_f( void )
+{
+ int n;
+ int count;
+ char *p;
+ int isdeveloper;
+
+ creditsBuffer = NULL;
+ count = FS_LoadFile ("credits", &creditsBuffer);
+ if (count != -1)
+ {
+ p = creditsBuffer;
+ for (n = 0; n < 255; n++)
+ {
+ creditsIndex[n] = p;
+ while (*p != '\r' && *p != '\n')
+ {
+ p++;
+ if (--count == 0)
+ break;
+ }
+ if (*p == '\r')
+ {
+ *p++ = 0;
+ if (--count == 0)
+ break;
+ }
+ *p++ = 0;
+ if (--count == 0)
+ break;
+ }
+ creditsIndex[++n] = 0;
+ credits = creditsIndex;
+ }
+ else
+ {
+ isdeveloper = Developer_searchpath (1);
+
+ if (isdeveloper == 1) // xatrix
+ credits = xatcredits;
+ else if (isdeveloper == 2) // ROGUE
+ credits = roguecredits;
+ else
+ {
+ credits = idcredits;
+ }
+
+ }
+
+ credits_start_time = cls.realtime;
+ M_PushMenu( M_Credits_MenuDraw, M_Credits_Key);
+}
+
+/*
+=============================================================================
+
+GAME MENU
+
+=============================================================================
+*/
+
+static int m_game_cursor;
+
+static menuframework_t s_game_menu;
+static menuaction_t s_easy_game_action;
+static menuaction_t s_medium_game_action;
+static menuaction_t s_hard_game_action;
+static menuaction_t s_load_game_action;
+static menuaction_t s_save_game_action;
+static menuaction_t s_credits_action;
+static menuseparator_t s_blankline;
+
+static void StartGame( void )
+{
+ // disable updates and start the cinematic going
+ cl.servercount = -1;
+ M_ForceMenuOff ();
+ Cvar_SetValue( "deathmatch", 0 );
+ Cvar_SetValue( "coop", 0 );
+
+ Cvar_SetValue( "gamerules", 0 ); //PGM
+
+ Cbuf_AddText ("loading ; killserver ; wait ; newgame\n");
+ cls.key_dest = key_game;
+}
+
+static void EasyGameFunc( void * )
+{
+ Cvar_ForceSet( "skill", "0" );
+ StartGame();
+}
+
+static void MediumGameFunc( void * )
+{
+ Cvar_ForceSet( "skill", "1" );
+ StartGame();
+}
+
+static void HardGameFunc( void * )
+{
+ Cvar_ForceSet( "skill", "2" );
+ StartGame();
+}
+
+static void LoadGameFunc( void * )
+{
+ M_Menu_LoadGame_f ();
+}
+
+static void SaveGameFunc( void * )
+{
+ M_Menu_SaveGame_f();
+}
+
+static void CreditsFunc( void * )
+{
+ M_Menu_Credits_f();
+}
+
+void Game_MenuInit( void )
+{
+ static char *difficulty_names[] =
+ {
+ "easy",
+ "medium",
+ "hard",
+ 0
+ };
+
+ s_game_menu.x = vid.width * 0.50;
+ s_game_menu.nitems = 0;
+
+ s_easy_game_action.generic.type = MTYPE_ACTION;
+ s_easy_game_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_easy_game_action.generic.x = 0;
+ s_easy_game_action.generic.y = 0;
+ s_easy_game_action.generic.name = "easy";
+ s_easy_game_action.generic.callback = EasyGameFunc;
+
+ s_medium_game_action.generic.type = MTYPE_ACTION;
+ s_medium_game_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_medium_game_action.generic.x = 0;
+ s_medium_game_action.generic.y = 10;
+ s_medium_game_action.generic.name = "medium";
+ s_medium_game_action.generic.callback = MediumGameFunc;
+
+ s_hard_game_action.generic.type = MTYPE_ACTION;
+ s_hard_game_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_hard_game_action.generic.x = 0;
+ s_hard_game_action.generic.y = 20;
+ s_hard_game_action.generic.name = "hard";
+ s_hard_game_action.generic.callback = HardGameFunc;
+
+ s_blankline.generic.type = MTYPE_SEPARATOR;
+
+ s_load_game_action.generic.type = MTYPE_ACTION;
+ s_load_game_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_load_game_action.generic.x = 0;
+ s_load_game_action.generic.y = 40;
+ s_load_game_action.generic.name = "load game";
+ s_load_game_action.generic.callback = LoadGameFunc;
+
+ s_save_game_action.generic.type = MTYPE_ACTION;
+ s_save_game_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_save_game_action.generic.x = 0;
+ s_save_game_action.generic.y = 50;
+ s_save_game_action.generic.name = "save game";
+ s_save_game_action.generic.callback = SaveGameFunc;
+
+ s_credits_action.generic.type = MTYPE_ACTION;
+ s_credits_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_credits_action.generic.x = 0;
+ s_credits_action.generic.y = 60;
+ s_credits_action.generic.name = "credits";
+ s_credits_action.generic.callback = CreditsFunc;
+
+ Menu_AddItem( &s_game_menu, ( void * ) &s_easy_game_action );
+ Menu_AddItem( &s_game_menu, ( void * ) &s_medium_game_action );
+ Menu_AddItem( &s_game_menu, ( void * ) &s_hard_game_action );
+ Menu_AddItem( &s_game_menu, ( void * ) &s_blankline );
+ Menu_AddItem( &s_game_menu, ( void * ) &s_load_game_action );
+ Menu_AddItem( &s_game_menu, ( void * ) &s_save_game_action );
+ Menu_AddItem( &s_game_menu, ( void * ) &s_blankline );
+ Menu_AddItem( &s_game_menu, ( void * ) &s_credits_action );
+
+ Menu_Center( &s_game_menu );
+}
+
+void Game_MenuDraw( void )
+{
+ M_Banner( "m_banner_game" );
+ Menu_AdjustCursor( &s_game_menu, 1 );
+ Menu_Draw( &s_game_menu );
+}
+
+char *Game_MenuKey( int key )
+{
+ return Default_MenuKey( &s_game_menu, key );
+}
+
+void M_Menu_Game_f (void)
+{
+ Game_MenuInit();
+ M_PushMenu( Game_MenuDraw, Game_MenuKey );
+ m_game_cursor = 1;
+}
+
+/*
+=============================================================================
+
+LOADGAME MENU
+
+=============================================================================
+*/
+
+#define MAX_SAVEGAMES 15
+
+static menuframework_t s_savegame_menu;
+
+static menuframework_t s_loadgame_menu;
+static menuaction_t s_loadgame_actions[MAX_SAVEGAMES];
+
+char m_savestrings[MAX_SAVEGAMES][32];
+qboolean m_savevalid[MAX_SAVEGAMES];
+
+void Create_Savestrings (void)
+{
+ int i;
+ FILE *f;
+ char name[MAX_OSPATH];
+
+ for (i=0 ; i<MAX_SAVEGAMES ; i++)
+ {
+ Com_sprintf (name, sizeof(name), "%s/save/save%i/server.ssv", FS_Gamedir(), i);
+ f = fopen (name, "rb");
+ if (!f)
+ {
+ strcpy (m_savestrings[i], "<EMPTY>");
+ m_savevalid[i] = false;
+ }
+ else
+ {
+ FS_Read (m_savestrings[i], sizeof(m_savestrings[i]), f);
+ fclose (f);
+ m_savevalid[i] = true;
+ }
+ }
+}
+
+void LoadGameCallback( void *self )
+{
+ menuaction_t *a = ( menuaction_t * ) self;
+
+ if ( m_savevalid[ a->generic.localdata[0] ] )
+ Cbuf_AddText (va("load save%i\n", a->generic.localdata[0] ) );
+ M_ForceMenuOff ();
+}
+
+void LoadGame_MenuInit( void )
+{
+ int i;
+
+ s_loadgame_menu.x = vid.width / 2 - 120;
+ s_loadgame_menu.y = vid.height / 2 - 58;
+ s_loadgame_menu.nitems = 0;
+
+ Create_Savestrings();
+
+ for ( i = 0; i < MAX_SAVEGAMES; i++ )
+ {
+ s_loadgame_actions[i].generic.name = m_savestrings[i];
+ s_loadgame_actions[i].generic.flags = QMF_LEFT_JUSTIFY;
+ s_loadgame_actions[i].generic.localdata[0] = i;
+ s_loadgame_actions[i].generic.callback = LoadGameCallback;
+
+ s_loadgame_actions[i].generic.x = 0;
+ s_loadgame_actions[i].generic.y = ( i ) * 10;
+ if (i>0) // separate from autosave
+ s_loadgame_actions[i].generic.y += 10;
+
+ s_loadgame_actions[i].generic.type = MTYPE_ACTION;
+
+ Menu_AddItem( &s_loadgame_menu, &s_loadgame_actions[i] );
+ }
+}
+
+void LoadGame_MenuDraw( void )
+{
+ M_Banner( "m_banner_load_game" );
+// Menu_AdjustCursor( &s_loadgame_menu, 1 );
+ Menu_Draw( &s_loadgame_menu );
+}
+
+char *LoadGame_MenuKey( int key )
+{
+ if ( key == K_ESCAPE || key == K_ENTER )
+ {
+ s_savegame_menu.cursor = s_loadgame_menu.cursor - 1;
+ if ( s_savegame_menu.cursor < 0 )
+ s_savegame_menu.cursor = 0;
+ }
+ return Default_MenuKey( &s_loadgame_menu, key );
+}
+
+void M_Menu_LoadGame_f (void)
+{
+ LoadGame_MenuInit();
+ M_PushMenu( LoadGame_MenuDraw, LoadGame_MenuKey );
+}
+
+
+/*
+=============================================================================
+
+SAVEGAME MENU
+
+=============================================================================
+*/
+static menuframework_t s_savegame_menu;
+static menuaction_t s_savegame_actions[MAX_SAVEGAMES];
+
+void SaveGameCallback( void *self )
+{
+ menuaction_t *a = ( menuaction_t * ) self;
+
+ Cbuf_AddText (va("save save%i\n", a->generic.localdata[0] ));
+ M_ForceMenuOff ();
+}
+
+void SaveGame_MenuDraw( void )
+{
+ M_Banner( "m_banner_save_game" );
+ Menu_AdjustCursor( &s_savegame_menu, 1 );
+ Menu_Draw( &s_savegame_menu );
+}
+
+void SaveGame_MenuInit( void )
+{
+ int i;
+
+ s_savegame_menu.x = vid.width / 2 - 120;
+ s_savegame_menu.y = vid.height / 2 - 58;
+ s_savegame_menu.nitems = 0;
+
+ Create_Savestrings();
+
+ // don't include the autosave slot
+ for ( i = 0; i < MAX_SAVEGAMES-1; i++ )
+ {
+ s_savegame_actions[i].generic.name = m_savestrings[i+1];
+ s_savegame_actions[i].generic.localdata[0] = i+1;
+ s_savegame_actions[i].generic.flags = QMF_LEFT_JUSTIFY;
+ s_savegame_actions[i].generic.callback = SaveGameCallback;
+
+ s_savegame_actions[i].generic.x = 0;
+ s_savegame_actions[i].generic.y = ( i ) * 10;
+
+ s_savegame_actions[i].generic.type = MTYPE_ACTION;
+
+ Menu_AddItem( &s_savegame_menu, &s_savegame_actions[i] );
+ }
+}
+
+char *SaveGame_MenuKey( int key )
+{
+ if ( key == K_ENTER || key == K_ESCAPE )
+ {
+ s_loadgame_menu.cursor = s_savegame_menu.cursor - 1;
+ if ( s_loadgame_menu.cursor < 0 )
+ s_loadgame_menu.cursor = 0;
+ }
+ return Default_MenuKey( &s_savegame_menu, key );
+}
+
+void M_Menu_SaveGame_f (void)
+{
+ if (!Com_ServerState())
+ return; // not playing a game
+
+ SaveGame_MenuInit();
+ M_PushMenu( SaveGame_MenuDraw, SaveGame_MenuKey );
+ Create_Savestrings ();
+}
+
+
+/*
+=============================================================================
+
+JOIN SERVER MENU
+
+=============================================================================
+*/
+#define MAX_LOCAL_SERVERS 8
+
+static menuframework_t s_joinserver_menu;
+static menuseparator_t s_joinserver_server_title;
+static menuaction_t s_joinserver_search_action;
+static menuaction_t s_joinserver_address_book_action;
+static menuaction_t s_joinserver_server_actions[MAX_LOCAL_SERVERS];
+
+int m_num_servers;
+#define NO_SERVER_STRING "<no server>"
+
+// user readable information
+static char local_server_names[MAX_LOCAL_SERVERS][80];
+
+// network address
+static netadr_t local_server_netadr[MAX_LOCAL_SERVERS];
+
+void M_AddToServerList (netadr_t adr, char *info)
+{
+ int i;
+
+ if (m_num_servers == MAX_LOCAL_SERVERS)
+ return;
+ while ( *info == ' ' )
+ info++;
+
+ // ignore if duplicated
+ for (i=0 ; i<m_num_servers ; i++)
+ if (!strcmp(info, local_server_names[i]))
+ return;
+
+ local_server_netadr[m_num_servers] = adr;
+ strncpy (local_server_names[m_num_servers], info, sizeof(local_server_names[0])-1);
+ m_num_servers++;
+}
+
+
+void JoinServerFunc( void *self )
+{
+ char buffer[128];
+ int index;
+
+ index = ( menuaction_t * ) self - s_joinserver_server_actions;
+
+ if ( cistrcmp( local_server_names[index], NO_SERVER_STRING ) == 0 )
+ return;
+
+ if (index >= m_num_servers)
+ return;
+
+ Com_sprintf (buffer, sizeof(buffer), "connect %s\n", NET_AdrToString (local_server_netadr[index]));
+ Cbuf_AddText (buffer);
+ M_ForceMenuOff ();
+}
+
+void AddressBookFunc( void * )
+{
+ M_Menu_AddressBook_f();
+}
+
+void NullCursorDraw( void * )
+{
+}
+
+void SearchLocalGames( void )
+{
+ int i;
+
+ m_num_servers = 0;
+ for (i=0 ; i<MAX_LOCAL_SERVERS ; i++)
+ strcpy (local_server_names[i], NO_SERVER_STRING);
+
+ M_DrawTextBox( 8, 120 - 48, 36, 3 );
+ M_Print( 16 + 16, 120 - 48 + 8, "Searching for local servers, this" );
+ M_Print( 16 + 16, 120 - 48 + 16, "could take up to a minute, so" );
+ M_Print( 16 + 16, 120 - 48 + 24, "please be patient." );
+
+ // the text box won't show up unless we do a buffer swap
+ re.EndFrame();
+
+ // send out info packets
+ CL_PingServers_f();
+}
+
+void SearchLocalGamesFunc( void * )
+{
+ SearchLocalGames();
+}
+
+void JoinServer_MenuInit( void )
+{
+ int i;
+
+ s_joinserver_menu.x = vid.width * 0.50 - 120;
+ s_joinserver_menu.nitems = 0;
+
+ s_joinserver_address_book_action.generic.type = MTYPE_ACTION;
+ s_joinserver_address_book_action.generic.name = "address book";
+ s_joinserver_address_book_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_joinserver_address_book_action.generic.x = 0;
+ s_joinserver_address_book_action.generic.y = 0;
+ s_joinserver_address_book_action.generic.callback = AddressBookFunc;
+
+ s_joinserver_search_action.generic.type = MTYPE_ACTION;
+ s_joinserver_search_action.generic.name = "refresh server list";
+ s_joinserver_search_action.generic.flags = QMF_LEFT_JUSTIFY;
+ s_joinserver_search_action.generic.x = 0;
+ s_joinserver_search_action.generic.y = 10;
+ s_joinserver_search_action.generic.callback = SearchLocalGamesFunc;
+ s_joinserver_search_action.generic.statusbar = "search for servers";
+
+ s_joinserver_server_title.generic.type = MTYPE_SEPARATOR;
+ s_joinserver_server_title.generic.name = "connect to...";
+ s_joinserver_server_title.generic.x = 80;
+ s_joinserver_server_title.generic.y = 30;
+
+ for ( i = 0; i < MAX_LOCAL_SERVERS; i++ )
+ {
+ s_joinserver_server_actions[i].generic.type = MTYPE_ACTION;
+ strcpy (local_server_names[i], NO_SERVER_STRING);
+ s_joinserver_server_actions[i].generic.name = local_server_names[i];
+ s_joinserver_server_actions[i].generic.flags = QMF_LEFT_JUSTIFY;
+ s_joinserver_server_actions[i].generic.x = 0;
+ s_joinserver_server_actions[i].generic.y = 40 + i*10;
+ s_joinserver_server_actions[i].generic.callback = JoinServerFunc;
+ s_joinserver_server_actions[i].generic.statusbar = "press ENTER to connect";
+ }
+
+ Menu_AddItem( &s_joinserver_menu, &s_joinserver_address_book_action );
+ Menu_AddItem( &s_joinserver_menu, &s_joinserver_server_title );
+ Menu_AddItem( &s_joinserver_menu, &s_joinserver_search_action );
+
+ for ( i = 0; i < 8; i++ )
+ Menu_AddItem( &s_joinserver_menu, &s_joinserver_server_actions[i] );
+
+ Menu_Center( &s_joinserver_menu );
+
+ SearchLocalGames();
+}
+
+void JoinServer_MenuDraw(void)
+{
+ M_Banner( "m_banner_join_server" );
+ Menu_Draw( &s_joinserver_menu );
+}
+
+
+char *JoinServer_MenuKey( int key )
+{
+ return Default_MenuKey( &s_joinserver_menu, key );
+}
+
+void M_Menu_JoinServer_f (void)
+{
+ JoinServer_MenuInit();
+ M_PushMenu( JoinServer_MenuDraw, JoinServer_MenuKey );
+}
+
+
+/*
+=============================================================================
+
+START SERVER MENU
+
+=============================================================================
+*/
+static menuframework_t s_startserver_menu;
+static char **mapnames;
+static int nummaps;
+
+static menuaction_t s_startserver_start_action;
+static menuaction_t s_startserver_dmoptions_action;
+static menufield_t s_timelimit_field;
+static menufield_t s_fraglimit_field;
+static menufield_t s_maxclients_field;
+static menufield_t s_hostname_field;
+static menulist_t s_startmap_list;
+static menulist_t s_rules_box;
+
+void DMOptionsFunc( void * )
+{
+ if (s_rules_box.curvalue == 1)
+ return;
+ M_Menu_DMOptions_f();
+}
+
+void RulesChangeFunc ( void * )
+{
+ // DM
+ if (s_rules_box.curvalue == 0)
+ {
+ s_maxclients_field.generic.statusbar = NULL;
+ s_startserver_dmoptions_action.generic.statusbar = NULL;
+ }
+ else if(s_rules_box.curvalue == 1) // coop // PGM
+ {
+ s_maxclients_field.generic.statusbar = "4 maximum for cooperative";
+ if (atoi(s_maxclients_field.buffer) > 4)
+ strcpy( s_maxclients_field.buffer, "4" );
+ s_startserver_dmoptions_action.generic.statusbar = "N/A for cooperative";
+ }
+//=====
+//PGM
+ // ROGUE GAMES
+ else if(Developer_searchpath(2) == 2)
+ {
+ if (s_rules_box.curvalue == 2) // tag
+ {
+ s_maxclients_field.generic.statusbar = NULL;
+ s_startserver_dmoptions_action.generic.statusbar = NULL;
+ }
+/*
+ else if(s_rules_box.curvalue == 3) // deathball
+ {
+ s_maxclients_field.generic.statusbar = NULL;
+ s_startserver_dmoptions_action.generic.statusbar = NULL;
+ }
+*/
+ }
+//PGM
+//=====
+}
+
+void StartServerActionFunc( void * )
+{
+ char startmap[1024];
+ int timelimit;
+ int fraglimit;
+ int maxclients;
+ char *spot;
+
+ strcpy( startmap, strchr( mapnames[s_startmap_list.curvalue], '\n' ) + 1 );
+
+ maxclients = atoi( s_maxclients_field.buffer );
+ timelimit = atoi( s_timelimit_field.buffer );
+ fraglimit = atoi( s_fraglimit_field.buffer );
+
+ Cvar_SetValue( "maxclients", ClampCvar( 0, maxclients, maxclients ) );
+ Cvar_SetValue ("timelimit", ClampCvar( 0, timelimit, timelimit ) );
+ Cvar_SetValue ("fraglimit", ClampCvar( 0, fraglimit, fraglimit ) );
+ Cvar_Set("hostname", s_hostname_field.buffer );
+// Cvar_SetValue ("deathmatch", !s_rules_box.curvalue );
+// Cvar_SetValue ("coop", s_rules_box.curvalue );
+
+//PGM
+ if((s_rules_box.curvalue < 2) || (Developer_searchpath(2) != 2))
+ {
+ Cvar_SetValue ("deathmatch", !s_rules_box.curvalue );
+ Cvar_SetValue ("coop", s_rules_box.curvalue );
+ Cvar_SetValue ("gamerules", 0 );
+ }
+ else
+ {
+ Cvar_SetValue ("deathmatch", 1 ); // deathmatch is always true for rogue games, right?
+ Cvar_SetValue ("coop", 0 ); // FIXME - this might need to depend on which game we're running
+ Cvar_SetValue ("gamerules", s_rules_box.curvalue );
+ }
+//PGM
+
+ spot = NULL;
+ if (s_rules_box.curvalue == 1) // PGM
+ {
+ if(cistrcmp(startmap, "bunk1") == 0)
+ spot = "start";
+ else if(cistrcmp(startmap, "mintro") == 0)
+ spot = "start";
+ else if(cistrcmp(startmap, "fact1") == 0)
+ spot = "start";
+ else if(cistrcmp(startmap, "power1") == 0)
+ spot = "pstart";
+ else if(cistrcmp(startmap, "biggun") == 0)
+ spot = "bstart";
+ else if(cistrcmp(startmap, "hangar1") == 0)
+ spot = "unitstart";
+ else if(cistrcmp(startmap, "city1") == 0)
+ spot = "unitstart";
+ else if(cistrcmp(startmap, "boss1") == 0)
+ spot = "bosstart";
+ }
+
+ if (spot)
+ {
+ if (Com_ServerState())
+ Cbuf_AddText ("disconnect\n");
+ Cbuf_AddText (va("gamemap \"*%s$%s\"\n", startmap, spot));
+ }
+ else
+ {
+ Cbuf_AddText (va("map %s\n", startmap));
+ }
+
+ M_ForceMenuOff ();
+}
+
+void StartServer_MenuInit( void )
+{
+ static char *dm_coop_names[] =
+ {
+ "deathmatch",
+ "cooperative",
+ 0
+ };
+//=======
+//PGM
+ static char *dm_coop_names_rogue[] =
+ {
+ "deathmatch",
+ "cooperative",
+ "tag",
+// "deathball",
+ 0
+ };
+//PGM
+//=======
+ char *buffer;
+ char mapsname[1024];
+ char *s;
+ int length;
+ int i;
+ FILE *fp;
+
+ /*
+ ** load the list of map names
+ */
+ Com_sprintf( mapsname, sizeof( mapsname ), "%s/maps.lst", FS_Gamedir() );
+ if ( ( fp = fopen( mapsname, "rb" ) ) == 0 )
+ {
+ if ( ( length = FS_LoadFile( "maps.lst", ( void ** ) &buffer ) ) == -1 )
+ Com_Error( ERR_DROP, "couldn't find maps.lst\n" );
+ }
+ else
+ {
+#ifdef _WIN32
+ length = filelength( fileno( fp ) );
+#else
+ fseek(fp, 0, SEEK_END);
+ length = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+#endif
+ buffer = malloc( length );
+ fread( buffer, length, 1, fp );
+ }
+
+ s = buffer;
+
+ i = 0;
+ while ( i < length )
+ {
+ if ( s[i] == '\r' )
+ nummaps++;
+ i++;
+ }
+
+ if ( nummaps == 0 )
+ Com_Error( ERR_DROP, "no maps in maps.lst\n" );
+
+ mapnames = malloc( sizeof( char * ) * ( nummaps + 1 ) );
+ memset( mapnames, 0, sizeof( char * ) * ( nummaps + 1 ) );
+
+ s = buffer;
+
+ for ( i = 0; i < nummaps; i++ )
+ {
+ char shortname[MAX_TOKEN_CHARS];
+ char longname[MAX_TOKEN_CHARS];
+ char scratch[200];
+ int j, l;
+
+ strcpy( shortname, COM_Parse( &s ) );
+ l = strlen(shortname);
+ for (j=0 ; j<l ; j++)
+ shortname[j] = toupper(shortname[j]);
+ strcpy( longname, COM_Parse( &s ) );
+ Com_sprintf( scratch, sizeof( scratch ), "%s\n%s", longname, shortname );
+
+ mapnames[i] = malloc( strlen( scratch ) + 1 );
+ strcpy( mapnames[i], scratch );
+ }
+ mapnames[nummaps] = 0;
+
+ if ( fp != 0 )
+ {
+ free( buffer );
+ }
+ else
+ {
+ FS_FreeFile( buffer );
+ }
+
+ /*
+ ** initialize the menu stuff
+ */
+ s_startserver_menu.x = vid.width * 0.50;
+ s_startserver_menu.nitems = 0;
+
+ s_startmap_list.generic.type = MTYPE_SPINCONTROL;
+ s_startmap_list.generic.x = 0;
+ s_startmap_list.generic.y = 0;
+ s_startmap_list.generic.name = "initial map";
+ s_startmap_list.itemnames = mapnames;
+
+ s_rules_box.generic.type = MTYPE_SPINCONTROL;
+ s_rules_box.generic.x = 0;
+ s_rules_box.generic.y = 20;
+ s_rules_box.generic.name = "rules";
+
+//PGM - rogue games only available with rogue DLL.
+ if(Developer_searchpath(2) == 2)
+ s_rules_box.itemnames = dm_coop_names_rogue;
+ else
+ s_rules_box.itemnames = dm_coop_names;
+//PGM
+
+ if (Cvar_VariableValue("coop"))
+ s_rules_box.curvalue = 1;
+ else
+ s_rules_box.curvalue = 0;
+ s_rules_box.generic.callback = RulesChangeFunc;
+
+ s_timelimit_field.generic.type = MTYPE_FIELD;
+ s_timelimit_field.generic.name = "time limit";
+ s_timelimit_field.generic.flags = QMF_NUMBERSONLY;
+ s_timelimit_field.generic.x = 0;
+ s_timelimit_field.generic.y = 36;
+ s_timelimit_field.generic.statusbar = "0 = no limit";
+ s_timelimit_field.length = 3;
+ s_timelimit_field.visible_length = 3;
+ strcpy( s_timelimit_field.buffer, Cvar_VariableString("timelimit") );
+
+ s_fraglimit_field.generic.type = MTYPE_FIELD;
+ s_fraglimit_field.generic.name = "frag limit";
+ s_fraglimit_field.generic.flags = QMF_NUMBERSONLY;
+ s_fraglimit_field.generic.x = 0;
+ s_fraglimit_field.generic.y = 54;
+ s_fraglimit_field.generic.statusbar = "0 = no limit";
+ s_fraglimit_field.length = 3;
+ s_fraglimit_field.visible_length = 3;
+ strcpy( s_fraglimit_field.buffer, Cvar_VariableString("fraglimit") );
+
+ /*
+ ** maxclients determines the maximum number of players that can join
+ ** the game. If maxclients is only "1" then we should default the menu
+ ** option to 8 players, otherwise use whatever its current value is.
+ ** Clamping will be done when the server is actually started.
+ */
+ s_maxclients_field.generic.type = MTYPE_FIELD;
+ s_maxclients_field.generic.name = "max players";
+ s_maxclients_field.generic.flags = QMF_NUMBERSONLY;
+ s_maxclients_field.generic.x = 0;
+ s_maxclients_field.generic.y = 72;
+ s_maxclients_field.generic.statusbar = NULL;
+ s_maxclients_field.length = 3;
+ s_maxclients_field.visible_length = 3;
+ if ( Cvar_VariableValue( "maxclients" ) == 1 )
+ strcpy( s_maxclients_field.buffer, "8" );
+ else
+ strcpy( s_maxclients_field.buffer, Cvar_VariableString("maxclients") );
+
+ s_hostname_field.generic.type = MTYPE_FIELD;
+ s_hostname_field.generic.name = "hostname";
+ s_hostname_field.generic.flags = 0;
+ s_hostname_field.generic.x = 0;
+ s_hostname_field.generic.y = 90;
+ s_hostname_field.generic.statusbar = NULL;
+ s_hostname_field.length = 12;
+ s_hostname_field.visible_length = 12;
+ strcpy( s_hostname_field.buffer, Cvar_VariableString("hostname") );
+
+ s_startserver_dmoptions_action.generic.type = MTYPE_ACTION;
+ s_startserver_dmoptions_action.generic.name = " deathmatch flags";
+ s_startserver_dmoptions_action.generic.flags= QMF_LEFT_JUSTIFY;
+ s_startserver_dmoptions_action.generic.x = 24;
+ s_startserver_dmoptions_action.generic.y = 108;
+ s_startserver_dmoptions_action.generic.statusbar = NULL;
+ s_startserver_dmoptions_action.generic.callback = DMOptionsFunc;
+
+ s_startserver_start_action.generic.type = MTYPE_ACTION;
+ s_startserver_start_action.generic.name = " begin";
+ s_startserver_start_action.generic.flags= QMF_LEFT_JUSTIFY;
+ s_startserver_start_action.generic.x = 24;
+ s_startserver_start_action.generic.y = 128;
+ s_startserver_start_action.generic.callback = StartServerActionFunc;
+
+ Menu_AddItem( &s_startserver_menu, &s_startmap_list );
+ Menu_AddItem( &s_startserver_menu, &s_rules_box );
+ Menu_AddItem( &s_startserver_menu, &s_timelimit_field );
+ Menu_AddItem( &s_startserver_menu, &s_fraglimit_field );
+ Menu_AddItem( &s_startserver_menu, &s_maxclients_field );
+ Menu_AddItem( &s_startserver_menu, &s_hostname_field );
+ Menu_AddItem( &s_startserver_menu, &s_startserver_dmoptions_action );
+ Menu_AddItem( &s_startserver_menu, &s_startserver_start_action );
+
+ Menu_Center( &s_startserver_menu );
+
+ // call this now to set proper inital state
+ RulesChangeFunc ( NULL );
+}
+
+void StartServer_MenuDraw(void)
+{
+ Menu_Draw( &s_startserver_menu );
+}
+
+char *StartServer_MenuKey( int key )
+{
+ if ( key == K_ESCAPE )
+ {
+ if ( mapnames )
+ {
+ int i;
+
+ for ( i = 0; i < nummaps; i++ )
+ free( mapnames[i] );
+ free( mapnames );
+ }
+ mapnames = 0;
+ nummaps = 0;
+ }
+
+ return Default_MenuKey( &s_startserver_menu, key );
+}
+
+void M_Menu_StartServer_f (void)
+{
+ StartServer_MenuInit();
+ M_PushMenu( StartServer_MenuDraw, StartServer_MenuKey );
+}
+
+/*
+=============================================================================
+
+DMOPTIONS BOOK MENU
+
+=============================================================================
+*/
+static char dmoptions_statusbar[128];
+
+static menuframework_t s_dmoptions_menu;
+
+static menulist_t s_friendlyfire_box;
+static menulist_t s_falls_box;
+static menulist_t s_weapons_stay_box;
+static menulist_t s_instant_powerups_box;
+static menulist_t s_powerups_box;
+static menulist_t s_health_box;
+static menulist_t s_spawn_farthest_box;
+static menulist_t s_teamplay_box;
+static menulist_t s_samelevel_box;
+static menulist_t s_force_respawn_box;
+static menulist_t s_armor_box;
+static menulist_t s_allow_exit_box;
+static menulist_t s_infinite_ammo_box;
+static menulist_t s_fixed_fov_box;
+static menulist_t s_quad_drop_box;
+
+//ROGUE
+static menulist_t s_no_mines_box;
+static menulist_t s_no_nukes_box;
+static menulist_t s_stack_double_box;
+static menulist_t s_no_spheres_box;
+//ROGUE
+
+static void DMFlagCallback( void *self )
+{
+ menulist_t *f = ( menulist_t * ) self;
+ int flags;
+ int bit = 0;
+
+ flags = Cvar_VariableValue( "dmflags" );
+
+ if ( f == &s_friendlyfire_box )
+ {
+ if ( f->curvalue )
+ flags &= ~DF_NO_FRIENDLY_FIRE;
+ else
+ flags |= DF_NO_FRIENDLY_FIRE;
+ goto setvalue;
+ }
+ else if ( f == &s_falls_box )
+ {
+ if ( f->curvalue )
+ flags &= ~DF_NO_FALLING;
+ else
+ flags |= DF_NO_FALLING;
+ goto setvalue;
+ }
+ else if ( f == &s_weapons_stay_box )
+ {
+ bit = DF_WEAPONS_STAY;
+ }
+ else if ( f == &s_instant_powerups_box )
+ {
+ bit = DF_INSTANT_ITEMS;
+ }
+ else if ( f == &s_allow_exit_box )
+ {
+ bit = DF_ALLOW_EXIT;
+ }
+ else if ( f == &s_powerups_box )
+ {
+ if ( f->curvalue )
+ flags &= ~DF_NO_ITEMS;
+ else
+ flags |= DF_NO_ITEMS;
+ goto setvalue;
+ }
+ else if ( f == &s_health_box )
+ {
+ if ( f->curvalue )
+ flags &= ~DF_NO_HEALTH;
+ else
+ flags |= DF_NO_HEALTH;
+ goto setvalue;
+ }
+ else if ( f == &s_spawn_farthest_box )
+ {
+ bit = DF_SPAWN_FARTHEST;
+ }
+ else if ( f == &s_teamplay_box )
+ {
+ if ( f->curvalue == 1 )
+ {
+ flags |= DF_SKINTEAMS;
+ flags &= ~DF_MODELTEAMS;
+ }
+ else if ( f->curvalue == 2 )
+ {
+ flags |= DF_MODELTEAMS;
+ flags &= ~DF_SKINTEAMS;
+ }
+ else
+ {
+ flags &= ~( DF_MODELTEAMS | DF_SKINTEAMS );
+ }
+
+ goto setvalue;
+ }
+ else if ( f == &s_samelevel_box )
+ {
+ bit = DF_SAME_LEVEL;
+ }
+ else if ( f == &s_force_respawn_box )
+ {
+ bit = DF_FORCE_RESPAWN;
+ }
+ else if ( f == &s_armor_box )
+ {
+ if ( f->curvalue )
+ flags &= ~DF_NO_ARMOR;
+ else
+ flags |= DF_NO_ARMOR;
+ goto setvalue;
+ }
+ else if ( f == &s_infinite_ammo_box )
+ {
+ bit = DF_INFINITE_AMMO;
+ }
+ else if ( f == &s_fixed_fov_box )
+ {
+ bit = DF_FIXED_FOV;
+ }
+ else if ( f == &s_quad_drop_box )
+ {
+ bit = DF_QUAD_DROP;
+ }
+
+//=======
+//ROGUE
+ else if (Developer_searchpath(2) == 2)
+ {
+ if ( f == &s_no_mines_box)
+ {
+ bit = DF_NO_MINES;
+ }
+ else if ( f == &s_no_nukes_box)
+ {
+ bit = DF_NO_NUKES;
+ }
+ else if ( f == &s_stack_double_box)
+ {
+ bit = DF_NO_STACK_DOUBLE;
+ }
+ else if ( f == &s_no_spheres_box)
+ {
+ bit = DF_NO_SPHERES;
+ }
+ }
+//ROGUE
+//=======
+
+ if ( f )
+ {
+ if ( f->curvalue == 0 )
+ flags &= ~bit;
+ else
+ flags |= bit;
+ }
+
+setvalue:
+ Cvar_SetValue ("dmflags", flags);
+
+ Com_sprintf( dmoptions_statusbar, sizeof( dmoptions_statusbar ), "dmflags = %d", flags );
+
+}
+
+void DMOptions_MenuInit( void )
+{
+ static char *yes_no_names[] =
+ {
+ "no", "yes", 0
+ };
+ static char *teamplay_names[] =
+ {
+ "disabled", "by skin", "by model", 0
+ };
+ int dmflags = Cvar_VariableValue( "dmflags" );
+ int y = 0;
+
+ s_dmoptions_menu.x = vid.width * 0.50;
+ s_dmoptions_menu.nitems = 0;
+
+ s_falls_box.generic.type = MTYPE_SPINCONTROL;
+ s_falls_box.generic.x = 0;
+ s_falls_box.generic.y = y;
+ s_falls_box.generic.name = "falling damage";
+ s_falls_box.generic.callback = DMFlagCallback;
+ s_falls_box.itemnames = yes_no_names;
+ s_falls_box.curvalue = ( dmflags & DF_NO_FALLING ) == 0;
+
+ s_weapons_stay_box.generic.type = MTYPE_SPINCONTROL;
+ s_weapons_stay_box.generic.x = 0;
+ s_weapons_stay_box.generic.y = y += 10;
+ s_weapons_stay_box.generic.name = "weapons stay";
+ s_weapons_stay_box.generic.callback = DMFlagCallback;
+ s_weapons_stay_box.itemnames = yes_no_names;
+ s_weapons_stay_box.curvalue = ( dmflags & DF_WEAPONS_STAY ) != 0;
+
+ s_instant_powerups_box.generic.type = MTYPE_SPINCONTROL;
+ s_instant_powerups_box.generic.x = 0;
+ s_instant_powerups_box.generic.y = y += 10;
+ s_instant_powerups_box.generic.name = "instant powerups";
+ s_instant_powerups_box.generic.callback = DMFlagCallback;
+ s_instant_powerups_box.itemnames = yes_no_names;
+ s_instant_powerups_box.curvalue = ( dmflags & DF_INSTANT_ITEMS ) != 0;
+
+ s_powerups_box.generic.type = MTYPE_SPINCONTROL;
+ s_powerups_box.generic.x = 0;
+ s_powerups_box.generic.y = y += 10;
+ s_powerups_box.generic.name = "allow powerups";
+ s_powerups_box.generic.callback = DMFlagCallback;
+ s_powerups_box.itemnames = yes_no_names;
+ s_powerups_box.curvalue = ( dmflags & DF_NO_ITEMS ) == 0;
+
+ s_health_box.generic.type = MTYPE_SPINCONTROL;
+ s_health_box.generic.x = 0;
+ s_health_box.generic.y = y += 10;
+ s_health_box.generic.callback = DMFlagCallback;
+ s_health_box.generic.name = "allow health";
+ s_health_box.itemnames = yes_no_names;
+ s_health_box.curvalue = ( dmflags & DF_NO_HEALTH ) == 0;
+
+ s_armor_box.generic.type = MTYPE_SPINCONTROL;
+ s_armor_box.generic.x = 0;
+ s_armor_box.generic.y = y += 10;
+ s_armor_box.generic.name = "allow armor";
+ s_armor_box.generic.callback = DMFlagCallback;
+ s_armor_box.itemnames = yes_no_names;
+ s_armor_box.curvalue = ( dmflags & DF_NO_ARMOR ) == 0;
+
+ s_spawn_farthest_box.generic.type = MTYPE_SPINCONTROL;
+ s_spawn_farthest_box.generic.x = 0;
+ s_spawn_farthest_box.generic.y = y += 10;
+ s_spawn_farthest_box.generic.name = "spawn farthest";
+ s_spawn_farthest_box.generic.callback = DMFlagCallback;
+ s_spawn_farthest_box.itemnames = yes_no_names;
+ s_spawn_farthest_box.curvalue = ( dmflags & DF_SPAWN_FARTHEST ) != 0;
+
+ s_samelevel_box.generic.type = MTYPE_SPINCONTROL;
+ s_samelevel_box.generic.x = 0;
+ s_samelevel_box.generic.y = y += 10;
+ s_samelevel_box.generic.name = "same map";
+ s_samelevel_box.generic.callback = DMFlagCallback;
+ s_samelevel_box.itemnames = yes_no_names;
+ s_samelevel_box.curvalue = ( dmflags & DF_SAME_LEVEL ) != 0;
+
+ s_force_respawn_box.generic.type = MTYPE_SPINCONTROL;
+ s_force_respawn_box.generic.x = 0;
+ s_force_respawn_box.generic.y = y += 10;
+ s_force_respawn_box.generic.name = "force respawn";
+ s_force_respawn_box.generic.callback = DMFlagCallback;
+ s_force_respawn_box.itemnames = yes_no_names;
+ s_force_respawn_box.curvalue = ( dmflags & DF_FORCE_RESPAWN ) != 0;
+
+ s_teamplay_box.generic.type = MTYPE_SPINCONTROL;
+ s_teamplay_box.generic.x = 0;
+ s_teamplay_box.generic.y = y += 10;
+ s_teamplay_box.generic.name = "teamplay";
+ s_teamplay_box.generic.callback = DMFlagCallback;
+ s_teamplay_box.itemnames = teamplay_names;
+
+ s_allow_exit_box.generic.type = MTYPE_SPINCONTROL;
+ s_allow_exit_box.generic.x = 0;
+ s_allow_exit_box.generic.y = y += 10;
+ s_allow_exit_box.generic.name = "allow exit";
+ s_allow_exit_box.generic.callback = DMFlagCallback;
+ s_allow_exit_box.itemnames = yes_no_names;
+ s_allow_exit_box.curvalue = ( dmflags & DF_ALLOW_EXIT ) != 0;
+
+ s_infinite_ammo_box.generic.type = MTYPE_SPINCONTROL;
+ s_infinite_ammo_box.generic.x = 0;
+ s_infinite_ammo_box.generic.y = y += 10;
+ s_infinite_ammo_box.generic.name = "infinite ammo";
+ s_infinite_ammo_box.generic.callback = DMFlagCallback;
+ s_infinite_ammo_box.itemnames = yes_no_names;
+ s_infinite_ammo_box.curvalue = ( dmflags & DF_INFINITE_AMMO ) != 0;
+
+ s_fixed_fov_box.generic.type = MTYPE_SPINCONTROL;
+ s_fixed_fov_box.generic.x = 0;
+ s_fixed_fov_box.generic.y = y += 10;
+ s_fixed_fov_box.generic.name = "fixed FOV";
+ s_fixed_fov_box.generic.callback = DMFlagCallback;
+ s_fixed_fov_box.itemnames = yes_no_names;
+ s_fixed_fov_box.curvalue = ( dmflags & DF_FIXED_FOV ) != 0;
+
+ s_quad_drop_box.generic.type = MTYPE_SPINCONTROL;
+ s_quad_drop_box.generic.x = 0;
+ s_quad_drop_box.generic.y = y += 10;
+ s_quad_drop_box.generic.name = "quad drop";
+ s_quad_drop_box.generic.callback = DMFlagCallback;
+ s_quad_drop_box.itemnames = yes_no_names;
+ s_quad_drop_box.curvalue = ( dmflags & DF_QUAD_DROP ) != 0;
+
+ s_friendlyfire_box.generic.type = MTYPE_SPINCONTROL;
+ s_friendlyfire_box.generic.x = 0;
+ s_friendlyfire_box.generic.y = y += 10;
+ s_friendlyfire_box.generic.name = "friendly fire";
+ s_friendlyfire_box.generic.callback = DMFlagCallback;
+ s_friendlyfire_box.itemnames = yes_no_names;
+ s_friendlyfire_box.curvalue = ( dmflags & DF_NO_FRIENDLY_FIRE ) == 0;
+
+//============
+//ROGUE
+ if(Developer_searchpath(2) == 2)
+ {
+ s_no_mines_box.generic.type = MTYPE_SPINCONTROL;
+ s_no_mines_box.generic.x = 0;
+ s_no_mines_box.generic.y = y += 10;
+ s_no_mines_box.generic.name = "remove mines";
+ s_no_mines_box.generic.callback = DMFlagCallback;
+ s_no_mines_box.itemnames = yes_no_names;
+ s_no_mines_box.curvalue = ( dmflags & DF_NO_MINES ) != 0;
+
+ s_no_nukes_box.generic.type = MTYPE_SPINCONTROL;
+ s_no_nukes_box.generic.x = 0;
+ s_no_nukes_box.generic.y = y += 10;
+ s_no_nukes_box.generic.name = "remove nukes";
+ s_no_nukes_box.generic.callback = DMFlagCallback;
+ s_no_nukes_box.itemnames = yes_no_names;
+ s_no_nukes_box.curvalue = ( dmflags & DF_NO_NUKES ) != 0;
+
+ s_stack_double_box.generic.type = MTYPE_SPINCONTROL;
+ s_stack_double_box.generic.x = 0;
+ s_stack_double_box.generic.y = y += 10;
+ s_stack_double_box.generic.name = "2x/4x stacking off";
+ s_stack_double_box.generic.callback = DMFlagCallback;
+ s_stack_double_box.itemnames = yes_no_names;
+ s_stack_double_box.curvalue = ( dmflags & DF_NO_STACK_DOUBLE ) != 0;
+
+ s_no_spheres_box.generic.type = MTYPE_SPINCONTROL;
+ s_no_spheres_box.generic.x = 0;
+ s_no_spheres_box.generic.y = y += 10;
+ s_no_spheres_box.generic.name = "remove spheres";
+ s_no_spheres_box.generic.callback = DMFlagCallback;
+ s_no_spheres_box.itemnames = yes_no_names;
+ s_no_spheres_box.curvalue = ( dmflags & DF_NO_SPHERES ) != 0;
+
+ }
+//ROGUE
+//============
+
+ Menu_AddItem( &s_dmoptions_menu, &s_falls_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_weapons_stay_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_instant_powerups_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_powerups_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_health_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_armor_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_spawn_farthest_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_samelevel_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_force_respawn_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_teamplay_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_allow_exit_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_infinite_ammo_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_fixed_fov_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_quad_drop_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_friendlyfire_box );
+
+//=======
+//ROGUE
+ if(Developer_searchpath(2) == 2)
+ {
+ Menu_AddItem( &s_dmoptions_menu, &s_no_mines_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_no_nukes_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_stack_double_box );
+ Menu_AddItem( &s_dmoptions_menu, &s_no_spheres_box );
+ }
+//ROGUE
+//=======
+
+ Menu_Center( &s_dmoptions_menu );
+
+ // set the original dmflags statusbar
+ DMFlagCallback( 0 );
+ Menu_SetStatusBar( &s_dmoptions_menu, dmoptions_statusbar );
+}
+
+void DMOptions_MenuDraw(void)
+{
+ Menu_Draw( &s_dmoptions_menu );
+}
+
+char *DMOptions_MenuKey( int key )
+{
+ return Default_MenuKey( &s_dmoptions_menu, key );
+}
+
+void M_Menu_DMOptions_f (void)
+{
+ DMOptions_MenuInit();
+ M_PushMenu( DMOptions_MenuDraw, DMOptions_MenuKey );
+}
+
+/*
+=============================================================================
+
+DOWNLOADOPTIONS BOOK MENU
+
+=============================================================================
+*/
+static menuframework_t s_downloadoptions_menu;
+
+static menuseparator_t s_download_title;
+static menulist_t s_allow_download_box;
+static menulist_t s_allow_download_maps_box;
+static menulist_t s_allow_download_models_box;
+static menulist_t s_allow_download_players_box;
+static menulist_t s_allow_download_sounds_box;
+
+static void DownloadCallback( void *self )
+{
+ menulist_t *f = ( menulist_t * ) self;
+
+ if (f == &s_allow_download_box)
+ {
+ Cvar_SetValue("allow_download", f->curvalue);
+ }
+
+ else if (f == &s_allow_download_maps_box)
+ {
+ Cvar_SetValue("allow_download_maps", f->curvalue);
+ }
+
+ else if (f == &s_allow_download_models_box)
+ {
+ Cvar_SetValue("allow_download_models", f->curvalue);
+ }
+
+ else if (f == &s_allow_download_players_box)
+ {
+ Cvar_SetValue("allow_download_players", f->curvalue);
+ }
+
+ else if (f == &s_allow_download_sounds_box)
+ {
+ Cvar_SetValue("allow_download_sounds", f->curvalue);
+ }
+}
+
+void DownloadOptions_MenuInit( void )
+{
+ static char *yes_no_names[] =
+ {
+ "no", "yes", 0
+ };
+ int y = 0;
+
+ s_downloadoptions_menu.x = vid.width * 0.50;
+ s_downloadoptions_menu.nitems = 0;
+
+ s_download_title.generic.type = MTYPE_SEPARATOR;
+ s_download_title.generic.name = "Download Options";
+ s_download_title.generic.x = 48;
+ s_download_title.generic.y = y;
+
+ s_allow_download_box.generic.type = MTYPE_SPINCONTROL;
+ s_allow_download_box.generic.x = 0;
+ s_allow_download_box.generic.y = y += 20;
+ s_allow_download_box.generic.name = "allow downloading";
+ s_allow_download_box.generic.callback = DownloadCallback;
+ s_allow_download_box.itemnames = yes_no_names;
+ s_allow_download_box.curvalue = (Cvar_VariableValue("allow_download") != 0);
+
+ s_allow_download_maps_box.generic.type = MTYPE_SPINCONTROL;
+ s_allow_download_maps_box.generic.x = 0;
+ s_allow_download_maps_box.generic.y = y += 20;
+ s_allow_download_maps_box.generic.name = "maps";
+ s_allow_download_maps_box.generic.callback = DownloadCallback;
+ s_allow_download_maps_box.itemnames = yes_no_names;
+ s_allow_download_maps_box.curvalue = (Cvar_VariableValue("allow_download_maps") != 0);
+
+ s_allow_download_players_box.generic.type = MTYPE_SPINCONTROL;
+ s_allow_download_players_box.generic.x = 0;
+ s_allow_download_players_box.generic.y = y += 10;
+ s_allow_download_players_box.generic.name = "player models/skins";
+ s_allow_download_players_box.generic.callback = DownloadCallback;
+ s_allow_download_players_box.itemnames = yes_no_names;
+ s_allow_download_players_box.curvalue = (Cvar_VariableValue("allow_download_players") != 0);
+
+ s_allow_download_models_box.generic.type = MTYPE_SPINCONTROL;
+ s_allow_download_models_box.generic.x = 0;
+ s_allow_download_models_box.generic.y = y += 10;
+ s_allow_download_models_box.generic.name = "models";
+ s_allow_download_models_box.generic.callback = DownloadCallback;
+ s_allow_download_models_box.itemnames = yes_no_names;
+ s_allow_download_models_box.curvalue = (Cvar_VariableValue("allow_download_models") != 0);
+
+ s_allow_download_sounds_box.generic.type = MTYPE_SPINCONTROL;
+ s_allow_download_sounds_box.generic.x = 0;
+ s_allow_download_sounds_box.generic.y = y += 10;
+ s_allow_download_sounds_box.generic.name = "sounds";
+ s_allow_download_sounds_box.generic.callback = DownloadCallback;
+ s_allow_download_sounds_box.itemnames = yes_no_names;
+ s_allow_download_sounds_box.curvalue = (Cvar_VariableValue("allow_download_sounds") != 0);
+
+ Menu_AddItem( &s_downloadoptions_menu, &s_download_title );
+ Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_box );
+ Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_maps_box );
+ Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_players_box );
+ Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_models_box );
+ Menu_AddItem( &s_downloadoptions_menu, &s_allow_download_sounds_box );
+
+ Menu_Center( &s_downloadoptions_menu );
+
+ // skip over title
+ if (s_downloadoptions_menu.cursor == 0)
+ s_downloadoptions_menu.cursor = 1;
+}
+
+void DownloadOptions_MenuDraw(void)
+{
+ Menu_Draw( &s_downloadoptions_menu );
+}
+
+char *DownloadOptions_MenuKey( int key )
+{
+ return Default_MenuKey( &s_downloadoptions_menu, key );
+}
+
+void M_Menu_DownloadOptions_f (void)
+{
+ DownloadOptions_MenuInit();
+ M_PushMenu( DownloadOptions_MenuDraw, DownloadOptions_MenuKey );
+}
+/*
+=============================================================================
+
+ADDRESS BOOK MENU
+
+=============================================================================
+*/
+#define NUM_ADDRESSBOOK_ENTRIES 9
+
+static menuframework_t s_addressbook_menu;
+static menufield_t s_addressbook_fields[NUM_ADDRESSBOOK_ENTRIES];
+
+void AddressBook_MenuInit( void )
+{
+ int i;
+
+ s_addressbook_menu.x = vid.width / 2 - 142;
+ s_addressbook_menu.y = vid.height / 2 - 58;
+ s_addressbook_menu.nitems = 0;
+
+ for ( i = 0; i < NUM_ADDRESSBOOK_ENTRIES; i++ )
+ {
+ cvar_t *adr;
+ char buffer[20];
+
+ Com_sprintf( buffer, sizeof( buffer ), "adr%d", i );
+
+ adr = Cvar_Get( buffer, "", CVAR_ARCHIVE );
+
+ s_addressbook_fields[i].generic.type = MTYPE_FIELD;
+ s_addressbook_fields[i].generic.name = 0;
+ s_addressbook_fields[i].generic.callback = 0;
+ s_addressbook_fields[i].generic.x = 0;
+ s_addressbook_fields[i].generic.y = i * 18 + 0;
+ s_addressbook_fields[i].generic.localdata[0] = i;
+ s_addressbook_fields[i].cursor = 0;
+ s_addressbook_fields[i].length = 60;
+ s_addressbook_fields[i].visible_length = 30;
+
+ strcpy( s_addressbook_fields[i].buffer, adr->string );
+
+ Menu_AddItem( &s_addressbook_menu, &s_addressbook_fields[i] );
+ }
+}
+
+char *AddressBook_MenuKey( int key )
+{
+ if ( key == K_ESCAPE )
+ {
+ int index;
+ char buffer[20];
+
+ for ( index = 0; index < NUM_ADDRESSBOOK_ENTRIES; index++ )
+ {
+ Com_sprintf( buffer, sizeof( buffer ), "adr%d", index );
+ Cvar_Set( buffer, s_addressbook_fields[index].buffer );
+ }
+ }
+ return Default_MenuKey( &s_addressbook_menu, key );
+}
+
+void AddressBook_MenuDraw(void)
+{
+ M_Banner( "m_banner_addressbook" );
+ Menu_Draw( &s_addressbook_menu );
+}
+
+void M_Menu_AddressBook_f(void)
+{
+ AddressBook_MenuInit();
+ M_PushMenu( AddressBook_MenuDraw, AddressBook_MenuKey );
+}
+
+/*
+=============================================================================
+
+PLAYER CONFIG MENU
+
+=============================================================================
+*/
+static menuframework_t s_player_config_menu;
+static menufield_t s_player_name_field;
+static menulist_t s_player_model_box;
+static menulist_t s_player_skin_box;
+static menulist_t s_player_handedness_box;
+static menulist_t s_player_rate_box;
+static menuseparator_t s_player_skin_title;
+static menuseparator_t s_player_model_title;
+static menuseparator_t s_player_hand_title;
+static menuseparator_t s_player_rate_title;
+static menuaction_t s_player_download_action;
+
+#define MAX_DISPLAYNAME 16
+#define MAX_PLAYERMODELS 1024
+
+typedef struct
+{
+ int nskins;
+ char **skindisplaynames;
+ char displayname[MAX_DISPLAYNAME];
+ char directory[MAX_QPATH];
+} playermodelinfo_s;
+
+static playermodelinfo_s s_pmi[MAX_PLAYERMODELS];
+static char *s_pmnames[MAX_PLAYERMODELS];
+static int s_numplayermodels;
+
+static int rate_tbl[] = { 2500, 3200, 5000, 10000, 25000, 0 };
+static char *rate_names[] = { "28.8 Modem", "33.6 Modem", "Single ISDN",
+ "Dual ISDN/Cable", "T1/LAN", "User defined", 0 };
+
+void DownloadOptionsFunc( void * )
+{
+ M_Menu_DownloadOptions_f();
+}
+
+static void HandednessCallback( void * )
+{
+ Cvar_SetValue( "hand", s_player_handedness_box.curvalue );
+}
+
+static void RateCallback( void * )
+{
+ if (s_player_rate_box.curvalue != sizeof(rate_tbl) / sizeof(*rate_tbl) - 1)
+ Cvar_SetValue( "rate", rate_tbl[s_player_rate_box.curvalue] );
+}
+
+static void ModelCallback( void * )
+{
+ s_player_skin_box.itemnames = s_pmi[s_player_model_box.curvalue].skindisplaynames;
+ s_player_skin_box.curvalue = 0;
+}
+
+static void FreeFileList( char **list, int n )
+{
+ int i;
+
+ for ( i = 0; i < n; i++ )
+ {
+ if ( list[i] )
+ {
+ free( list[i] );
+ list[i] = 0;
+ }
+ }
+ free( list );
+}
+
+static qboolean IconOfSkinExists( char *skin, char **pcxfiles, int npcxfiles )
+{
+ int i;
+ char scratch[1024];
+
+ strcpy( scratch, skin );
+ *strrchr( scratch, '.' ) = 0;
+ strcat( scratch, "_i.pcx" );
+
+ for ( i = 0; i < npcxfiles; i++ )
+ {
+ if ( strcmp( pcxfiles[i], scratch ) == 0 )
+ return true;
+ }
+
+ return false;
+}
+
+static qboolean PlayerConfig_ScanDirectories( void )
+{
+ char findname[1024];
+ char scratch[1024];
+ int ndirs = 0, npms;
+ char **dirnames = NULL;
+ char *path = NULL;
+ int i;
+
+ extern char **FS_ListFiles( char *, int *, unsigned, unsigned );
+
+ s_numplayermodels = 0;
+
+ /*
+ ** get a list of directories
+ */
+ do
+ {
+ if ( ( path = FS_NextPath( path ) ) == NULL)
+ break;
+ Com_sprintf( findname, sizeof(findname), "%s/players/*.*", path );
+
+ if ( ( dirnames = FS_ListFiles( findname, &ndirs, SFF_SUBDIR, 0 ) ) != 0 )
+ break;
+ } while ( path );
+
+ if ( !dirnames )
+ return false;
+
+ /*
+ ** go through the subdirectories
+ */
+ npms = ndirs;
+ if ( npms > MAX_PLAYERMODELS )
+ npms = MAX_PLAYERMODELS;
+
+ for ( i = 0; i < npms; i++ )
+ {
+ int k, s;
+ char *a, *b, *c;
+ char **pcxnames;
+ char **skinnames;
+ int npcxfiles;
+ int nskins = 0;
+
+ if ( dirnames[i] == 0 )
+ continue;
+
+ // verify the existence of tris.md2
+ strcpy( scratch, dirnames[i] );
+ strcat( scratch, "/tris.md2" );
+ if ( !Sys_FindFirst( scratch, 0, SFF_SUBDIR ) )
+ {
+ free( dirnames[i] );
+ dirnames[i] = 0;
+ Sys_FindClose();
+ continue;
+ }
+ Sys_FindClose();
+
+ // verify the existence of at least one pcx skin
+ strcpy( scratch, dirnames[i] );
+ strcat( scratch, "/*.pcx" );
+ pcxnames = FS_ListFiles( scratch, &npcxfiles, 0, SFF_SUBDIR);
+
+ if ( !pcxnames )
+ {
+ free( dirnames[i] );
+ dirnames[i] = 0;
+ continue;
+ }
+
+ // count valid skins, which consist of a skin with a matching "_i" icon
+ for ( k = 0; k < npcxfiles-1; k++ )
+ {
+ if ( !strstr( pcxnames[k], "_i.pcx" ) )
+ {
+ if ( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles - 1 ) )
+ {
+ nskins++;
+ }
+ }
+ }
+ if ( !nskins )
+ continue;
+
+ skinnames = malloc( sizeof( char * ) * ( nskins + 1 ) );
+ memset( skinnames, 0, sizeof( char * ) * ( nskins + 1 ) );
+
+ // copy the valid skins
+ for ( s = 0, k = 0; k < npcxfiles-1; k++ )
+ {
+ char *a, *b, *c;
+
+ if ( !strstr( pcxnames[k], "_i.pcx" ) )
+ {
+ if ( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles - 1 ) )
+ {
+ a = strrchr( pcxnames[k], '/' );
+ b = strrchr( pcxnames[k], '\\' );
+
+ if ( a > b )
+ c = a;
+ else
+ c = b;
+
+ strcpy( scratch, c + 1 );
+
+ if ( strrchr( scratch, '.' ) )
+ *strrchr( scratch, '.' ) = 0;
+
+ skinnames[s] = strdup( scratch );
+ s++;
+ }
+ }
+ }
+
+ // at this point we have a valid player model
+ s_pmi[s_numplayermodels].nskins = nskins;
+ s_pmi[s_numplayermodels].skindisplaynames = skinnames;
+
+ // make short name for the model
+ a = strrchr( dirnames[i], '/' );
+ b = strrchr( dirnames[i], '\\' );
+
+ if ( a > b )
+ c = a;
+ else
+ c = b;
+
+ strncpy( s_pmi[s_numplayermodels].displayname, c + 1, MAX_DISPLAYNAME-1 );
+ strcpy( s_pmi[s_numplayermodels].directory, c + 1 );
+
+ FreeFileList( pcxnames, npcxfiles );
+
+ s_numplayermodels++;
+ }
+ if ( dirnames )
+ FreeFileList( dirnames, ndirs );
+ return true;
+}
+
+static int pmicmpfnc( void *_a, void *_b )
+{
+ playermodelinfo_s *a = ( playermodelinfo_s * ) _a;
+ playermodelinfo_s *b = ( playermodelinfo_s * ) _b;
+
+ /*
+ ** sort by male, female, then alphabetical
+ */
+ if ( strcmp( a->directory, "male" ) == 0 )
+ return -1;
+ else if ( strcmp( b->directory, "male" ) == 0 )
+ return 1;
+
+ if ( strcmp( a->directory, "female" ) == 0 )
+ return -1;
+ else if ( strcmp( b->directory, "female" ) == 0 )
+ return 1;
+
+ return strcmp( a->directory, b->directory );
+}
+
+
+qboolean PlayerConfig_MenuInit( void )
+{
+ extern cvar_t *name;
+ extern cvar_t *team;
+ extern cvar_t *skin;
+ char currentdirectory[1024];
+ char currentskin[1024];
+ int i;
+
+ int currentdirectoryindex = 0;
+ int currentskinindex = 0;
+
+ cvar_t *hand = Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE );
+
+ static char *handedness[] = { "right", "left", "center", 0 };
+
+ PlayerConfig_ScanDirectories();
+
+ if (s_numplayermodels == 0)
+ return false;
+
+ if ( hand->value < 0 || hand->value > 2 )
+ Cvar_SetValue( "hand", 0 );
+
+ strcpy( currentdirectory, skin->string );
+
+ if ( strchr( currentdirectory, '/' ) )
+ {
+ strcpy( currentskin, strchr( currentdirectory, '/' ) + 1 );
+ *strchr( currentdirectory, '/' ) = 0;
+ }
+ else if ( strchr( currentdirectory, '\\' ) )
+ {
+ strcpy( currentskin, strchr( currentdirectory, '\\' ) + 1 );
+ *strchr( currentdirectory, '\\' ) = 0;
+ }
+ else
+ {
+ strcpy( currentdirectory, "male" );
+ strcpy( currentskin, "grunt" );
+ }
+
+ qsort( s_pmi, s_numplayermodels, sizeof( s_pmi[0] ), pmicmpfnc );
+
+ memset( s_pmnames, 0, sizeof( s_pmnames ) );
+ for ( i = 0; i < s_numplayermodels; i++ )
+ {
+ s_pmnames[i] = s_pmi[i].displayname;
+ if ( cistrcmp( s_pmi[i].directory, currentdirectory ) == 0 )
+ {
+ int j;
+
+ currentdirectoryindex = i;
+
+ for ( j = 0; j < s_pmi[i].nskins; j++ )
+ {
+ if ( cistrcmp( s_pmi[i].skindisplaynames[j], currentskin ) == 0 )
+ {
+ currentskinindex = j;
+ break;
+ }
+ }
+ }
+ }
+
+ s_player_config_menu.x = vid.width / 2 - 95;
+ s_player_config_menu.y = vid.height / 2 - 97;
+ s_player_config_menu.nitems = 0;
+
+ s_player_name_field.generic.type = MTYPE_FIELD;
+ s_player_name_field.generic.name = "name";
+ s_player_name_field.generic.callback = 0;
+ s_player_name_field.generic.x = 0;
+ s_player_name_field.generic.y = 0;
+ s_player_name_field.length = 20;
+ s_player_name_field.visible_length = 20;
+ strcpy( s_player_name_field.buffer, name->string );
+ s_player_name_field.cursor = strlen( name->string );
+
+ s_player_model_title.generic.type = MTYPE_SEPARATOR;
+ s_player_model_title.generic.name = "model";
+ s_player_model_title.generic.x = -8;
+ s_player_model_title.generic.y = 60;
+
+ s_player_model_box.generic.type = MTYPE_SPINCONTROL;
+ s_player_model_box.generic.x = -56;
+ s_player_model_box.generic.y = 70;
+ s_player_model_box.generic.callback = ModelCallback;
+ s_player_model_box.generic.cursor_offset = -48;
+ s_player_model_box.curvalue = currentdirectoryindex;
+ s_player_model_box.itemnames = s_pmnames;
+
+ s_player_skin_title.generic.type = MTYPE_SEPARATOR;
+ s_player_skin_title.generic.name = "skin";
+ s_player_skin_title.generic.x = -16;
+ s_player_skin_title.generic.y = 84;
+
+ s_player_skin_box.generic.type = MTYPE_SPINCONTROL;
+ s_player_skin_box.generic.x = -56;
+ s_player_skin_box.generic.y = 94;
+ s_player_skin_box.generic.name = 0;
+ s_player_skin_box.generic.callback = 0;
+ s_player_skin_box.generic.cursor_offset = -48;
+ s_player_skin_box.curvalue = currentskinindex;
+ s_player_skin_box.itemnames = s_pmi[currentdirectoryindex].skindisplaynames;
+
+ s_player_hand_title.generic.type = MTYPE_SEPARATOR;
+ s_player_hand_title.generic.name = "handedness";
+ s_player_hand_title.generic.x = 32;
+ s_player_hand_title.generic.y = 108;
+
+ s_player_handedness_box.generic.type = MTYPE_SPINCONTROL;
+ s_player_handedness_box.generic.x = -56;
+ s_player_handedness_box.generic.y = 118;
+ s_player_handedness_box.generic.name = 0;
+ s_player_handedness_box.generic.cursor_offset = -48;
+ s_player_handedness_box.generic.callback = HandednessCallback;
+ s_player_handedness_box.curvalue = Cvar_VariableValue( "hand" );
+ s_player_handedness_box.itemnames = handedness;
+
+ for (i = 0; i < sizeof(rate_tbl) / sizeof(*rate_tbl) - 1; i++)
+ if (Cvar_VariableValue("rate") == rate_tbl[i])
+ break;
+
+ s_player_rate_title.generic.type = MTYPE_SEPARATOR;
+ s_player_rate_title.generic.name = "connect speed";
+ s_player_rate_title.generic.x = 56;
+ s_player_rate_title.generic.y = 156;
+
+ s_player_rate_box.generic.type = MTYPE_SPINCONTROL;
+ s_player_rate_box.generic.x = -56;
+ s_player_rate_box.generic.y = 166;
+ s_player_rate_box.generic.name = 0;
+ s_player_rate_box.generic.cursor_offset = -48;
+ s_player_rate_box.generic.callback = RateCallback;
+ s_player_rate_box.curvalue = i;
+ s_player_rate_box.itemnames = rate_names;
+
+ s_player_download_action.generic.type = MTYPE_ACTION;
+ s_player_download_action.generic.name = "download options";
+ s_player_download_action.generic.flags= QMF_LEFT_JUSTIFY;
+ s_player_download_action.generic.x = -24;
+ s_player_download_action.generic.y = 186;
+ s_player_download_action.generic.statusbar = NULL;
+ s_player_download_action.generic.callback = DownloadOptionsFunc;
+
+ Menu_AddItem( &s_player_config_menu, &s_player_name_field );
+ Menu_AddItem( &s_player_config_menu, &s_player_model_title );
+ Menu_AddItem( &s_player_config_menu, &s_player_model_box );
+ if ( s_player_skin_box.itemnames )
+ {
+ Menu_AddItem( &s_player_config_menu, &s_player_skin_title );
+ Menu_AddItem( &s_player_config_menu, &s_player_skin_box );
+ }
+ Menu_AddItem( &s_player_config_menu, &s_player_hand_title );
+ Menu_AddItem( &s_player_config_menu, &s_player_handedness_box );
+ Menu_AddItem( &s_player_config_menu, &s_player_rate_title );
+ Menu_AddItem( &s_player_config_menu, &s_player_rate_box );
+ Menu_AddItem( &s_player_config_menu, &s_player_download_action );
+
+ return true;
+}
+
+void PlayerConfig_MenuDraw( void )
+{
+ extern float CalcFov( float fov_x, float w, float h );
+ refdef_t refdef;
+ char scratch[MAX_QPATH];
+
+ memset( &refdef, 0, sizeof( refdef ) );
+
+ refdef.x = vid.width / 2;
+ refdef.y = vid.height / 2 - 72;
+ refdef.width = 144;
+ refdef.height = 168;
+ refdef.fov_x = 40;
+ refdef.fov_y = CalcFov( refdef.fov_x, refdef.width, refdef.height );
+ refdef.time = cls.realtime*0.001;
+
+ if ( s_pmi[s_player_model_box.curvalue].skindisplaynames )
+ {
+ static int yaw;
+ entity_t entity;
+
+ memset( &entity, 0, sizeof( entity ) );
+
+ Com_sprintf( scratch, sizeof( scratch ), "players/%s/tris.md2", s_pmi[s_player_model_box.curvalue].directory );
+ entity.model = re.RegisterModel( scratch );
+ Com_sprintf( scratch, sizeof( scratch ), "players/%s/%s.pcx", s_pmi[s_player_model_box.curvalue].directory, s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
+ entity.skin = re.RegisterSkin( scratch );
+ entity.flags = RF_FULLBRIGHT;
+ entity.origin[0] = 80;
+ entity.origin[1] = 0;
+ entity.origin[2] = 0;
+ VectorCopy( entity.origin, entity.oldorigin );
+ entity.frame = 0;
+ entity.oldframe = 0;
+ entity.backlerp = 0.0;
+ entity.angles[1] = yaw++;
+ if ( ++yaw > 360 )
+ yaw -= 360;
+
+ refdef.areabits = 0;
+ refdef.num_entities = 1;
+ refdef.entities = &entity;
+ refdef.lightstyles = 0;
+ refdef.rdflags = RDF_NOWORLDMODEL;
+
+ Menu_Draw( &s_player_config_menu );
+
+ M_DrawTextBox( ( refdef.x ) * ( 320.0F / vid.width ) - 8, ( vid.height / 2 ) * ( 240.0F / vid.height) - 77, refdef.width / 8, refdef.height / 8 );
+ refdef.height += 4;
+
+ re.RenderFrame( &refdef );
+
+ Com_sprintf( scratch, sizeof( scratch ), "/players/%s/%s_i.pcx",
+ s_pmi[s_player_model_box.curvalue].directory,
+ s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
+ re.DrawPic( s_player_config_menu.x - 40, refdef.y, scratch );
+ }
+}
+
+char *PlayerConfig_MenuKey (int key)
+{
+ int i;
+
+ if ( key == K_ESCAPE )
+ {
+ char scratch[1024];
+
+ Cvar_Set( "name", s_player_name_field.buffer );
+
+ Com_sprintf( scratch, sizeof( scratch ), "%s/%s",
+ s_pmi[s_player_model_box.curvalue].directory,
+ s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
+
+ Cvar_Set( "skin", scratch );
+
+ for ( i = 0; i < s_numplayermodels; i++ )
+ {
+ int j;
+
+ for ( j = 0; j < s_pmi[i].nskins; j++ )
+ {
+ if ( s_pmi[i].skindisplaynames[j] )
+ free( s_pmi[i].skindisplaynames[j] );
+ s_pmi[i].skindisplaynames[j] = 0;
+ }
+ free( s_pmi[i].skindisplaynames );
+ s_pmi[i].skindisplaynames = 0;
+ s_pmi[i].nskins = 0;
+ }
+ }
+ return Default_MenuKey( &s_player_config_menu, key );
+}
+
+
+void M_Menu_PlayerConfig_f (void)
+{
+ if (!PlayerConfig_MenuInit())
+ {
+ Menu_SetStatusBar( &s_multiplayer_menu, "No valid player models found" );
+ return;
+ }
+ Menu_SetStatusBar( &s_multiplayer_menu, NULL );
+ M_PushMenu( PlayerConfig_MenuDraw, PlayerConfig_MenuKey );
+}
+
+
+/*
+=======================================================================
+
+GALLERY MENU
+
+=======================================================================
+*/
+/* commented out in release
+void M_Menu_Gallery_f( void )
+{
+ extern void Gallery_MenuDraw( void );
+ extern char *Gallery_MenuKey( int key );
+
+ M_PushMenu( Gallery_MenuDraw, Gallery_MenuKey );
+}
+*/
+
+/*
+=======================================================================
+
+QUIT MENU
+
+=======================================================================
+*/
+
+char *M_Quit_Key (int key)
+{
+ switch (key)
+ {
+ case K_ESCAPE:
+ case 'n':
+ case 'N':
+ M_PopMenu ();
+ break;
+
+ case 'Y':
+ case 'y':
+ cls.key_dest = key_console;
+ CL_Quit_f ();
+ break;
+
+ default:
+ break;
+ }
+
+ return NULL;
+
+}
+
+
+void M_Quit_Draw (void)
+{
+ int w, h;
+
+ re.DrawGetPicSize (&w, &h, "quit");
+ re.DrawPic ( (vid.width-w)/2, (vid.height-h)/2, "quit");
+}
+
+
+void M_Menu_Quit_f (void)
+{
+ M_PushMenu (M_Quit_Draw, M_Quit_Key);
+}
+
+
+
+//=============================================================================
+/* Menu Subsystem */
+
+
+/*
+=================
+M_Init
+=================
+*/
+void M_Init (void)
+{
+ Cmd_AddCommand ("menu_main", M_Menu_Main_f);
+ Cmd_AddCommand ("menu_game", M_Menu_Game_f);
+ Cmd_AddCommand ("menu_loadgame", M_Menu_LoadGame_f);
+ Cmd_AddCommand ("menu_savegame", M_Menu_SaveGame_f);
+ Cmd_AddCommand ("menu_joinserver", M_Menu_JoinServer_f);
+ Cmd_AddCommand ("menu_addressbook", M_Menu_AddressBook_f);
+ Cmd_AddCommand ("menu_startserver", M_Menu_StartServer_f);
+ Cmd_AddCommand ("menu_dmoptions", M_Menu_DMOptions_f);
+ Cmd_AddCommand ("menu_playerconfig", M_Menu_PlayerConfig_f);
+ Cmd_AddCommand ("menu_downloadoptions", M_Menu_DownloadOptions_f);
+ Cmd_AddCommand ("menu_credits", M_Menu_Credits_f );
+ Cmd_AddCommand ("menu_multiplayer", M_Menu_Multiplayer_f );
+ Cmd_AddCommand ("menu_video", M_Menu_Video_f);
+ Cmd_AddCommand ("menu_options", M_Menu_Options_f);
+ Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
+ Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
+}
+
+
+/*
+=================
+M_Draw
+=================
+*/
+void M_Draw (void)
+{
+ if (cls.key_dest != key_menu)
+ return;
+
+ // repaint everything next frame
+ SCR_DirtyScreen ();
+
+ // dim everything behind it down
+ if (cl.cinematictime > 0)
+ re.DrawFill (0,0,vid.width, vid.height, 0);
+ else
+ re.DrawFadeScreen ();
+
+ m_drawfunc ();
+
+ // delay playing the enter sound until after the
+ // menu has been drawn, to avoid delay while
+ // caching images
+ if (m_entersound)
+ {
+ S_StartLocalSound( menu_in_sound );
+ m_entersound = false;
+ }
+}
+
+
+/*
+=================
+M_Keydown
+=================
+*/
+void M_Keydown (int key)
+{
+ char *s;
+
+ if (m_keyfunc)
+ if ( ( s = m_keyfunc( key ) ) != 0 )
+ S_StartLocalSound( ( char * ) s );
+}
+
+
--- a/mk.baseq2
+++ b/mk.baseq2
@@ -1,3 +1,5 @@
+TARG=quake2
+
GMOFILES=\
game/g_ai.$O\
game/p_client.$O\
@@ -49,7 +51,6 @@
game/q_shared.$O\
GMHFILES=\
- game/g_local.h\
game/game.h\
game/m_actor.h\
game/m_berserk.h\
--- a/mk.ctf
+++ b/mk.ctf
@@ -1,35 +1,32 @@
+TARG=q2ctf
+
GMOFILES=\
- ctf/g_ai.$O\
- ctf/g_chase.$O\
- ctf/g_cmds.$O\
- ctf/g_combat.$O\
- ctf/g_ctf.$O\
- ctf/g_func.$O\
- ctf/g_items.$O\
- ctf/g_main.$O\
- ctf/g_misc.$O\
- ctf/g_monster.$O\
- ctf/g_phys.$O\
- ctf/g_save.$O\
- ctf/g_spawn.$O\
- ctf/g_svcmds.$O\
- ctf/g_target.$O\
- ctf/g_trigger.$O\
- ctf/g_utils.$O\
- ctf/g_weapon.$O\
- ctf/m_move.$O\
- ctf/p_client.$O\
- ctf/p_hud.$O\
- ctf/p_menu.$O\
- ctf/p_trail.$O\
- ctf/p_view.$O\
- ctf/p_weapon.$O\
- ctf/q_shared.$O\
+ game/g_ai.$O\
+ game/g_chase.$O\
+ game/g_cmds.$O\
+ game/g_combat.$O\
+ game/g_game.$O\
+ game/g_func.$O\
+ game/g_items.$O\
+ game/g_main.$O\
+ game/g_misc.$O\
+ game/g_monster.$O\
+ game/g_phys.$O\
+ game/g_save.$O\
+ game/g_spawn.$O\
+ game/g_svcmds.$O\
+ game/g_target.$O\
+ game/g_trigger.$O\
+ game/g_utils.$O\
+ game/g_weapon.$O\
+ game/m_move.$O\
+ game/p_client.$O\
+ game/p_hud.$O\
+ game/p_menu.$O\
+ game/p_trail.$O\
+ game/p_view.$O\
+ game/p_weapon.$O\
+ game/q_shared.$O\
GMHFILES=\
- ctf/g_ctf.h\
- ctf/g_local.h\
- ctf/game.h\
- ctf/m_player.h\
- ctf/p_menu.h\
-
+ game/game.h\
--- a/mk.xatrix
+++ /dev/null
@@ -1,55 +1,0 @@
-GMFILES=\
- xatrix/g_ai.$O\
- xatrix/g_cmds.$O\
- xatrix/g_combat.$O\
- xatrix/g_func.$O\
- xatrix/g_items.$O\
- xatrix/g_main.$O\
- xatrix/g_misc.$O\
- xatrix/g_monster.$O\
- xatrix/g_phys.$O\
- xatrix/g_save.$O\
- xatrix/g_spawn.$O\
- xatrix/g_svcmds.$O\
- xatrix/g_target.$O\
- xatrix/g_trigger.$O\
- xatrix/g_turret.$O\
- xatrix/g_utils.$O\
- xatrix/g_weapon.$O\
- xatrix/m_actor.$O\
- xatrix/m_berserk.$O\
- xatrix/m_boss2.$O\
- xatrix/m_boss3.$O\
- xatrix/m_boss31.$O\
- xatrix/m_boss32.$O\
- xatrix/m_boss5.$O\
- xatrix/m_brain.$O\
- xatrix/m_chick.$O\
- xatrix/m_fixbot.$O\
- xatrix/m_flash.$O\
- xatrix/m_flipper.$O\
- xatrix/m_float.$O\
- xatrix/m_flyer.$O\
- xatrix/m_gekk.$O\
- xatrix/m_gladb.$O\
- xatrix/m_gladiator.$O\
- xatrix/m_gunner.$O\
- xatrix/m_hover.$O\
- xatrix/m_infantry.$O\
- xatrix/m_insane.$O\
- xatrix/m_medic.$O\
- xatrix/m_move.$O\
- xatrix/m_mutant.$O\
- xatrix/m_parasite.$O\
- xatrix/m_soldier.$O\
- xatrix/m_supertank.$O\
- xatrix/m_tank.$O\
- xatrix/p_client.$O\
- xatrix/p_hud.$O\
- xatrix/p_trail.$O\
- xatrix/p_view.$O\
- xatrix/p_weapon.$O\
- xatrix/q_shared.$O\
-
-GMHFILES=\
-
--- a/mkfile
+++ b/mkfile
@@ -1,95 +1,79 @@
</$objtype/mkfile
BIN=$home/bin/$objtype
-TARG=quake2
# change this to build/load a different game "dll"
<mk.baseq2
OFILES=\
- client/cl_cin.$O\
- client/cl_ents.$O\
- client/cl_fx.$O\
- client/cl_newfx.$O\
- client/cl_input.$O\
- client/cl_inv.$O\
- client/cl_main.$O\
- client/cl_parse.$O\
- client/cl_pred.$O\
- client/cl_tent.$O\
- client/cl_scrn.$O\
- client/cl_view.$O\
- client/console.$O\
- client/keys.$O\
- client/menu.$O\
- client/snd_dma.$O\
- client/snd_mem.$O\
- client/snd_mix.$O\
- client/qmenu.$O\
- server/sv_ccmds.$O\
- server/sv_ents.$O\
- server/sv_game.$O\
- server/sv_init.$O\
- server/sv_main.$O\
- server/sv_send.$O\
- server/sv_user.$O\
- server/sv_world.$O\
- qcommon/cmd.$O\
- qcommon/cmodel.$O\
- qcommon/common.$O\
- qcommon/crc.$O\
- qcommon/cvar.$O\
- qcommon/files.$O\
- qcommon/md4.$O\
- qcommon/net_chan.$O\
- qcommon/pmove.$O\
- plan9/cd.$O\
- plan9/in.$O\
- plan9/menu.$O\
- plan9/snd.$O\
- plan9/sys.$O\
- plan9/udp.$O\
- plan9/vid.$O\
- ref/r_aclip.$O\
- ref/r_alias.$O\
- ref/r_bsp.$O\
- ref/r_draw.$O\
- ref/r_edge.$O\
- ref/r_image.$O\
- ref/r_light.$O\
- ref/r_main.$O\
- ref/r_misc.$O\
- ref/r_model.$O\
- ref/r_part.$O\
- ref/r_poly.$O\
- ref/r_polyse.$O\
- ref/r_rast.$O\
- ref/r_scan.$O\
- ref/r_sprite.$O\
- ref/r_surf.$O\
+ cl_cin.$O\
+ cl_ents.$O\
+ cl_fx.$O\
+ cl_newfx.$O\
+ cl_input.$O\
+ cl_inv.$O\
+ cl_main.$O\
+ cl_parse.$O\
+ cl_pred.$O\
+ cl_tent.$O\
+ cl_scrn.$O\
+ cl_view.$O\
+ console.$O\
+ keys.$O\
+ menu.$O\
+ snd_dma.$O\
+ snd_mem.$O\
+ snd_mix.$O\
+ qmenu.$O\
+ sv_ccmds.$O\
+ sv_ents.$O\
+ sv_game.$O\
+ sv_init.$O\
+ sv_main.$O\
+ sv_send.$O\
+ sv_user.$O\
+ sv_world.$O\
+ cmd.$O\
+ cmodel.$O\
+ common.$O\
+ crc.$O\
+ cvar.$O\
+ files.$O\
+ md4.$O\
+ net_chan.$O\
+ pmove.$O\
+ cd.$O\
+ in.$O\
+ snd.$O\
+ sys.$O\
+ udp.$O\
+ vid.$O\
+ vmenu.$O\
+ r_aclip.$O\
+ r_alias.$O\
+ r_bsp.$O\
+ r_draw.$O\
+ r_edge.$O\
+ r_image.$O\
+ r_light.$O\
+ r_main.$O\
+ r_misc.$O\
+ r_model.$O\
+ r_part.$O\
+ r_poly.$O\
+ r_polyse.$O\
+ r_rast.$O\
+ r_scan.$O\
+ r_sprite.$O\
+ r_surf.$O\
$GMOFILES\
HFILES=\
+ adivtab.h\
anorms.h\
- q_shared.h\
- client/cdaudio.h\
- client/client.h\
- client/console.h\
- client/input.h\
- client/keys.h\
- client/qmenu.h\
- client/ref.h\
- client/screen.h\
- client/snd_loc.h\
- client/sound.h\
- client/vid.h\
- server/server.h\
- qcommon/crc.h\
- qcommon/qcommon.h\
- qcommon/qfiles.h\
- ref/adivtab.h\
- ref/r_local.h\
- ref/rand1k.h\
+ dat.h\
+ fns.h\
+ rand1k.h\
$GMHFILES\
# FIXME
--- /dev/null
+++ b/net_chan.c
@@ -1,0 +1,370 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/*
+
+packet header
+-------------
+31 sequence
+1 does this message contain a reliable payload
+31 acknowledge sequence
+1 acknowledge receipt of even/odd message
+16 qport
+
+The remote connection never knows if it missed a reliable message, the
+local side detects that it has been dropped by seeing a sequence acknowledge
+higher thatn the last reliable sequence, but without the correct evon/odd
+bit for the reliable set.
+
+If the sender notices that a reliable message has been dropped, it will be
+retransmitted. It will not be retransmitted again until a message after
+the retransmit has been acknowledged and the reliable still failed to get there.
+
+if the sequence number is -1, the packet should be handled without a netcon
+
+The reliable message can be added to at any time by doing
+MSG_Write* (&netchan->message, <data>).
+
+If the message buffer is overflowed, either by a single message, or by
+multiple frames worth piling up while the last reliable transmit goes
+unacknowledged, the netchan signals a fatal error.
+
+Reliable messages are always placed first in a packet, then the unreliable
+message is included if there is sufficient room.
+
+To the receiver, there is no distinction between the reliable and unreliable
+parts of the message, they are just processed out as a single larger message.
+
+Illogical packet sequence numbers cause the packet to be dropped, but do
+not kill the connection. This, combined with the tight window of valid
+reliable acknowledgement numbers provides protection against malicious
+address spoofing.
+
+
+The qport field is a workaround for bad address translating routers that
+sometimes remap the client's source port on a packet during gameplay.
+
+If the base part of the net address matches and the qport matches, then the
+channel matches even if the IP port differs. The IP port should be updated
+to the new value before sending out any replies.
+
+
+If there is no information that needs to be transfered on a given frame,
+such as during the connection stage while waiting for the client to load,
+then a packet only needs to be delivered if there is something in the
+unacknowledged reliable
+*/
+
+cvar_t *showpackets;
+cvar_t *showdrop;
+cvar_t *qport;
+
+netadr_t net_from;
+sizebuf_t net_message;
+byte net_message_buffer[MAX_MSGLEN];
+
+/*
+===============
+Netchan_Init
+
+===============
+*/
+void Netchan_Init (void)
+{
+ int port;
+
+ // pick a port value that should be nice and random
+ port = Sys_Milliseconds() & 0xffff;
+
+ showpackets = Cvar_Get ("showpackets", "0", 0);
+ showdrop = Cvar_Get ("showdrop", "0", 0);
+ qport = Cvar_Get ("qport", va("%i", port), CVAR_NOSET);
+}
+
+/*
+===============
+Netchan_OutOfBand
+
+Sends an out-of-band datagram
+================
+*/
+void Netchan_OutOfBand (int net_socket, netadr_t adr, int length, byte *data)
+{
+ sizebuf_t send;
+ byte send_buf[MAX_MSGLEN];
+
+// write the packet header
+ SZ_Init (&send, send_buf, sizeof(send_buf));
+
+ MSG_WriteLong (&send, -1); // -1 sequence means out of band
+ SZ_Write (&send, data, length);
+
+// send the datagram
+ NET_SendPacket (net_socket, send.cursize, send.data, adr);
+}
+
+/*
+===============
+Netchan_OutOfBandPrint
+
+Sends a text message in an out-of-band datagram
+================
+*/
+void Netchan_OutOfBandPrint (int net_socket, netadr_t adr, char *format, ...)
+{
+ va_list argptr;
+ static char string[MAX_MSGLEN - 4];
+
+ va_start (argptr, format);
+ vsprintf (string, format,argptr);
+ va_end (argptr);
+
+ Netchan_OutOfBand (net_socket, adr, strlen(string), (byte *)string);
+}
+
+
+/*
+==============
+Netchan_Setup
+
+called to open a channel to a remote system
+==============
+*/
+void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t adr, int qport)
+{
+ memset (chan, 0, sizeof(*chan));
+
+ chan->sock = sock;
+ chan->remote_address = adr;
+ chan->qport = qport;
+ chan->last_received = curtime;
+ chan->incoming_sequence = 0;
+ chan->outgoing_sequence = 1;
+
+ SZ_Init (&chan->message, chan->message_buf, sizeof(chan->message_buf));
+ chan->message.allowoverflow = true;
+}
+
+
+/*
+===============
+Netchan_CanReliable
+
+Returns true if the last reliable message has acked
+================
+*/
+qboolean Netchan_CanReliable (netchan_t *chan)
+{
+ if (chan->reliable_length)
+ return false; // waiting for ack
+ return true;
+}
+
+
+qboolean Netchan_NeedReliable (netchan_t *chan)
+{
+ qboolean send_reliable;
+
+// if the remote side dropped the last reliable message, resend it
+ send_reliable = false;
+
+ if (chan->incoming_acknowledged > chan->last_reliable_sequence
+ && chan->incoming_reliable_acknowledged != chan->reliable_sequence)
+ send_reliable = true;
+
+// if the reliable transmit buffer is empty, copy the current message out
+ if (!chan->reliable_length && chan->message.cursize)
+ {
+ send_reliable = true;
+ }
+
+ return send_reliable;
+}
+
+/*
+===============
+Netchan_Transmit
+
+tries to send an unreliable message to a connection, and handles the
+transmition / retransmition of the reliable messages.
+
+A 0 length will still generate a packet and deal with the reliable messages.
+================
+*/
+void Netchan_Transmit (netchan_t *chan, int length, byte *data)
+{
+ sizebuf_t send;
+ byte send_buf[MAX_MSGLEN];
+ qboolean send_reliable;
+ unsigned w1, w2;
+
+// check for message overflow
+ if (chan->message.overflowed)
+ {
+ chan->fatal_error = true;
+ Com_Printf ("%s:Outgoing message overflow\n"
+ , NET_AdrToString (chan->remote_address));
+ return;
+ }
+
+ send_reliable = Netchan_NeedReliable (chan);
+
+ if (!chan->reliable_length && chan->message.cursize)
+ {
+ memcpy (chan->reliable_buf, chan->message_buf, chan->message.cursize);
+ chan->reliable_length = chan->message.cursize;
+ chan->message.cursize = 0;
+ chan->reliable_sequence ^= 1;
+ }
+
+
+// write the packet header
+ SZ_Init (&send, send_buf, sizeof(send_buf));
+
+ w1 = ( chan->outgoing_sequence & ~(1<<31) ) | (send_reliable<<31);
+ w2 = ( chan->incoming_sequence & ~(1<<31) ) | (chan->incoming_reliable_sequence<<31);
+
+ chan->outgoing_sequence++;
+ chan->last_sent = curtime;
+
+ MSG_WriteLong (&send, w1);
+ MSG_WriteLong (&send, w2);
+
+ // send the qport if we are a client
+ if (chan->sock == NS_CLIENT)
+ MSG_WriteShort (&send, qport->value);
+
+// copy the reliable message to the packet first
+ if (send_reliable)
+ {
+ SZ_Write (&send, chan->reliable_buf, chan->reliable_length);
+ chan->last_reliable_sequence = chan->outgoing_sequence;
+ }
+
+// add the unreliable part if space is available
+ if (send.maxsize - send.cursize >= length)
+ SZ_Write (&send, data, length);
+ else
+ Com_Printf ("Netchan_Transmit: dumped unreliable\n");
+
+// send the datagram
+ NET_SendPacket (chan->sock, send.cursize, send.data, chan->remote_address);
+
+ if (showpackets->value)
+ {
+ if (send_reliable)
+ Com_Printf ("send %4i : s=%i reliable=%i ack=%i rack=%i\n"
+ , send.cursize
+ , chan->outgoing_sequence - 1
+ , chan->reliable_sequence
+ , chan->incoming_sequence
+ , chan->incoming_reliable_sequence);
+ else
+ Com_Printf ("send %4i : s=%i ack=%i rack=%i\n"
+ , send.cursize
+ , chan->outgoing_sequence - 1
+ , chan->incoming_sequence
+ , chan->incoming_reliable_sequence);
+ }
+}
+
+/*
+=================
+Netchan_Process
+
+called when the current net_message is from remote_address
+modifies net_message so that it points to the packet payload
+=================
+*/
+qboolean Netchan_Process (netchan_t *chan, sizebuf_t *msg)
+{
+ unsigned sequence, sequence_ack;
+ unsigned reliable_ack, reliable_message;
+
+// get sequence numbers
+ MSG_BeginReading (msg);
+ sequence = MSG_ReadLong (msg);
+ sequence_ack = MSG_ReadLong (msg);
+
+ // read the qport if we are a server
+ if (chan->sock == NS_SERVER)
+ MSG_ReadShort (msg); /* toss read */
+
+ reliable_message = sequence >> 31;
+ reliable_ack = sequence_ack >> 31;
+
+ sequence &= ~(1<<31);
+ sequence_ack &= ~(1<<31);
+
+ if (showpackets->value)
+ {
+ if (reliable_message)
+ Com_Printf ("recv %4i : s=%i reliable=%i ack=%i rack=%i\n"
+ , msg->cursize
+ , sequence
+ , chan->incoming_reliable_sequence ^ 1
+ , sequence_ack
+ , reliable_ack);
+ else
+ Com_Printf ("recv %4i : s=%i ack=%i rack=%i\n"
+ , msg->cursize
+ , sequence
+ , sequence_ack
+ , reliable_ack);
+ }
+
+//
+// discard stale or duplicated packets
+//
+ if (sequence <= chan->incoming_sequence)
+ {
+ if (showdrop->value)
+ Com_Printf ("%s:Out of order packet %i at %i\n"
+ , NET_AdrToString (chan->remote_address)
+ , sequence
+ , chan->incoming_sequence);
+ return false;
+ }
+
+//
+// dropped packets don't keep the message from being used
+//
+ chan->dropped = sequence - (chan->incoming_sequence+1);
+ if (chan->dropped > 0)
+ {
+ if (showdrop->value)
+ Com_Printf ("%s:Dropped %i packets at %i\n"
+ , NET_AdrToString (chan->remote_address)
+ , chan->dropped
+ , sequence);
+ }
+
+//
+// if the current outgoing reliable message has been acknowledged
+// clear the buffer to make way for the next
+//
+ if (reliable_ack == chan->reliable_sequence)
+ chan->reliable_length = 0; // it has been received
+
+//
+// if this message contains a reliable message, bump incoming_reliable_sequence
+//
+ chan->incoming_sequence = sequence;
+ chan->incoming_acknowledged = sequence_ack;
+ chan->incoming_reliable_acknowledged = reliable_ack;
+ if (reliable_message)
+ {
+ chan->incoming_reliable_sequence ^= 1;
+ }
+
+//
+// the message can now be read from the current message pointer
+//
+ chan->last_received = curtime;
+
+ return true;
+}
+
--- a/plan9/cd.c
+++ /dev/null
@@ -1,414 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-qboolean cdValid = false;
-qboolean playing = false;
-qboolean wasPlaying = false;
-qboolean initialized = false;
-qboolean enabled = true;
-qboolean playLooping = false;
-float cdvolume;
-byte remap[100];
-byte playTrack;
-byte maxTrack;
-int cdfile = -1;
-
-cvar_t *cd_volume;
-cvar_t *cd_nocd;
-cvar_t *cd_dev;
-
-
-void CDAudio_Eject(void)
-{
- if (cdfile == -1 || !enabled)
- return;
-
- Com_DPrintf("CDAudio_Eject: PORTME\n");
- /*
- if ( ioctl(cdfile, CDROMEJECT) == -1 )
- Com_DPrintf("ioctl cdromeject failed\n");
- */
-}
-
-void CDAudio_CloseDoor(void)
-{
- if (cdfile == -1 || !enabled)
- return;
-
- Com_DPrintf("CDAudio_CloseDoor: PORTME\n");
- /*
- if ( ioctl(cdfile, CDROMCLOSETRAY) == -1 )
- Com_DPrintf("ioctl cdromclosetray failed\n");
- */
-}
-
-int CDAudio_GetAudioDiskInfo(void)
-{
- cdValid = false;
- Com_DPrintf("CDAudio_GetAudioDiskInfo: PORTME\n");
- return -1;
-
- /*
- struct cdrom_tochdr tochdr;
-
- if ( ioctl(cdfile, CDROMREADTOCHDR, &tochdr) == -1 )
- {
- Com_DPrintf("ioctl cdromreadtochdr failed\n");
- return -1;
- }
-
- if (tochdr.cdth_trk0 < 1)
- {
- Com_DPrintf("CDAudio: no music tracks\n");
- return -1;
- }
-
- cdValid = true;
- maxTrack = tochdr.cdth_trk1;
- return 0;
- */
-}
-
-void CDAudio_Pause(void)
-{
- if (cdfile == -1 || !enabled)
- return;
- if (!playing)
- return;
-
- Com_DPrintf("CDAudio_GetAudioDiskInfo: PORTME\n");
-
- /*
- if ( ioctl(cdfile, CDROMPAUSE) == -1 )
- Com_DPrintf("ioctl cdrompause failed\n");
-
- wasPlaying = playing;
- playing = false;
- */
-}
-
-void CDAudio_Play(int track, qboolean looping)
-{
- if (cdfile == -1 || !enabled)
- return;
- if (!cdValid)
- {
- CDAudio_GetAudioDiskInfo();
- if (!cdValid)
- return;
- }
-
- track = remap[track];
- if (track < 1 || track > maxTrack)
- {
- Com_DPrintf("CDAudio: Bad track number %u.\n", track);
- return;
- }
-
- USED(looping);
- Com_DPrintf("CDAudio_Play: PORTME\n");
-
- /*
- struct cdrom_tocentry entry;
- struct cdrom_ti ti;
-
- // don't try to play a non-audio track
- entry.cdte_track = track;
- entry.cdte_format = CDROM_MSF;
- if ( ioctl(cdfile, CDROMREADTOCENTRY, &entry) == -1 )
- {
- Com_DPrintf("ioctl cdromreadtocentry failed\n");
- return;
- }
- if (entry.cdte_ctrl == CDROM_DATA_TRACK)
- {
- Com_Printf("CDAudio: track %i is not audio\n", track);
- return;
- }
-
- if (playing)
- {
- if (playTrack == track)
- return;
- CDAudio_Stop();
- }
-
- ti.cdti_trk0 = track;
- ti.cdti_trk1 = track;
- ti.cdti_ind0 = 1;
- ti.cdti_ind1 = 99;
- if ( ioctl(cdfile, CDROMPLAYTRKIND, &ti) == -1 )
- {
- Com_DPrintf("ioctl cdromplaytrkind failed\n");
- return;
- }
- if ( ioctl(cdfile, CDROMRESUME) == -1 )
- Com_DPrintf("ioctl cdromresume failed\n");
-
- playLooping = looping;
- playTrack = track;
- playing = true;
-
- if (cd_volume->value == 0.0)
- CDAudio_Pause ();
- */
-}
-
-
-void CDAudio_Stop(void)
-{
- if (cdfile == -1 || !enabled)
- return;
- if (!playing)
- return;
-
- Com_DPrintf("CDAudio_Stop: PORTME\n");
-
- /*
- if ( ioctl(cdfile, CDROMSTOP) == -1 )
- Com_DPrintf("ioctl cdromstop failed (%d)\n", errno);
-
- wasPlaying = false;
- playing = false;
- */
-}
-
-void CDAudio_Resume(void)
-{
- if (cdfile == -1 || !enabled)
- return;
- if (!cdValid)
- return;
- if (!wasPlaying)
- return;
-
- Com_DPrintf("CDAudio_Stop: PORTME\n");
-
- /*
- if ( ioctl(cdfile, CDROMRESUME) == -1 )
- Com_DPrintf("ioctl cdromresume failed\n");
- playing = true;
- */
-}
-
-static void CD_f (void)
-{
- char *command;
- int n, ret;
-
- if (Cmd_Argc() < 2)
- return;
-
- command = Cmd_Argv (1);
-
- if (cistrcmp(command, "on") == 0)
- {
- enabled = true;
- return;
- }
-
- if (cistrcmp(command, "off") == 0)
- {
- if (playing)
- CDAudio_Stop();
- enabled = false;
- return;
- }
-
- if (cistrcmp(command, "reset") == 0)
- {
- enabled = true;
- if (playing)
- CDAudio_Stop();
- for (n = 0; n < 100; n++)
- remap[n] = n;
- CDAudio_GetAudioDiskInfo();
- return;
- }
-
- if (cistrcmp(command, "remap") == 0)
- {
- ret = Cmd_Argc() - 2;
- if (ret <= 0)
- {
- for (n = 1; n < 100; n++)
- if (remap[n] != n)
- Com_Printf(" %u -> %u\n", n, remap[n]);
- return;
- }
- for (n = 1; n <= ret; n++)
- remap[n] = atoi(Cmd_Argv (n+1));
- return;
- }
-
- if (cistrcmp(command, "close") == 0)
- {
- CDAudio_CloseDoor();
- return;
- }
-
- if (!cdValid)
- {
- CDAudio_GetAudioDiskInfo();
- if (!cdValid)
- {
- Com_Printf("No CD in player.\n");
- return;
- }
- }
-
- if (cistrcmp(command, "play") == 0)
- {
- CDAudio_Play((byte)atoi(Cmd_Argv (2)), false);
- return;
- }
-
- if (cistrcmp(command, "loop") == 0)
- {
- CDAudio_Play((byte)atoi(Cmd_Argv (2)), true);
- return;
- }
-
- if (cistrcmp(command, "stop") == 0)
- {
- CDAudio_Stop();
- return;
- }
-
- if (cistrcmp(command, "pause") == 0)
- {
- CDAudio_Pause();
- return;
- }
-
- if (cistrcmp(command, "resume") == 0)
- {
- CDAudio_Resume();
- return;
- }
-
- if (cistrcmp(command, "eject") == 0)
- {
- if (playing)
- CDAudio_Stop();
- CDAudio_Eject();
- cdValid = false;
- return;
- }
-
- if (cistrcmp(command, "info") == 0)
- {
- Com_Printf("%u tracks\n", maxTrack);
- if (playing)
- Com_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack);
- else if (wasPlaying)
- Com_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack);
- Com_Printf("Volume is %f\n", cdvolume);
- return;
- }
-}
-
-void CDAudio_Update(void)
-{
- if (cdfile == -1 || !enabled)
- return;
- if (cd_volume && cd_volume->value != cdvolume)
- {
- if (cdvolume)
- {
- Cvar_SetValue ("cd_volume", 0.0);
- cdvolume = cd_volume->value;
- CDAudio_Pause ();
- }
- else
- {
- Cvar_SetValue ("cd_volume", 1.0);
- cdvolume = cd_volume->value;
- CDAudio_Resume ();
- }
- }
-
- Com_DPrintf("CDAudio_Stop: PORTME\n");
-
- /*
- struct cdrom_subchnl subchnl;
- static time_t lastchk;
-
- if (playing && lastchk < time(NULL)) {
- lastchk = time(NULL) + 2; //two seconds between chks
- subchnl.cdsc_format = CDROM_MSF;
- if (ioctl(cdfile, CDROMSUBCHNL, &subchnl) == -1 ) {
- Com_DPrintf("ioctl cdromsubchnl failed\n");
- playing = false;
- return;
- }
- if (subchnl.cdsc_audiostatus != CDROM_AUDIO_PLAY &&
- subchnl.cdsc_audiostatus != CDROM_AUDIO_PAUSED) {
- playing = false;
- if (playLooping)
- CDAudio_Play(playTrack, true);
- }
- }
- */
-}
-
-int CDAudio_Init(void)
-{
- int i;
- cvar_t *cv;
-
- cv = Cvar_Get ("nocdaudio", "0", CVAR_NOSET);
- if (cv->value)
- return -1;
-
- cd_nocd = Cvar_Get ("cd_nocd", "0", CVAR_ARCHIVE );
- if ( cd_nocd->value)
- return -1;
-
- cd_volume = Cvar_Get ("cd_volume", "1", CVAR_ARCHIVE);
-
- cd_dev = Cvar_Get("cd_dev", "/dev/cdrom", CVAR_ARCHIVE);
-
- if((cdfile = open(cd_dev->string, OREAD)) < 0){
- fprint(2, "CDAudio_Init: %r\n");
- Com_Printf("CDAudio_Init: failed to open \"%s\"\n", cd_dev->string);
- cdfile = -1;
- return -1;
- }
-
- for (i = 0; i < 100; i++)
- remap[i] = i;
- initialized = true;
- enabled = true;
-
- if (CDAudio_GetAudioDiskInfo())
- {
- Com_Printf("CDAudio_Init: No CD in player.\n");
- cdValid = false;
- }
-
- Cmd_AddCommand ("cd", CD_f);
-
- Com_Printf("CD Audio Initialized\n");
-
- return 0;
-}
-
-void CDAudio_Activate (qboolean active)
-{
- if (active)
- CDAudio_Resume ();
- else
- CDAudio_Pause ();
-}
-
-void CDAudio_Shutdown(void)
-{
- if (!initialized)
- return;
- CDAudio_Stop();
- close(cdfile);
- cdfile = -1;
-}
--- a/plan9/in.c
+++ /dev/null
@@ -1,454 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <draw.h>
-#include <thread.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include "../q_shared.h"
-
-extern int resized; /* vid.c */
-extern Point center;
-extern Channel *fuckchan, *tchan; /* sys.c */
-
-cvar_t *in_joystick;
-cvar_t *sensitivity;
-cvar_t *lookstrafe;
-cvar_t *lookspring;
-cvar_t *freelook;
-cvar_t *m_pitch;
-
-static cvar_t *m_filter;
-static cvar_t *m_windowed;
-static cvar_t *m_yaw;
-static cvar_t *m_side;
-static cvar_t *m_forward;
-
-static int mouseon;
-static int mlooking;
-static int dx, dy;
-static int oldmwin;
-
-typedef struct Kev Kev;
-struct Kev{
- int key;
- int down;
-};
-enum{
- Nbuf = 64
-};
-static Channel *kchan, *mchan;
-static int iop = -1, pfd[2];
-static QLock killock;
-
-
-char *
-Sys_ConsoleInput(void)
-{
- static char buf[256];
- int n;
-
- if(dedicated != nil && dedicated->value && iop >= 0){
- if(flen(pfd[1]) < 1) /* only poll for input */
- return nil;
- if((n = read(pfd[1], buf, sizeof buf)) < 0)
- sysfatal("Sys_ConsoleInput:read: %r");
- if(n == 0){
- iop = -1;
- return nil;
- }
- return buf;
- }
- return nil;
-}
-
-void
-IN_Grabm(int on)
-{
- static char nocurs[2*4+2*2*16];
- static int fd = -1;
-
- if(mouseon == on)
- return;
- if(mouseon = on && m_windowed->value){
- if((fd = open("/dev/cursor", ORDWR|OCEXEC)) < 0){
- sysfatal("IN_Grabm:open: %r\n");
- return;
- }
- write(fd, nocurs, sizeof nocurs);
- }else if(fd >= 0){
- close(fd);
- fd = -1;
- }
-}
-
-void
-IN_Commands(void)
-{
- /* joystick stuff */
-}
-
-void
-btnev(int btn, ulong msec)
-{
- static int oldb;
- int i, b;
-
- for(i = 0; i < 3; i++){
- b = 1<<i;
- if(btn & b && ~oldb & b)
- Key_Event(K_MOUSE1+i, true, msec);
- else if(~btn & b && oldb & b)
- Key_Event(K_MOUSE1+i, false, msec);
- }
- oldb = btn;
- /* mwheelup and mwheeldn buttons are never held down */
- for(i = 3; i < 5; i++){
- b = 1<<i;
- if(btn & b){
- Key_Event(K_MOUSE1+i, true, msec);
- Key_Event(K_MOUSE1+i, false, msec);
- }
- }
-}
-
-void
-KBD_Update(void)
-{
- int r;
- Kev ev;
- Mouse m;
-
- if(oldmwin != m_windowed->value){
- oldmwin = m_windowed->value;
- IN_Grabm(m_windowed->value);
- }
- while((r = nbrecv(kchan, &ev)) > 0)
- Key_Event(ev.key, ev.down, Sys_Milliseconds());
- if(r < 0)
- sysfatal("KBD_Update:nbrecv: %r\n");
- while((r = nbrecv(mchan, &m)) > 0){
- dx += m.xy.x;
- dy += m.xy.y;
- btnev(m.buttons, m.msec);
- }
- if(r < 0)
- sysfatal("KBD_Update:nbrecv: %r\n");
-}
-
-void
-IN_Move(usercmd_t *cmd)
-{
- static int oldmx, oldmy;
- int mx, my;
-
- if(!mouseon)
- return;
-
- if(m_filter->value){
- mx = (dx + oldmx) * 0.5;
- my = (dy + oldmy) * 0.5;
- }else{
- mx = dx;
- my = dy;
- }
- oldmx = dx;
- oldmy = dy;
- dx = dy = 0;
- if(!mx && !my)
- return;
- mx *= sensitivity->value;
- my *= sensitivity->value;
-
- /* add mouse x/y movement to cmd */
- if(in_strafe.state & 1 || lookstrafe->value && mlooking)
- cmd->sidemove += m_side->value * mx;
- else
- cl.viewangles[YAW] -= m_yaw->value * mx;
- if((mlooking || freelook->value) && ~in_strafe.state & 1)
- cl.viewangles[PITCH] += m_pitch->value * my;
- else
- cmd->forwardmove -= m_forward->value * my;
-}
-
-/* called on focus/unfocus in win32 */
-void
-IN_Activate(qboolean)
-{
-}
-
-/* called every frame even if not generating commands */
-void
-IN_Frame(void)
-{
-}
-
-void
-IN_ForceCenterView(void)
-{
- cl.viewangles[PITCH] = 0;
-}
-
-void
-IN_MLookDown(void)
-{
- mlooking = true;
-}
-
-void
-IN_MLookUp(void)
-{
- mlooking = false;
- IN_CenterView();
-}
-
-static int
-runetokey(Rune r)
-{
- int k = 0;
-
- switch(r){
- case Kpgup: k = K_PGUP; break;
- case Kpgdown: k = K_PGDN; break;
- case Khome: k = K_HOME; break;
- case Kend: k = K_END; break;
- case Kleft: k = K_LEFTARROW; break;
- case Kright: k = K_RIGHTARROW; break;
- case Kdown: k = K_DOWNARROW; break;
- case Kup: k = K_UPARROW; break;
- case Kesc: k = K_ESCAPE; break;
- case '\n': k = K_ENTER; break;
- case '\t': k = K_TAB; break;
- case KF|1: k = K_F1; break;
- case KF|2: k = K_F2; break;
- case KF|3: k = K_F3; break;
- case KF|4: k = K_F4; break;
- case KF|5: k = K_F5; break;
- case KF|6: k = K_F6; break;
- case KF|7: k = K_F7; break;
- case KF|8: k = K_F8; break;
- case KF|9: k = K_F9; break;
- case KF|10: k = K_F10; break;
- case KF|11: k = K_F11; break;
- case KF|12: k = K_F12; break;
- case Kbs: k = K_BACKSPACE; break;
- case Kdel: k = K_DEL; break;
- case Kbreak: k = K_PAUSE; break;
- case Kshift: k = K_SHIFT; break;
- case Kctl: k = K_CTRL; break;
- case Kalt:
- case Kaltgr: k = K_ALT; break;
- case Kins: k = K_INS; break;
- default:
- if(r < 0x80)
- k = r;
- };
- return k;
-}
-
-static void
-kproc(void *)
-{
- int n, k, fd;
- char buf[128], kdown[128], *s;
- Rune r;
- Kev ev;
-
- if(threadsetgrp(THin) < 0)
- sysfatal("kproc:threadsetgrp: %r");
- if((fd = open("/dev/kbd", OREAD)) < 0)
- sysfatal("open /dev/kbd: %r");
-
- kdown[0] = kdown[1] = 0;
- while((n = read(fd, buf, sizeof buf)) > 0){
- buf[n-1] = 0;
- switch(*buf){
- case 'c':
- default:
- continue;
- case 'k':
- s = buf+1;
- while(*s){
- s += chartorune(&r, s);
- if(utfrune(kdown+1, r) == nil){
- if(k = runetokey(r)){
- ev.key = k;
- ev.down = true;
- if(send(kchan, &ev) < 0)
- sysfatal("kproc:nbsend: %r\n");
- }
- }
- }
- break;
- case 'K':
- s = kdown+1;
- while(*s){
- s += chartorune(&r, s);
- if(utfrune(buf+1, r) == nil){
- if(k = runetokey(r)){
- ev.key = k;
- ev.down = false;
- if(send(kchan, &ev) < 0)
- sysfatal("mproc:nbsend: %r\n");
- }
- }
- }
- break;
- }
- strcpy(kdown, buf);
- }
- fprint(2, "kproc: %r\n");
- close(fd);
-}
-
-static void
-mproc(void *)
-{
- int n, nerr = 0, fd;
- char buf[1+5*12];
- Mouse m;
-
- if(threadsetgrp(THin) < 0)
- sysfatal("mproc:threadsetgrp: %r");
- if((fd = open("/dev/mouse", ORDWR)) < 0)
- sysfatal("open /dev/mouse: %r");
-
- for(;;){
- if((n = read(fd, buf, sizeof buf)) != 1+4*12){
- fprint(2, "mproc:read: bad count %d not 49: %r\n", n);
- if(n < 0 || ++nerr > 10)
- break;
- continue;
- }
- nerr = 0;
- switch(*buf){
- case 'r':
- resized = 1;
- /* fall through */
- case 'm':
- if(!mouseon)
- break;
-
- m.xy.x = atoi(buf+1+0*12) - center.x;
- m.xy.y = atoi(buf+1+1*12) - center.y;
- if(m.xy.x != 0 || m.xy.y != 0)
- fprint(fd, "m%d %d", center.x, center.y);
- m.buttons = atoi(buf+1+2*12);
- m.msec = atoi(buf+1+3*12);
- if(nbsend(mchan, &m) < 0)
- sysfatal("mproc:nbsend: %r\n");
- break;
- }
- }
- fprint(2, "mproc: %r\n");
- IN_Grabm(0);
- close(fd);
-}
-
-static void
-tproc(void *) /* stupid select() timeout bullshit */
-{
- int t, ms, n, r;
-
- threadsetgrp(THin);
-
- t = ms = 0;
- for(;;){
- sleep(1);
- t++;
-
- if((r = nbrecv(tchan, &n)) < 0)
- sysfatal("tproc:nbrecv: %r");
- if(r == 0){
- if(t == ms && nbsend(fuckchan, nil) < 0)
- sysfatal("tproc:nbsend: %r");
- continue;
- }
- if(n <= 0)
- ms = 0;
- else{
- ms = n;
- t = 0;
- }
- }
-}
-
-static void
-iproc(void *)
-{
- int n;
- char s[256];
-
- threadsetgrp(THin);
-
- if((iop = pipe(pfd)) < 0)
- sysfatal("iproc:pipe: %r");
- for(;;){
- if((n = read(0, s, sizeof s)) <= 0)
- break;
- s[n-1] = 0;
- if((write(pfd[0], s, n)) != n)
- break;
- if(nbsend(fuckchan, nil) < 0)
- sysfatal("iproc:nbsend: %r");
- }
- fprint(2, "iproc %d: %r\n", threadpid(threadid()));
- iop = -1;
-}
-
-void
-IN_Shutdown(void)
-{
- qlock(&killock); /* there can be only one */
- IN_Grabm(0);
- threadkillgrp(THin);
- iop = -1;
- close(pfd[0]);
- close(pfd[1]);
- if(kchan != nil){
- chanfree(kchan);
- kchan = nil;
- }
- if(mchan != nil){
- chanfree(mchan);
- mchan = nil;
- }
- qunlock(&killock);
-}
-
-void
-IN_Init(void)
-{
- if(dedicated->value){
- if(proccreate(iproc, nil, 8192) < 0)
- sysfatal("proccreate iproc: %r");
- if(proccreate(tproc, nil, 8192) < 0)
- sysfatal("proccreate tproc: %r");
- return;
- }
- in_joystick = Cvar_Get("in_joystick", "0", CVAR_ARCHIVE);
- sensitivity = Cvar_Get("sensitivity", "3", CVAR_ARCHIVE);
- freelook = Cvar_Get("freelook", "0", CVAR_ARCHIVE);
- lookspring = Cvar_Get("lookspring", "0", CVAR_ARCHIVE);
- lookstrafe = Cvar_Get("lookstrafe", "0", CVAR_ARCHIVE);
- m_pitch = Cvar_Get("m_pitch", "0.022", CVAR_ARCHIVE);
-
- m_yaw = Cvar_Get("m_yaw", "0.022", 0);
- m_forward = Cvar_Get("m_forward", "1", 0);
- m_side = Cvar_Get("m_side", "0.8", 0);
- m_windowed = Cvar_Get("m_windowed", "0", CVAR_ARCHIVE);
- m_filter = Cvar_Get("m_filter", "0", 0);
-
- Cmd_AddCommand("+mlook", IN_MLookDown);
- Cmd_AddCommand("-mlook", IN_MLookUp);
- Cmd_AddCommand("force_centerview", IN_ForceCenterView);
-
- if((kchan = chancreate(sizeof(Kev), Nbuf)) == nil)
- sysfatal("chancreate kchan: %r");
- if(proccreate(kproc, nil, 8192) < 0)
- sysfatal("proccreate kproc: %r");
- if((mchan = chancreate(sizeof(Mouse), Nbuf)) == nil)
- sysfatal("chancreate kchan: %r");
- if(proccreate(mproc, nil, 8192) < 0)
- sysfatal("proccreate mproc: %r");
-}
--- a/plan9/menu.c
+++ /dev/null
@@ -1,137 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-extern void M_PopMenu(void);
-
-static menuframework_s vmenu;
-static menuslider_s ssizeslide, gammaslide;
-static menulist_s fullscrbox;
-static menuaction_s applyaction, defaultsaction;
-
-
-void
-vmssize(void *s)
-{
- Cvar_SetValue("viewsize", ((menuslider_s *)s)->curvalue * 10);
-}
-
-void
-vmgamma(void *s)
-{
- // invert sense so greater = brighter, and scale to a range of 0.5 to 1.3
- Cvar_SetValue("vid_gamma", 0.8 - (((menuslider_s *)s)->curvalue/10.0 - 0.5) + 0.5);
-}
-
-void
-vmreset(void *)
-{
- VID_MenuInit();
-}
-
-void
-vmapply(void *)
-{
- Cvar_SetValue("vid_gamma", 0.8 - (gammaslide.curvalue/10.0 - 0.5) + 0.5);
- Cvar_SetValue("vid_fullscreen", fullscrbox.curvalue);
- M_ForceMenuOff();
-}
-
-void
-VID_MenuInit(void)
-{
- static char *yesno[] = {"no", "yes", nil};
-
- if(!scr_viewsize)
- scr_viewsize = Cvar_Get("viewsize", "100", CVAR_ARCHIVE);
- ssizeslide.curvalue = scr_viewsize->value/10;
-
- vmenu.x = vid.width * 0.50;
- vmenu.nitems = 0;
-
- ssizeslide.generic.type = MTYPE_SLIDER;
- ssizeslide.generic.x = 0;
- ssizeslide.generic.y = 20;
- ssizeslide.generic.name = "screen size";
- ssizeslide.minvalue = 3;
- ssizeslide.maxvalue = 12;
- ssizeslide.generic.callback = vmssize;
-
- gammaslide.generic.type = MTYPE_SLIDER;
- gammaslide.generic.x = 0;
- gammaslide.generic.y = 30;
- gammaslide.generic.name = "gamma";
- gammaslide.generic.callback = vmgamma;
- gammaslide.minvalue = 5;
- gammaslide.maxvalue = 13;
- gammaslide.curvalue = (1.3 - vid_gamma->value + 0.5) * 10;
-
- fullscrbox.generic.type = MTYPE_SPINCONTROL;
- fullscrbox.generic.x = 0;
- fullscrbox.generic.y = 40;
- fullscrbox.generic.name = "fullscreen";
- fullscrbox.itemnames = yesno;
- fullscrbox.curvalue = vid_fullscreen->value;
-
- defaultsaction.generic.type = MTYPE_ACTION;
- defaultsaction.generic.name = "reset to default";
- defaultsaction.generic.x = 0;
- defaultsaction.generic.y = 90;
- defaultsaction.generic.callback = vmreset;
-
- applyaction.generic.type = MTYPE_ACTION;
- applyaction.generic.name = "apply";
- applyaction.generic.x = 0;
- applyaction.generic.y = 100;
- applyaction.generic.callback = vmapply;
-
- Menu_AddItem(&vmenu, (void *)&ssizeslide);
- Menu_AddItem(&vmenu, (void *)&gammaslide);
- Menu_AddItem(&vmenu, (void *)&fullscrbox);
- Menu_AddItem(&vmenu, (void *)&defaultsaction);
- Menu_AddItem(&vmenu, (void *)&applyaction);
-
- Menu_Center(&vmenu);
- vmenu.x -= 8;
-}
-
-void
-VID_MenuDraw(void)
-{
- int w, h;
-
- Draw_GetPicSize(&w, &h, "m_banner_video");
- Draw_Pic(vid.width/2 - w/2, vid.height/2 - 110, "m_banner_video");
- Menu_AdjustCursor(&vmenu, 1); // starting position
- Menu_Draw(&vmenu);
-}
-
-char *VID_MenuKey (int key)
-{
- static char *sound = "misc/menu1.wav";
-
- switch(key){
- case K_ESCAPE:
- M_PopMenu();
- return NULL;
- case K_UPARROW:
- vmenu.cursor--;
- Menu_AdjustCursor(&vmenu, -1);
- break;
- case K_DOWNARROW:
- vmenu.cursor++;
- Menu_AdjustCursor(&vmenu, 1);
- break;
- case K_LEFTARROW:
- Menu_SlideItem(&vmenu, -1);
- break;
- case K_RIGHTARROW:
- Menu_SlideItem(&vmenu, 1);
- break;
- case K_ENTER:
- Menu_SelectItem(&vmenu);
- break;
- }
- return sound;
-}
--- a/plan9/snd.c
+++ /dev/null
@@ -1,128 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <thread.h>
-#include "../q_shared.h"
-
-static cvar_t *sndbits;
-static cvar_t *sndspeed;
-static cvar_t *sndchannels;
-static cvar_t *snddev;
-
-static int afd, sndon, wpos;
-enum{
- Nbuf = 32
-};
-static Channel *schan;
-static QLock sndlock;
-
-
-static void
-sproc(void *)
-{
- int n;
-
- threadsetgrp(THsnd);
-
- for(;;){
- if(recv(schan, nil) < 0){
- fprint(2, "sproc:recv %r\n");
- break;
- }
- if((n = write(afd, dma.buffer, dma.samplebits/8 * dma.samples)) < 0){
- fprint(2, "sproc:write %r\n");
- break;
- }
- qlock(&sndlock);
- wpos += n;
- qunlock(&sndlock);
- }
- fprint(2, "sproc %d: %r\n", threadpid(threadid()));
-}
-
-qboolean
-SNDDMA_Init(void)
-{
- if(sndon)
- return false;
-
- if(COM_CheckParm("-nosound"))
- return false;
-
- if(snddev == nil){
- sndbits = Cvar_Get("sndbits", "16", CVAR_ARCHIVE);
- sndspeed = Cvar_Get("sndspeed", "44100", CVAR_ARCHIVE);
- sndchannels = Cvar_Get("sndchannels", "2", CVAR_ARCHIVE);
- snddev = Cvar_Get("snddev", "/dev/audio", CVAR_ARCHIVE);
- }
-
- if((afd = open(snddev->string, OWRITE)) < 0){
- fprint(2, "SNDDMA_Init:open %r\n");
- return false;
- }
-
- dma.samplebits = (int)sndbits->value;
- if(dma.samplebits != 16 && dma.samplebits != 8)
- dma.samplebits = 16;
- dma.speed = (int)sndspeed->value;
- if(dma.speed != 44100)
- dma.speed = 44100;
- dma.channels = (int)sndchannels->value;
- if(dma.channels < 1 || dma.channels > 2)
- dma.channels = 2;
- dma.samples = 8192;
- dma.submission_chunk = 1;
- if((dma.buffer = mallocz(dma.samplebits/8 * dma.samples, 1)) == nil)
- sysfatal("SNDDMA_Init:mallocz: %r\n");
- dma.samplepos = 0;
- sndon = 1;
- wpos = 0;
-
- schan = chancreate(sizeof(int), Nbuf);
- if(proccreate(sproc, nil, 8192) < 0){
- SNDDMA_Shutdown();
- sysfatal("SNDDMA_Init:proccreate: %r\n");
- }
- return true;
-}
-
-int
-SNDDMA_GetDMAPos(void)
-{
- if(!sndon)
- return 0;
- qlock(&sndlock);
- dma.samplepos = wpos / (dma.samplebits/8);
- qunlock(&sndlock);
- return dma.samplepos;
-}
-
-void
-SNDDMA_Shutdown(void)
-{
- if(!sndon)
- return;
-
- threadkillgrp(THsnd);
- close(afd);
- if(schan != nil){
- chanfree(schan);
- schan = nil;
- }
- free(dma.buffer);
- sndon = 0;
-}
-
-void
-SNDDMA_Submit(void)
-{
- if(nbsend(schan, nil) < 0){
- fprint(2, "SNDDMA_Submit:nbsend: %r\n");
- SNDDMA_Shutdown();
- }
-}
-
-void
-SNDDMA_BeginPainting(void)
-{
-}
--- a/plan9/sys.c
+++ /dev/null
@@ -1,452 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <thread.h>
-#include "../q_shared.h"
-
-void KBD_Update(void);
-
-mainstacksize = 512*1024;
-int curtime;
-uint sys_frame_time;
-Channel *fuckchan, *tchan;
-
-static uchar *membase;
-static int maxhunksize, curhunksize;
-static char findbase[MAX_OSPATH], findpath[MAX_OSPATH], findpattern[MAX_OSPATH];
-static Dir *dirs;
-static long dirn, di;
-
-static int glob_match(char *, char *);
-
-
-/* Like glob_match, but match PATTERN against any final segment of TEXT. */
-static int
-glob_match_after_star(char *pattern, char *text)
-{
- char *p = pattern, *t = text;
- char c, c1;
-
- while ((c = *p++) == '?' || c == '*')
- if (c == '?' && *t++ == '\0')
- return 0;
-
- if (c == '\0')
- return 1;
-
- if (c == '\\')
- c1 = *p;
- else
- c1 = c;
-
- while (1) {
- if ((c == '[' || *t == c1) && glob_match(p - 1, t))
- return 1;
- if (*t++ == '\0')
- return 0;
- }
-}
-
-/* Return nonzero if PATTERN has any special globbing chars in it. */
-static int
-glob_pattern_p(char *pattern)
-{
- char *p = pattern;
- char c;
- int open = 0;
-
- while ((c = *p++) != '\0')
- switch (c) {
- case '?':
- case '*':
- return 1;
-
- case '[': /* Only accept an open brace if there is a close */
- open++; /* brace to match it. Bracket expressions must be */
- continue; /* complete, according to Posix.2 */
- case ']':
- if (open)
- return 1;
- continue;
-
- case '\\':
- if (*p++ == '\0')
- return 0;
- }
-
- return 0;
-}
-
-/* Match the pattern PATTERN against the string TEXT;
- return 1 if it matches, 0 otherwise.
-
- A match means the entire string TEXT is used up in matching.
-
- In the pattern string, `*' matches any sequence of characters,
- `?' matches any character, [SET] matches any character in the specified set,
- [!SET] matches any character not in the specified set.
-
- A set is composed of characters or ranges; a range looks like
- character hyphen character (as in 0-9 or A-Z).
- [0-9a-zA-Z_] is the set of characters allowed in C identifiers.
- Any other character in the pattern must be matched exactly.
-
- To suppress the special syntactic significance of any of `[]*?!-\',
- and match the character exactly, precede it with a `\'.
-*/
-
-static int
-glob_match(char *pattern, char *text)
-{
- char *p = pattern, *t = text;
- char c, c1, cstart, cend;
- int invert;
-
- while ((c = *p++) != '\0')
- switch (c) {
- case '?':
- if (*t == '\0')
- return 0;
- else
- ++t;
- break;
-
- case '\\':
- if (*p++ != *t++)
- return 0;
- break;
-
- case '*':
- return glob_match_after_star(p, t);
-
- case '[':
- {
- c1 = *t++;
-
- if (!c1)
- return (0);
-
- invert = ((*p == '!') || (*p == '^'));
- if (invert)
- p++;
-
- c = *p++;
- while (1) {
- cstart = c;
- cend = c;
-
- if (c == '\\') {
- cstart = *p++;
- cend = cstart;
- }
- if (c == '\0')
- return 0;
-
- c = *p++;
- if (c == '-' && *p != ']') {
- cend = *p++;
- if (cend == '\\')
- cend = *p++;
- if (cend == '\0')
- return 0;
- c = *p++;
- }
- if (c1 >= cstart && c1 <= cend)
- goto match;
- if (c == ']')
- break;
- }
- if (!invert)
- return 0;
- break;
-
- match:
- /* Skip the rest of the [...] construct that already matched. */
- while (c != ']') {
- if (c == '\0')
- return 0;
- c = *p++;
- if (c == '\0')
- return 0;
- else if (c == '\\')
- ++p;
- }
- if (invert)
- return 0;
- break;
- }
-
- default:
- if (c != *t++)
- return 0;
- }
-
- /* if the pattern is empty, Sys_FindNext looks at the current file anyway */
- return *t == '\0';
-}
-
-void *
-Hunk_Begin(int maxsize)
-{
- // reserve a huge chunk of memory, but don't commit any yet
- maxhunksize = maxsize;
- curhunksize = 0;
- if((membase = mallocz(maxhunksize, 1)) == nil)
- sysfatal("Hunk_Begin:malloc %d: %r", maxhunksize);
- return membase;
-}
-
-void *
-Hunk_Alloc(int size)
-{
- byte *buf;
-
- // round to cacheline
- size = (size+31)&~31;
- if(curhunksize + size > maxhunksize)
- Sys_Error("Hunk_Alloc overflow");
- buf = membase + curhunksize;
- curhunksize += size;
- return buf;
-}
-
-int
-Hunk_End(void)
-{
- if(realloc(membase, curhunksize) != membase)
- sysfatal("Hunk_End:realloc: %r");
- return curhunksize;
-}
-
-void
-Hunk_Free(void *base)
-{
- if(base != nil)
- free(base);
-}
-
-static qboolean
-CompareAttributes(ulong m, uint musthave, uint canthave)
-{
- if(m & DMDIR && canthave & SFF_SUBDIR)
- return false;
- if(musthave & SFF_SUBDIR && ~m & DMDIR)
- return false;
- return true;
-}
-
-char *
-Sys_FindFirst(char *path, uint musthave, uint canhave)
-{
- char *p;
- int fd;
-
- if(dirs != nil)
- Sys_Error("Sys_BeginFind without close");
-
- strncpy(findbase, path, sizeof findbase-1);
- if((p = strrchr(findbase, '/')) != nil){
- *p = 0;
- strncpy(findpattern, p+1, sizeof findpattern-1);
- }else
- strcpy(findpattern, "*");
- if(strcmp(findpattern, "*.*") == 0)
- strcpy(findpattern, "*");
- if(*findpattern == '\0'){
- Com_Printf("Sys_BeginFind: empty pattern\n");
- return nil;
- }
-
- if((fd = open(findbase, OREAD)) < 0){
- fprint(2, "Sys_BeginFind:open: %r\n");
- return nil;
- }
- dirn = dirreadall(fd, &dirs);
- close(fd);
- if(dirn == 0)
- return nil;
- if(dirn < 0){
- fprint(2, "Sys_BeginFind:dirread: %r\n");
- return nil;
- }
-
- di = 0;
- return Sys_FindNext (musthave, canhave);
-}
-
-char *
-Sys_FindNext(uint musthave, uint canhave)
-{
- int i;
-
- if(dirs == nil)
- Sys_Error("Sys_FindNext without open\n");
-
- while(di < dirn){
- i = di++;
- if(glob_match(findpattern, dirs[i].name)){
- if(CompareAttributes(dirs[i].mode, musthave, canhave)){
- snprintf(findpath, sizeof findpath, "%s/%s", findbase, dirs[i].name);
- return findpath;
- }
- }
- }
- return nil;
-}
-
-void
-Sys_FindClose(void)
-{
- if(dirs != nil){
- free(dirs);
- dirs = nil;
- }
-}
-
-/* prints to "debugging console" */
-void
-Sys_ConsoleOutput(char *s)
-{
- write(1, s, strlen(s));
-}
-
-void
-Sys_Error(char *error, ...)
-{
- char buf[1024], *out;
- va_list arg;
-
- CL_Shutdown();
-
- va_start(arg, error);
- out = vseprint(buf, buf+sizeof(buf), error, arg);
- va_end(arg);
- write(2, buf, out-buf);
- print("\n");
- sysfatal("ending.");
-}
-
-int
-Sys_Milliseconds(void)
-{
- static long msbase;
-
- if(msbase == 0)
- msbase = time(nil)*1000;
- curtime = nsec()/1000000 - msbase;
- return curtime;
-}
-
-void
-Sys_Mkdir(char *path)
-{
- int d;
-
- if((d = create(path, OREAD, DMDIR|0777)) < 0)
- fprint(2, "Sys_Mkdir:create: %r\n");
- else
- close(d);
-}
-
-vlong
-flen(int fd)
-{
- uchar bs[1024];
-
- if(fstat(fd, bs, sizeof bs) < 0){
- fprint(2, "flen:fstat: %r\n");
- return -1;
- }
- return *((vlong *)(bs+2+2+4+1+4+8+4+4+4)); /* length[8] */
-}
-
-int
-Sys_FileTime(char *path)
-{
- uchar sb[1024];
-
- if(stat(path, sb, sizeof sb) < 0){
- fprint(2, "Sys_FileTime:stat: %r\n");
- return -1;
- }
- return *((int *)(sb+25));
-}
-
-void
-Sys_UnloadGame(void)
-{
-}
-
-void
-Sys_AppActivate(void)
-{
-}
-
-void
-Sys_SendKeyEvents(void)
-{
- KBD_Update();
- sys_frame_time = Sys_Milliseconds(); // grab frame time
-}
-
-char *
-Sys_GetClipboardData(void)
-{
- return nil;
-}
-
-void
-Sys_CopyProtect(void)
-{
-}
-
-void
-Sys_Quit(void)
-{
- chanfree(fuckchan);
- chanfree(tchan);
- threadexitsall(nil);
-}
-
-void
-Sys_Init(void)
-{
- //Sys_SetFPCW();
- if((fuckchan = chancreate(sizeof(int), 1)) == nil)
- sysfatal("chancreate fuckchan: %r");
- if((tchan = chancreate(sizeof(int), 16)) == nil)
- sysfatal("chancreate tchan: %r");
-}
-
-void
-croak(void *, char *note)
-{
- if(!strncmp(note, "sys:", 4)){
- IN_Shutdown();
- SNDDMA_Shutdown();
- NET_Shutdown();
- }
- noted(NDFLT);
-}
-
-void
-threadmain(int argc, char *argv[])
-{
- int time, oldtime, newtime;
-
- setfcr(getfcr() & ~(FPOVFL|FPUNFL|FPINVAL|FPZDIV)); /* assumed ignored in code */
- notify(croak);
-
- Qcommon_Init(argc, argv);
-
- oldtime = Sys_Milliseconds();
- for(;;){
- do{
- newtime = Sys_Milliseconds();
- time = newtime - oldtime;
- }while(time < 1); // find time spent rendering last frame
- Qcommon_Frame(time);
- oldtime = newtime;
- }
-}
--- a/plan9/udp.c
+++ /dev/null
@@ -1,552 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include <thread.h>
-#include <bio.h>
-#include <ndb.h>
-#include <ip.h>
-#include "../q_shared.h"
-
-/* FIXME: this shit SUCKS, and ipv4 only because of other code */
-
-extern Channel *fuckchan, *tchan;
-
-static cvar_t *svport; /* server port and copy of string value */
-static char srv[6];
-static cvar_t *clport; /* "client" port and copy */
-static char clsrv[6];
-
-typedef struct Loopmsg Loopmsg;
-typedef struct Loopback Loopback;
-typedef struct Conmsg Conmsg;
-typedef struct Conlist Conlist;
-
-enum{
- Hdrsz = 16+16+16+2+2, /* sizeof Udphdr w/o padding */
- Bufsz = MAX_MSGLEN,
- Nbuf = 64,
- MAX_LOOPBACK = 4,
- CLPORT = 27909
-};
-struct Loopmsg{
- byte data[MAX_MSGLEN];
- int datalen;
-};
-struct Loopback{
- Loopmsg msgs[MAX_LOOPBACK];
- int get;
- int send;
-};
-static Loopback loopbacks[2];
-
-struct Conlist{
- Conlist *p;
- uchar u[IPaddrlen+2];
- char addr[IPaddrlen*2+8+6]; /* ipv6 + separators + port in decimal */
- int dfd;
- Udphdr h;
- int src; /* q2 assumes broadcast replies are received on NS_CLIENT */
-};
-static Conlist *cnroot;
-
-struct Conmsg{
- Conlist *p;
- int n;
- uchar buf[Bufsz];
-};
-static Channel *udpchan, *clchan;
-
-static netadr_t laddr; /* 0.0.0.0:0 */
-static int cfd = -1, ufd = -1, clfd = -1, cldfd = -1;
-static QLock cnlock;
-
-
-qboolean
-NET_CompareAdr(netadr_t a, netadr_t b)
-{
- return(a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port);
-}
-
-/* compares without the port */
-qboolean
-NET_CompareBaseAdr(netadr_t a, netadr_t b)
-{
- if(a.type != b.type)
- return false;
- switch(a.type){
- case NA_LOOPBACK:
- return true;
- case NA_IP:
- return (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3]);
- case NA_IPX:
- return !memcmp(a.ipx, b.ipx, 10);
- default:
- return false;
- }
-}
-
-char *
-NET_AdrToString(netadr_t a)
-{
- static char s[256];
-
- seprint(s, s+sizeof s, "%ud.%ud.%ud.%ud:%hud", a.ip[0], a.ip[1], a.ip[2], a.ip[3], BigShort(a.port));
- return s;
-}
-
-char *
-NET_BaseAdrToString(netadr_t a)
-{
- static char s[256];
-
- seprint(s, s+sizeof s, "%ud.%ud.%ud.%ud", a.ip[0], a.ip[1], a.ip[2], a.ip[3]);
- return s;
-}
-
-/*
-=============
-NET_StringToAdr
-
-localhost
-idnewt
-idnewt:28000
-192.246.40.70
-192.246.40.70:28000
-=============
-*/
-qboolean
-NET_StringToAdr(char *addr, netadr_t *a) /* assumes IPv4 */
-{
- int i;
- char s[256], *p, *pp;
- Ndbtuple *t, *nt;
-
- if(!strcmp(addr, "localhost")){
- memset(a, 0, sizeof *a);
- a->type = NA_LOOPBACK;
- return true;
- }
-
- strncpy(s, addr, sizeof s);
- s[sizeof(s)-1] = 0;
-
- /* FIXME: arbitrary length strings */
- if((p = strrchr(s, ':')) != nil){
- *p++ = '\0';
- a->port = BigShort(atoi(p));
- }
-
- if((t = dnsquery(nil, s, "ip")) == nil){
- fprint(2, "NET_StringToAdr:dnsquery %s: %r\n", s);
- return 0;
- }
-
- for(nt = t; nt != nil; nt = nt->entry)
- if(!strcmp(nt->attr, "ip")){
- strncpy(s, nt->val, sizeof(s)-1);
- break;
- }
- ndbfree(t);
-
- /* FIXMEGASHIT */
- for(i = 0, pp = s; i < IPv4addrlen; i++){
- if((p = strchr(pp, '.')) != nil)
- *p++ = '\0';
- a->ip[i] = atoi(pp);
- pp = p;
- }
- a->type = NA_IP;
- return true;
-}
-
-qboolean
-NET_IsLocalAddress(netadr_t adr)
-{
- return NET_CompareAdr(adr, laddr);
-}
-
-static int
-looprecv(netsrc_t sock, netadr_t *net_from, sizebuf_t *d)
-{
- int i;
- Loopback *l;
-
- l = &loopbacks[sock];
- if(l->send - l->get > MAX_LOOPBACK)
- l->get = l->send - MAX_LOOPBACK;
- if(l->get >= l->send)
- return 0;
- i = l->get & (MAX_LOOPBACK-1);
- l->get++;
-
- memcpy(d->data, l->msgs[i].data, l->msgs[i].datalen);
- d->cursize = l->msgs[i].datalen;
- *net_from = laddr;
- return 1;
-}
-
-static void
-loopsend(netsrc_t sock, int length, void *data, netadr_t /*to*/)
-{
- Loopback *l;
- int i;
-
- l = &loopbacks[sock^1];
- i = l->send & (MAX_LOOPBACK-1);
- l->send++;
- memcpy(l->msgs[i].data, data, length);
- l->msgs[i].datalen = length;
-}
-
-static void
-cninit(void)
-{
- if(cnroot != nil)
- return;
- if((cnroot = malloc(sizeof *cnroot)) == nil)
- sysfatal("cninit:malloc: %r");
- cnroot->p = cnroot;
- memset(cnroot->u, 0, sizeof cnroot->u);
- memset(cnroot->addr, 0, sizeof cnroot->addr);
- cnroot->dfd = -1;
-}
-
-static Conlist *
-cnins(int fd, char *addr, uchar *u, Udphdr *h, int src)
-{
- Conlist *p, *l;
-
- l = cnroot;
- if((p = malloc(sizeof *p)) == nil)
- sysfatal("cnins:malloc: %r");
-
- strncpy(p->addr, addr, sizeof p->addr);
- memcpy(p->u, u, sizeof p->u);
- p->dfd = fd;
- if(h != nil)
- memcpy(&p->h, h, sizeof p->h);
- p->src = src;
- p->p = l->p;
- l->p = p;
- return p;
-}
-
-static Conlist *
-cnfind(char *raddr)
-{
- Conlist *p = cnroot->p;
-
- while(p != cnroot){
- if(!strncmp(p->addr, raddr, strlen(p->addr)))
- return p;
- p = p->p;
- }
- return nil;
-}
-
-static void
-cndel(Conlist *p)
-{
- Conlist *l = cnroot;
-
- while(l->p != p){
- l = l->p;
- if(l == cnroot)
- sysfatal("cndel: bad unlink: cnroot 0x%p node 0x%p\n", cnroot, p);
- }
- l->p = p->p;
- if(p->dfd != ufd && p->dfd != cldfd && p->dfd != -1)
- close(p->dfd);
- free(p);
-}
-
-static void
-cnnuke(void)
-{
- Conlist *p, *l = cnroot;
-
- if(cnroot == nil)
- return;
- do{
- p = l;
- l = l->p;
- if(p->dfd != -1)
- close(p->dfd);
- free(p);
- }while(l != cnroot);
- cnroot = nil;
-}
-
-static void
-dproc(void *me)
-{
- int n, fd;
- Conmsg m;
- Conlist *p;
- Channel *c;
-
- threadsetgrp(THnet);
-
- m.p = p = me;
- c = p->src == NS_CLIENT ? clchan : udpchan;
- fd = p->dfd;
-
- for(;;){
- if((n = read(fd, m.buf, sizeof m.buf)) <= 0)
- break;
- m.n = n;
- if(send(c, &m) < 0)
- sysfatal("uproc:send: %r");
- if(nbsend(fuckchan, nil) < 0)
- sysfatal("uproc:nbsend; %r");
- }
- fprint(2, "dproc %d: %r\n", threadpid(threadid()));
- cndel(me);
-}
-
-static void
-uproc(void *c)
-{
- int n, fd;
- uchar udpbuf[Bufsz+Hdrsz], u[IPaddrlen+2];
- char a[IPaddrlen*2+8+6];
- Udphdr h;
- Conmsg m;
- Conlist *p;
-
- threadsetgrp(THnet);
-
- fd = ufd;
- if(c == clchan)
- fd = cldfd;
- for(;;){
- if((n = read(fd, udpbuf, sizeof udpbuf)) <= 0)
- sysfatal("uproc:read: %r");
- memcpy(&h, udpbuf, Hdrsz);
-
- memcpy(u, h.raddr, IPaddrlen);
- memcpy(u+IPaddrlen, h.rport, 2);
- snprint(a, sizeof a, "%ud.%ud.%ud.%ud:%hud", u[12], u[13], u[14], u[15], u[16]<<8 | u[17]);
- qlock(&cnlock);
- if((p = cnfind(a)) == nil)
- p = cnins(fd, a, u, &h, 0);
- qunlock(&cnlock);
- m.p = p;
-
- if(n - Hdrsz < 0){ /* FIXME */
- m.n = n;
- memcpy(m.buf, udpbuf, m.n);
- }else{
- m.n = n - Hdrsz;
- memcpy(m.buf, udpbuf+Hdrsz, m.n);
- }
- if(send(c, &m) < 0)
- sysfatal("uproc:send: %r");
- if(nbsend(fuckchan, nil) < 0)
- sysfatal("uproc:nbsend: %r");
- }
-}
-
-qboolean
-NET_GetPacket(netsrc_t src, netadr_t *from, sizebuf_t *d)
-{
- int n;
- Conmsg m;
-
- if(looprecv(src, from, d))
- return true;
- if(cfd == -1)
- return false;
-
- if((n = nbrecv(src == NS_SERVER ? udpchan : clchan, &m)) < 0)
- sysfatal("NET_GetPacket:nbrecv: %r");
- if(n == 0)
- return false;
-
- memcpy(from->ip, m.p->u+12, 4);
- from->port = m.p->u[17] << 8 | m.p->u[16];
- if(m.n == d->maxsize){
- Com_Printf("Oversize packet from %s\n", NET_AdrToString(*from));
- return false;
- }
- from->type = NA_IP;
- d->cursize = m.n;
- memcpy(d->data, m.buf, m.n);
- return true;
-}
-
-void
-NET_SendPacket(netsrc_t src, int length, void *data, netadr_t to)
-{
- int fd;
- char *addr, *s, *lport;
- uchar b[Bufsz+Hdrsz], u[IPaddrlen+2];
- Conlist *p;
-
- switch(to.type){
- case NA_LOOPBACK:
- loopsend(src, length, data, to);
- break;
- case NA_BROADCAST_IPX:
- case NA_IPX:
- break;
- case NA_BROADCAST:
- memset(to.ip, 0xff, 4);
- addr = NET_AdrToString(to); /* port is PORT_SERVER */
- s = strrchr(addr, ':');
- *s++ = '\0';
- if((fd = dial(netmkaddr(addr, "udp", s), clsrv, nil, nil)) < 0)
- sysfatal("NET_SendPacket:dial bcast: %r");
- if(write(fd, data, length) != length)
- sysfatal("NET_SendPacket:write bcast: %r");
- close(fd);
- break;
- case NA_IP:
- if(cfd == -1)
- break;
-
- addr = NET_AdrToString(to);
- qlock(&cnlock);
- p = cnfind(addr);
- qunlock(&cnlock);
- if(p != nil){
- fd = p->dfd;
- if(fd == ufd || fd == cldfd){
- memcpy(b, &p->h, Hdrsz);
- memcpy(b+Hdrsz, data, length);
- write(fd, b, length+Hdrsz);
- break;
- }
- }else{
- lport = strrchr(addr, ':');
- *lport++ = '\0';
- s = netmkaddr(addr, "udp", lport);
- if((fd = dial(s, srv, nil, nil)) < 0)
- sysfatal("NET_SendPacket:dial: %r");
-
- memcpy(u, v4prefix, sizeof v4prefix);
- memcpy(u+IPv4off, to.ip, IPv4addrlen);
- u[16] = to.port;
- u[17] = to.port >> 8;
- *(lport-1) = ':';
- qlock(&cnlock);
- p = cnins(fd, addr, u, nil, src);
- qunlock(&cnlock);
-
- if(proccreate(dproc, p, 8196) < 0)
- sysfatal("NET_SendPacket:proccreate: %r");
- }
- if(write(fd, data, length) != length)
- sysfatal("NET_SendPacket:write: %r");
- break;
- default:
- Com_Error(ERR_FATAL, "NET_SendPacket: bad address type");
- }
-}
-
-void
-NET_Sleep(int ms) /* sleep for ms, or wakeup for stdio or incoming packets */
-{
- if(cfd == -1 || dedicated != nil && !dedicated->value)
- return; // we're not a server, just run full speed
-
- if(send(tchan, &ms) < 0)
- sysfatal("NET_Sleep:send: %r");
- if(recv(fuckchan, nil) < 0)
- sysfatal("NET_Sleep:recv: %r");
- ms = -1;
- if(nbsend(tchan, &ms) < 0) /* stop timer */
- sysfatal("NET_Sleep:nbsend: %r");
-}
-
-static int
-openname(char *port, int *dfd, Channel **c)
-{
- int fd;
- char data[64], adir[40];
-
- if((fd = announce(netmkaddr("*", "udp", port), adir)) < 0)
- sysfatal("openname:announce udp!*!%s: %r", port);
- if(fprint(fd, "headers") < 0)
- sysfatal("openname: failed to set header mode: %r");
- snprint(data, sizeof data, "%s/data", adir);
- if((*dfd = open(data, ORDWR)) < 0)
- sysfatal("openname:open %r");
- if((*c = chancreate(sizeof(Conmsg), Nbuf)) == nil)
- sysfatal("openname:chancreate: %r");
- if(proccreate(uproc, *c, 8192) < 0)
- sysfatal("openname:proccreate: %r");
- return fd;
-}
-
-static void
-openudp(void)
-{
- if(cfd != -1)
- return;
-
- /* svport value can be changed at any time */
- if(svport->value == PORT_ANY || svport->value > 32767)
- /* FIXME */
- strncpy(srv, "*", sizeof(srv)-1);
- else
- strncpy(srv, svport->string, sizeof(srv)-1);
- cfd = openname(srv, &ufd, &udpchan);
-
- /* broadcast kluge */
- if(clport->value == PORT_ANY || clport->value > 32767)
- strncpy(clsrv, "*", sizeof(clsrv)-1);
- else
- strncpy(clsrv, clport->string, sizeof(clsrv)-1);
- clfd = openname(clsrv, &cldfd, &clchan);
-}
-
-/* a single player game will only use the loopback code */
-void
-NET_Config(qboolean multiplayer)
-{
- if(!multiplayer){ /* shut down existing udp connections */
- threadkillgrp(THnet);
- cnnuke();
- if(udpchan != nil){
- chanfree(udpchan);
- udpchan = nil;
- }
- if(clchan != nil){
- chanfree(clchan);
- clchan = nil;
- }
- if(cfd != -1){
- close(cfd);
- cfd = -1;
- }
- if(clfd != -1){
- close(clfd);
- clfd = -1;
- }
- if(ufd != -1){
- close(ufd);
- ufd = -1;
- }
- if(cldfd != -1){
- close(cldfd);
- cldfd = -1;
- }
- }else{ /* announce open line and get cfd for it */
- cninit();
- openudp();
- }
-}
-
-void
-NET_Shutdown(void)
-{
- NET_Config(false);
-}
-
-void
-NET_Init(void)
-{
- svport = Cvar_Get("port", va("%hu", PORT_SERVER), CVAR_NOSET);
- clport = Cvar_Get("clport", va("%hu", CLPORT), CVAR_NOSET);
-}
--- a/plan9/vid.c
+++ /dev/null
@@ -1,249 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <stdio.h>
-#include <ctype.h>
-#include "../q_shared.h"
-
-refexport_t re; /* exported functions from refresh DLL */
-int resized;
-Point center;
-
-typedef ulong PIXEL;
-
-static int rwon;
-static uchar *framebuf;
-static Image *fbim;
-static PIXEL st2d_8to24table[256];
-static int shiftmask_fl;
-static int r_shift, g_shift, b_shift;
-static uint r_mask, g_mask, b_mask;
-
-refexport_t GetRefAPI(refimport_t);
-
-
-static void
-shiftmask_init(void)
-{
- uint x;
-
- r_mask = 0xff0000;
- g_mask = 0xff00;
- b_mask = 0xff;
- for(r_shift = -8, x = 1; x < r_mask; x <<= 1)
- r_shift++;
- for(g_shift = -8, x = 1; x < g_mask; x <<= 1)
- g_shift++;
- for(b_shift = -8, x = 1; x < b_mask; x <<= 1)
- b_shift++;
- shiftmask_fl = 1;
-}
-
-static PIXEL
-rgb24(int r, int g, int b)
-{
- PIXEL p = 0;
-
- if(shiftmask_fl == 0)
- shiftmask_init();
-
- if(r_shift > 0)
- p = r<<r_shift & r_mask;
- else if(r_shift < 0)
- p = r>>-r_shift & r_mask;
- else
- p |= r & r_mask;
- if(g_shift > 0)
- p |= g<<g_shift & g_mask;
- else if(g_shift < 0)
- p |= g>>-g_shift & g_mask;
- else
- p |= g & g_mask;
- if(b_shift > 0)
- p |= b<<b_shift & b_mask;
- else if(b_shift < 0)
- p |= b>>-b_shift & b_mask;
- else
- p |= b & b_mask;
- return p;
-}
-
-static void
-st3_fixup(void)
-{
- int x, y;
- uchar *src;
- PIXEL *dest;
-
- for(y = 0; y < vid.height; y++){
- src = &framebuf[y*vid.rowbytes];
- dest = (PIXEL*)src;
-
- /* vid.width % 8 not always 0
- for(x = vid.width-1; x >= 0; x -= 8) {
- dest[x ] = st2d_8to24table[src[x ]];
- dest[x-1] = st2d_8to24table[src[x-1]];
- dest[x-2] = st2d_8to24table[src[x-2]];
- dest[x-3] = st2d_8to24table[src[x-3]];
- dest[x-4] = st2d_8to24table[src[x-4]];
- dest[x-5] = st2d_8to24table[src[x-5]];
- dest[x-6] = st2d_8to24table[src[x-6]];
- dest[x-7] = st2d_8to24table[src[x-7]];
- }
- */
-
- for(x = vid.width-1; x >= 0; x--)
- dest[x] = st2d_8to24table[src[x]];
- }
-}
-
-static void
-resetfb(void)
-{
- vid.width = Dx(screen->r);
- vid.height = Dy(screen->r);
- if(framebuf != nil){
- free(framebuf);
- framebuf = nil;
- }
- if(fbim != nil){
- freeimage(fbim);
- fbim = nil;
- }
- if((framebuf = malloc(sizeof *framebuf * vid.width * vid.height * screen->depth/8)) == nil)
- sysfatal("resetfb:malloc: %r");
- if((fbim = allocimage(display, Rect(0, 0, vid.width, vid.height), screen->chan, 1, DNofill)) == nil)
- sysfatal("resetfb: %r");
- vid.buffer = framebuf;
- vid.rowbytes = vid.width * screen->depth/8;
- center = addpt(screen->r.min, Pt(vid.width/2, vid.height/2));
- sw_mode->modified = true; /* make ref_soft refresh its shit */
-}
-
-int
-SWimp_Init(void *, void *)
-{
- srand(getpid());
-
- if(initdraw(nil, nil, "quake2") < 0)
- sysfatal("VID_Init:initdraw: %r\n");
- resetfb();
- rwon = 1;
- return 1;
-}
-
-/* copy backbuffer to front buffer */
-void
-SWimp_EndFrame(void)
-{
- if(resized){ /* skip frame if window resizes */
- resized = 0;
- if(getwindow(display, Refnone) < 0)
- sysfatal("SWimp_EndFrame:getwindow: %r\n");
- resetfb();
- return;
- }
- st3_fixup();
- loadimage(fbim, fbim->r, framebuf, vid.height * vid.rowbytes);
- draw(screen, screen->r, fbim, nil, ZP);
- flushimage(display, 1);
-}
-
-rserr_t
-SWimp_SetMode(int */*pwidth*/, int */*pheight*/, int /*mode*/, qboolean /*fullscreen*/)
-{
- return rserr_ok;
-}
-
-/* nil palette == use existing; palette is expected to be in padded 4-byte xRGB format */
-void
-SWimp_SetPalette(uchar *palette)
-{
- int i;
-
- if(!rwon)
- return;
- if(!palette)
- palette = (uchar *)sw_state.currentpalette;
- for(i = 0; i < 256; i++)
- st2d_8to24table[i] = rgb24(palette[i*4], palette[i*4+1], palette[i*4+2]);
-}
-
-void
-SWimp_Shutdown(void)
-{
- if(!rwon)
- return;
- if(framebuf != nil)
- free(framebuf);
- if(fbim != nil)
- freeimage(fbim);
- rwon = 0;
-}
-
-void
-SWimp_AppActivate(qboolean /*active*/)
-{
-}
-
-void
-VID_Printf(int print_level, char *fmt, ...)
-{
- va_list argptr;
- char msg[4096];
-
- va_start(argptr, fmt);
- vsprintf(msg, fmt, argptr);
- va_end(argptr);
- if(print_level == PRINT_ALL)
- Com_Printf("%s", msg);
- else
- Com_DPrintf("%s", msg);
-}
-
-void
-VID_Error(int err_level, char *fmt, ...)
-{
- va_list argptr;
- char msg[4096];
-
- va_start(argptr, fmt);
- vsprintf(msg, fmt, argptr);
- va_end(argptr);
- Com_Error(err_level, "%s", msg);
-}
-
-void
-VID_CheckChanges(void)
-{
-}
-
-void
-VID_Shutdown(void)
-{
- R_Shutdown();
-}
-
-void
-VID_Init(void)
-{
- refimport_t ri;
-
- ri.Cmd_AddCommand = Cmd_AddCommand;
- ri.Cmd_RemoveCommand = Cmd_RemoveCommand;
- ri.Cmd_Argc = Cmd_Argc;
- ri.Cmd_Argv = Cmd_Argv;
- ri.Cmd_ExecuteText = Cbuf_ExecuteText;
- ri.Con_Printf = VID_Printf;
- ri.Sys_Error = VID_Error;
- ri.FS_LoadFile = FS_LoadFile;
- ri.FS_FreeFile = FS_FreeFile;
- ri.FS_Gamedir = FS_Gamedir;
- ri.Cvar_Get = Cvar_Get;
- ri.Cvar_Set = Cvar_Set;
- ri.Cvar_SetValue = Cvar_SetValue;
- ri.Vid_MenuInit = VID_MenuInit;
-
- re = GetRefAPI(ri);
- re.Init(nil, nil);
-}
--- /dev/null
+++ b/pmove.c
@@ -1,0 +1,1338 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+
+#define STEPSIZE 18
+
+// all of the locals will be zeroed before each
+// pmove, just to make damn sure we don't have
+// any differences when running on client or server
+
+typedef struct
+{
+ vec3_t origin; // full float precision
+ vec3_t velocity; // full float precision
+
+ vec3_t forward, right, up;
+ float frametime;
+
+
+ csurface_t *groundsurface;
+ cplane_t groundplane;
+ int groundcontents;
+
+ vec3_t previous_origin;
+ qboolean ladder;
+} pml_t;
+
+pmove_t *pm;
+pml_t pml;
+
+
+// movement parameters
+float pm_stopspeed = 100;
+float pm_maxspeed = 300;
+float pm_duckspeed = 100;
+float pm_accelerate = 10;
+float pm_airaccelerate = 0;
+float pm_wateraccelerate = 10;
+float pm_friction = 6;
+float pm_waterfriction = 1;
+float pm_waterspeed = 400;
+
+/*
+
+ walking up a step should kill some velocity
+
+*/
+
+
+/*
+==================
+PM_ClipVelocity
+
+Slide off of the impacting object
+returns the blocked flags (1 = floor, 2 = step / wall)
+==================
+*/
+#define STOP_EPSILON 0.1
+
+void PM_ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
+{
+ float backoff;
+ float change;
+ int i;
+
+ backoff = DotProduct (in, normal) * overbounce;
+
+ for (i=0 ; i<3 ; i++)
+ {
+ change = normal[i]*backoff;
+ out[i] = in[i] - change;
+ if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
+ out[i] = 0;
+ }
+}
+
+
+
+
+/*
+==================
+PM_StepSlideMove
+
+Each intersection will try to step over the obstruction instead of
+sliding along it.
+
+Returns a new origin, velocity, and contact entity
+Does not modify any world state?
+==================
+*/
+#define MIN_STEP_NORMAL 0.7 // can't step up onto very steep slopes
+#define MAX_CLIP_PLANES 5
+void PM_StepSlideMove_ (void)
+{
+ int bumpcount, numbumps;
+ vec3_t dir;
+ float d;
+ int numplanes;
+ vec3_t planes[MAX_CLIP_PLANES];
+ vec3_t primal_velocity;
+ int i, j;
+ trace_t trace;
+ vec3_t end;
+ float time_left;
+
+ numbumps = 4;
+
+ VectorCopy (pml.velocity, primal_velocity);
+ numplanes = 0;
+
+ time_left = pml.frametime;
+
+ for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
+ {
+ for (i=0 ; i<3 ; i++)
+ end[i] = pml.origin[i] + time_left * pml.velocity[i];
+
+ trace = pm->trace (pml.origin, pm->mins, pm->maxs, end);
+
+ if (trace.allsolid)
+ { // entity is trapped in another solid
+ pml.velocity[2] = 0; // don't build up falling damage
+ return;
+ }
+
+ if (trace.fraction > 0)
+ { // actually covered some distance
+ VectorCopy (trace.endpos, pml.origin);
+ numplanes = 0;
+ }
+
+ if (trace.fraction == 1)
+ break; // moved the entire distance
+
+ // save entity for contact
+ if (pm->numtouch < MAXTOUCH && trace.ent)
+ {
+ pm->touchents[pm->numtouch] = trace.ent;
+ pm->numtouch++;
+ }
+
+ time_left -= time_left * trace.fraction;
+
+ // slide along this plane
+ if (numplanes >= MAX_CLIP_PLANES)
+ { // this shouldn't really happen
+ VectorCopy (vec3_origin, pml.velocity);
+ break;
+ }
+
+ VectorCopy (trace.plane.normal, planes[numplanes]);
+ numplanes++;
+
+/* commented out in release
+ float rub;
+
+ //
+ // modify velocity so it parallels all of the clip planes
+ //
+ if (numplanes == 1)
+ { // go along this plane
+ VectorCopy (pml.velocity, dir);
+ VectorNormalize (dir);
+ rub = 1.0 + 0.5 * DotProduct (dir, planes[0]);
+
+ // slide along the plane
+ PM_ClipVelocity (pml.velocity, planes[0], pml.velocity, 1.01);
+ // rub some extra speed off on xy axis
+ // not on Z, or you can scrub down walls
+ pml.velocity[0] *= rub;
+ pml.velocity[1] *= rub;
+ pml.velocity[2] *= rub;
+ }
+ else if (numplanes == 2)
+ { // go along the crease
+ VectorCopy (pml.velocity, dir);
+ VectorNormalize (dir);
+ rub = 1.0 + 0.5 * DotProduct (dir, planes[0]);
+
+ // slide along the plane
+ CrossProduct (planes[0], planes[1], dir);
+ d = DotProduct (dir, pml.velocity);
+ VectorScale (dir, d, pml.velocity);
+
+ // rub some extra speed off
+ VectorScale (pml.velocity, rub, pml.velocity);
+ }
+ else
+ {
+// Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
+ VectorCopy (vec3_origin, pml.velocity);
+ break;
+ }
+
+*/
+//
+// modify original_velocity so it parallels all of the clip planes
+//
+ for (i=0 ; i<numplanes ; i++)
+ {
+ PM_ClipVelocity (pml.velocity, planes[i], pml.velocity, 1.01);
+ for (j=0 ; j<numplanes ; j++)
+ if (j != i)
+ {
+ if (DotProduct (pml.velocity, planes[j]) < 0)
+ break; // not ok
+ }
+ if (j == numplanes)
+ break;
+ }
+
+ if (i != numplanes)
+ { // go along this plane
+ }
+ else
+ { // go along the crease
+ if (numplanes != 2)
+ {
+// Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
+ VectorCopy (vec3_origin, pml.velocity);
+ break;
+ }
+ CrossProduct (planes[0], planes[1], dir);
+ d = DotProduct (dir, pml.velocity);
+ VectorScale (dir, d, pml.velocity);
+ }
+ //
+ // if velocity is against the original velocity, stop dead
+ // to avoid tiny occilations in sloping corners
+ //
+ if (DotProduct (pml.velocity, primal_velocity) <= 0)
+ {
+ VectorCopy (vec3_origin, pml.velocity);
+ break;
+ }
+ }
+
+ if (pm->s.pm_time)
+ {
+ VectorCopy (primal_velocity, pml.velocity);
+ }
+}
+
+/*
+==================
+PM_StepSlideMove
+
+==================
+*/
+void PM_StepSlideMove (void)
+{
+ vec3_t start_o, start_v;
+ vec3_t down_o, down_v;
+ trace_t trace;
+ float down_dist, up_dist;
+// vec3_t delta;
+ vec3_t up, down;
+
+ VectorCopy (pml.origin, start_o);
+ VectorCopy (pml.velocity, start_v);
+
+ PM_StepSlideMove_ ();
+
+ VectorCopy (pml.origin, down_o);
+ VectorCopy (pml.velocity, down_v);
+
+ VectorCopy (start_o, up);
+ up[2] += STEPSIZE;
+
+ trace = pm->trace (up, pm->mins, pm->maxs, up);
+ if (trace.allsolid)
+ return; // can't step up
+
+ // try sliding above
+ VectorCopy (up, pml.origin);
+ VectorCopy (start_v, pml.velocity);
+
+ PM_StepSlideMove_ ();
+
+ // push down the final amount
+ VectorCopy (pml.origin, down);
+ down[2] -= STEPSIZE;
+ trace = pm->trace (pml.origin, pm->mins, pm->maxs, down);
+ if (!trace.allsolid)
+ {
+ VectorCopy (trace.endpos, pml.origin);
+ }
+
+/*
+ VectorSubtract (pml.origin, up, delta);
+ up_dist = DotProduct (delta, start_v);
+
+ VectorSubtract (down_o, start_o, delta);
+ down_dist = DotProduct (delta, start_v);
+*/
+ VectorCopy(pml.origin, up);
+
+ // decide which one went farther
+ down_dist = (down_o[0] - start_o[0])*(down_o[0] - start_o[0])
+ + (down_o[1] - start_o[1])*(down_o[1] - start_o[1]);
+ up_dist = (up[0] - start_o[0])*(up[0] - start_o[0])
+ + (up[1] - start_o[1])*(up[1] - start_o[1]);
+
+ if (down_dist > up_dist || trace.plane.normal[2] < MIN_STEP_NORMAL)
+ {
+ VectorCopy (down_o, pml.origin);
+ VectorCopy (down_v, pml.velocity);
+ return;
+ }
+ //!! Special case
+ // if we were walking along a plane, then we need to copy the Z over
+ pml.velocity[2] = down_v[2];
+}
+
+
+/*
+==================
+PM_Friction
+
+Handles both ground friction and water friction
+==================
+*/
+void PM_Friction (void)
+{
+ float *vel;
+ float speed, newspeed, control;
+ float friction;
+ float drop;
+
+ vel = pml.velocity;
+
+ speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1] + vel[2]*vel[2]);
+ if (speed < 1)
+ {
+ vel[0] = 0;
+ vel[1] = 0;
+ return;
+ }
+
+ drop = 0;
+
+// apply ground friction
+ if ((pm->groundentity && pml.groundsurface && !(pml.groundsurface->flags & SURF_SLICK) ) || (pml.ladder) )
+ {
+ friction = pm_friction;
+ control = speed < pm_stopspeed ? pm_stopspeed : speed;
+ drop += control*friction*pml.frametime;
+ }
+
+// apply water friction
+ if (pm->waterlevel && !pml.ladder)
+ drop += speed*pm_waterfriction*pm->waterlevel*pml.frametime;
+
+// scale the velocity
+ newspeed = speed - drop;
+ if (newspeed < 0)
+ {
+ newspeed = 0;
+ }
+ newspeed /= speed;
+
+ vel[0] = vel[0] * newspeed;
+ vel[1] = vel[1] * newspeed;
+ vel[2] = vel[2] * newspeed;
+}
+
+
+/*
+==============
+PM_Accelerate
+
+Handles user intended acceleration
+==============
+*/
+void PM_Accelerate (vec3_t wishdir, float wishspeed, float accel)
+{
+ int i;
+ float addspeed, accelspeed, currentspeed;
+
+ currentspeed = DotProduct (pml.velocity, wishdir);
+ addspeed = wishspeed - currentspeed;
+ if (addspeed <= 0)
+ return;
+ accelspeed = accel*pml.frametime*wishspeed;
+ if (accelspeed > addspeed)
+ accelspeed = addspeed;
+
+ for (i=0 ; i<3 ; i++)
+ pml.velocity[i] += accelspeed*wishdir[i];
+}
+
+void PM_AirAccelerate (vec3_t wishdir, float wishspeed, float accel)
+{
+ int i;
+ float addspeed, accelspeed, currentspeed, wishspd = wishspeed;
+
+ if (wishspd > 30)
+ wishspd = 30;
+ currentspeed = DotProduct (pml.velocity, wishdir);
+ addspeed = wishspd - currentspeed;
+ if (addspeed <= 0)
+ return;
+ accelspeed = accel * wishspeed * pml.frametime;
+ if (accelspeed > addspeed)
+ accelspeed = addspeed;
+
+ for (i=0 ; i<3 ; i++)
+ pml.velocity[i] += accelspeed*wishdir[i];
+}
+
+/*
+=============
+PM_AddCurrents
+=============
+*/
+void PM_AddCurrents (vec3_t wishvel)
+{
+ vec3_t v;
+ float s;
+
+ //
+ // account for ladders
+ //
+
+ if (pml.ladder && fabs(pml.velocity[2]) <= 200)
+ {
+ if ((pm->viewangles[PITCH] <= -15) && (pm->cmd.forwardmove > 0))
+ wishvel[2] = 200;
+ else if ((pm->viewangles[PITCH] >= 15) && (pm->cmd.forwardmove > 0))
+ wishvel[2] = -200;
+ else if (pm->cmd.upmove > 0)
+ wishvel[2] = 200;
+ else if (pm->cmd.upmove < 0)
+ wishvel[2] = -200;
+ else
+ wishvel[2] = 0;
+
+ // limit horizontal speed when on a ladder
+ if (wishvel[0] < -25)
+ wishvel[0] = -25;
+ else if (wishvel[0] > 25)
+ wishvel[0] = 25;
+
+ if (wishvel[1] < -25)
+ wishvel[1] = -25;
+ else if (wishvel[1] > 25)
+ wishvel[1] = 25;
+ }
+
+
+ //
+ // add water currents
+ //
+
+ if (pm->watertype & MASK_CURRENT)
+ {
+ VectorClear (v);
+
+ if (pm->watertype & CONTENTS_CURRENT_0)
+ v[0] += 1;
+ if (pm->watertype & CONTENTS_CURRENT_90)
+ v[1] += 1;
+ if (pm->watertype & CONTENTS_CURRENT_180)
+ v[0] -= 1;
+ if (pm->watertype & CONTENTS_CURRENT_270)
+ v[1] -= 1;
+ if (pm->watertype & CONTENTS_CURRENT_UP)
+ v[2] += 1;
+ if (pm->watertype & CONTENTS_CURRENT_DOWN)
+ v[2] -= 1;
+
+ s = pm_waterspeed;
+ if ((pm->waterlevel == 1) && (pm->groundentity))
+ s /= 2;
+
+ VectorMA (wishvel, s, v, wishvel);
+ }
+
+ //
+ // add conveyor belt velocities
+ //
+
+ if (pm->groundentity)
+ {
+ VectorClear (v);
+
+ if (pml.groundcontents & CONTENTS_CURRENT_0)
+ v[0] += 1;
+ if (pml.groundcontents & CONTENTS_CURRENT_90)
+ v[1] += 1;
+ if (pml.groundcontents & CONTENTS_CURRENT_180)
+ v[0] -= 1;
+ if (pml.groundcontents & CONTENTS_CURRENT_270)
+ v[1] -= 1;
+ if (pml.groundcontents & CONTENTS_CURRENT_UP)
+ v[2] += 1;
+ if (pml.groundcontents & CONTENTS_CURRENT_DOWN)
+ v[2] -= 1;
+
+ VectorMA (wishvel, 100 /* pm->groundentity->speed */, v, wishvel);
+ }
+}
+
+
+/*
+===================
+PM_WaterMove
+
+===================
+*/
+void PM_WaterMove (void)
+{
+ int i;
+ vec3_t wishvel;
+ float wishspeed;
+ vec3_t wishdir;
+
+//
+// user intentions
+//
+ for (i=0 ; i<3 ; i++)
+ wishvel[i] = pml.forward[i]*pm->cmd.forwardmove + pml.right[i]*pm->cmd.sidemove;
+
+ if (!pm->cmd.forwardmove && !pm->cmd.sidemove && !pm->cmd.upmove)
+ wishvel[2] -= 60; // drift towards bottom
+ else
+ wishvel[2] += pm->cmd.upmove;
+
+ PM_AddCurrents (wishvel);
+
+ VectorCopy (wishvel, wishdir);
+ wishspeed = VectorNormalize(wishdir);
+
+ if (wishspeed > pm_maxspeed)
+ {
+ VectorScale (wishvel, pm_maxspeed/wishspeed, wishvel);
+ wishspeed = pm_maxspeed;
+ }
+ wishspeed *= 0.5;
+
+ PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate);
+
+ PM_StepSlideMove ();
+}
+
+
+/*
+===================
+PM_AirMove
+
+===================
+*/
+void PM_AirMove (void)
+{
+ int i;
+ vec3_t wishvel;
+ float fmove, smove;
+ vec3_t wishdir;
+ float wishspeed;
+ float maxspeed;
+
+ fmove = pm->cmd.forwardmove;
+ smove = pm->cmd.sidemove;
+
+//!!!!! pitch should be 1/3 so this isn't needed??!
+/*
+ pml.forward[2] = 0;
+ pml.right[2] = 0;
+ VectorNormalize (pml.forward);
+ VectorNormalize (pml.right);
+*/
+
+ for (i=0 ; i<2 ; i++)
+ wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
+ wishvel[2] = 0;
+
+ PM_AddCurrents (wishvel);
+
+ VectorCopy (wishvel, wishdir);
+ wishspeed = VectorNormalize(wishdir);
+
+//
+// clamp to server defined max speed
+//
+ maxspeed = (pm->s.pm_flags & PMF_DUCKED) ? pm_duckspeed : pm_maxspeed;
+
+ if (wishspeed > maxspeed)
+ {
+ VectorScale (wishvel, maxspeed/wishspeed, wishvel);
+ wishspeed = maxspeed;
+ }
+
+ if ( pml.ladder )
+ {
+ PM_Accelerate (wishdir, wishspeed, pm_accelerate);
+ if (!wishvel[2])
+ {
+ if (pml.velocity[2] > 0)
+ {
+ pml.velocity[2] -= pm->s.gravity * pml.frametime;
+ if (pml.velocity[2] < 0)
+ pml.velocity[2] = 0;
+ }
+ else
+ {
+ pml.velocity[2] += pm->s.gravity * pml.frametime;
+ if (pml.velocity[2] > 0)
+ pml.velocity[2] = 0;
+ }
+ }
+ PM_StepSlideMove ();
+ }
+ else if ( pm->groundentity )
+ { // walking on ground
+ pml.velocity[2] = 0; //!!! this is before the accel
+ PM_Accelerate (wishdir, wishspeed, pm_accelerate);
+
+// PGM -- fix for negative trigger_gravity fields
+// pml.velocity[2] = 0;
+ if(pm->s.gravity > 0)
+ pml.velocity[2] = 0;
+ else
+ pml.velocity[2] -= pm->s.gravity * pml.frametime;
+// PGM
+
+ if (!pml.velocity[0] && !pml.velocity[1])
+ return;
+ PM_StepSlideMove ();
+ }
+ else
+ { // not on ground, so little effect on velocity
+ if (pm_airaccelerate)
+ PM_AirAccelerate (wishdir, wishspeed, pm_accelerate);
+ else
+ PM_Accelerate (wishdir, wishspeed, 1);
+ // add gravity
+ pml.velocity[2] -= pm->s.gravity * pml.frametime;
+ PM_StepSlideMove ();
+ }
+}
+
+
+
+/*
+=============
+PM_CatagorizePosition
+=============
+*/
+void PM_CatagorizePosition (void)
+{
+ vec3_t point;
+ int cont;
+ trace_t trace;
+ int sample1;
+ int sample2;
+
+// if the player hull point one unit down is solid, the player
+// is on ground
+
+// see if standing on something solid
+ point[0] = pml.origin[0];
+ point[1] = pml.origin[1];
+ point[2] = pml.origin[2] - 0.25;
+ if (pml.velocity[2] > 180) //!!ZOID changed from 100 to 180 (ramp accel)
+ {
+ pm->s.pm_flags &= ~PMF_ON_GROUND;
+ pm->groundentity = NULL;
+ }
+ else
+ {
+ trace = pm->trace (pml.origin, pm->mins, pm->maxs, point);
+ pml.groundplane = trace.plane;
+ pml.groundsurface = trace.surface;
+ pml.groundcontents = trace.contents;
+
+ if (!trace.ent || (trace.plane.normal[2] < 0.7 && !trace.startsolid) )
+ {
+ pm->groundentity = NULL;
+ pm->s.pm_flags &= ~PMF_ON_GROUND;
+ }
+ else
+ {
+ pm->groundentity = trace.ent;
+
+ // hitting solid ground will end a waterjump
+ if (pm->s.pm_flags & PMF_TIME_WATERJUMP)
+ {
+ pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
+ pm->s.pm_time = 0;
+ }
+
+ if (! (pm->s.pm_flags & PMF_ON_GROUND) )
+ { // just hit the ground
+ pm->s.pm_flags |= PMF_ON_GROUND;
+ // don't do landing time if we were just going down a slope
+ if (pml.velocity[2] < -200)
+ {
+ pm->s.pm_flags |= PMF_TIME_LAND;
+ // don't allow another jump for a little while
+ if (pml.velocity[2] < -400)
+ pm->s.pm_time = 25;
+ else
+ pm->s.pm_time = 18;
+ }
+ }
+ }
+
+/*
+ if (trace.fraction < 1.0 && trace.ent && pml.velocity[2] < 0)
+ pml.velocity[2] = 0;
+*/
+
+ if (pm->numtouch < MAXTOUCH && trace.ent)
+ {
+ pm->touchents[pm->numtouch] = trace.ent;
+ pm->numtouch++;
+ }
+ }
+
+//
+// get waterlevel, accounting for ducking
+//
+ pm->waterlevel = 0;
+ pm->watertype = 0;
+
+ sample2 = pm->viewheight - pm->mins[2];
+ sample1 = sample2 / 2;
+
+ point[2] = pml.origin[2] + pm->mins[2] + 1;
+ cont = pm->pointcontents (point);
+
+ if (cont & MASK_WATER)
+ {
+ pm->watertype = cont;
+ pm->waterlevel = 1;
+ point[2] = pml.origin[2] + pm->mins[2] + sample1;
+ cont = pm->pointcontents (point);
+ if (cont & MASK_WATER)
+ {
+ pm->waterlevel = 2;
+ point[2] = pml.origin[2] + pm->mins[2] + sample2;
+ cont = pm->pointcontents (point);
+ if (cont & MASK_WATER)
+ pm->waterlevel = 3;
+ }
+ }
+
+}
+
+
+/*
+=============
+PM_CheckJump
+=============
+*/
+void PM_CheckJump (void)
+{
+ if (pm->s.pm_flags & PMF_TIME_LAND)
+ { // hasn't been long enough since landing to jump again
+ return;
+ }
+
+ if (pm->cmd.upmove < 10)
+ { // not holding jump
+ pm->s.pm_flags &= ~PMF_JUMP_HELD;
+ return;
+ }
+
+ // must wait for jump to be released
+ if (pm->s.pm_flags & PMF_JUMP_HELD)
+ return;
+
+ if (pm->s.pm_type == PM_DEAD)
+ return;
+
+ if (pm->waterlevel >= 2)
+ { // swimming, not jumping
+ pm->groundentity = NULL;
+
+ if (pml.velocity[2] <= -300)
+ return;
+
+ if (pm->watertype == CONTENTS_WATER)
+ pml.velocity[2] = 100;
+ else if (pm->watertype == CONTENTS_SLIME)
+ pml.velocity[2] = 80;
+ else
+ pml.velocity[2] = 50;
+ return;
+ }
+
+ if (pm->groundentity == NULL)
+ return; // in air, so no effect
+
+ pm->s.pm_flags |= PMF_JUMP_HELD;
+
+ pm->groundentity = NULL;
+ pml.velocity[2] += 270;
+ if (pml.velocity[2] < 270)
+ pml.velocity[2] = 270;
+}
+
+
+/*
+=============
+PM_CheckSpecialMovement
+=============
+*/
+void PM_CheckSpecialMovement (void)
+{
+ vec3_t spot;
+ int cont;
+ vec3_t flatforward;
+ trace_t trace;
+
+ if (pm->s.pm_time)
+ return;
+
+ pml.ladder = false;
+
+ // check for ladder
+ flatforward[0] = pml.forward[0];
+ flatforward[1] = pml.forward[1];
+ flatforward[2] = 0;
+ VectorNormalize (flatforward);
+
+ VectorMA (pml.origin, 1, flatforward, spot);
+ trace = pm->trace (pml.origin, pm->mins, pm->maxs, spot);
+ if ((trace.fraction < 1) && (trace.contents & CONTENTS_LADDER))
+ pml.ladder = true;
+
+ // check for water jump
+ if (pm->waterlevel != 2)
+ return;
+
+ VectorMA (pml.origin, 30, flatforward, spot);
+ spot[2] += 4;
+ cont = pm->pointcontents (spot);
+ if (!(cont & CONTENTS_SOLID))
+ return;
+
+ spot[2] += 16;
+ cont = pm->pointcontents (spot);
+ if (cont)
+ return;
+ // jump out of water
+ VectorScale (flatforward, 50, pml.velocity);
+ pml.velocity[2] = 350;
+
+ pm->s.pm_flags |= PMF_TIME_WATERJUMP;
+ pm->s.pm_time = 255;
+}
+
+
+/*
+===============
+PM_FlyMove
+===============
+*/
+void PM_FlyMove (qboolean doclip)
+{
+ float speed, drop, friction, control, newspeed;
+ float currentspeed, addspeed, accelspeed;
+ int i;
+ vec3_t wishvel;
+ float fmove, smove;
+ vec3_t wishdir;
+ float wishspeed;
+ vec3_t end;
+ trace_t trace;
+
+ pm->viewheight = 22;
+
+ // friction
+
+ speed = VectorLength (pml.velocity);
+ if (speed < 1)
+ {
+ VectorCopy (vec3_origin, pml.velocity);
+ }
+ else
+ {
+ drop = 0;
+
+ friction = pm_friction*1.5; // extra friction
+ control = speed < pm_stopspeed ? pm_stopspeed : speed;
+ drop += control*friction*pml.frametime;
+
+ // scale the velocity
+ newspeed = speed - drop;
+ if (newspeed < 0)
+ newspeed = 0;
+ newspeed /= speed;
+
+ VectorScale (pml.velocity, newspeed, pml.velocity);
+ }
+
+ // accelerate
+ fmove = pm->cmd.forwardmove;
+ smove = pm->cmd.sidemove;
+
+ VectorNormalize (pml.forward);
+ VectorNormalize (pml.right);
+
+ for (i=0 ; i<3 ; i++)
+ wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
+ wishvel[2] += pm->cmd.upmove;
+
+ VectorCopy (wishvel, wishdir);
+ wishspeed = VectorNormalize(wishdir);
+
+ //
+ // clamp to server defined max speed
+ //
+ if (wishspeed > pm_maxspeed)
+ {
+ VectorScale (wishvel, pm_maxspeed/wishspeed, wishvel);
+ wishspeed = pm_maxspeed;
+ }
+
+
+ currentspeed = DotProduct(pml.velocity, wishdir);
+ addspeed = wishspeed - currentspeed;
+ if (addspeed <= 0)
+ return;
+ accelspeed = pm_accelerate*pml.frametime*wishspeed;
+ if (accelspeed > addspeed)
+ accelspeed = addspeed;
+
+ for (i=0 ; i<3 ; i++)
+ pml.velocity[i] += accelspeed*wishdir[i];
+
+ if (doclip) {
+ for (i=0 ; i<3 ; i++)
+ end[i] = pml.origin[i] + pml.frametime * pml.velocity[i];
+
+ trace = pm->trace (pml.origin, pm->mins, pm->maxs, end);
+
+ VectorCopy (trace.endpos, pml.origin);
+ } else {
+ // move
+ VectorMA (pml.origin, pml.frametime, pml.velocity, pml.origin);
+ }
+}
+
+
+/*
+==============
+PM_CheckDuck
+
+Sets mins, maxs, and pm->viewheight
+==============
+*/
+void PM_CheckDuck (void)
+{
+ trace_t trace;
+
+ pm->mins[0] = -16;
+ pm->mins[1] = -16;
+
+ pm->maxs[0] = 16;
+ pm->maxs[1] = 16;
+
+ if (pm->s.pm_type == PM_GIB)
+ {
+ pm->mins[2] = 0;
+ pm->maxs[2] = 16;
+ pm->viewheight = 8;
+ return;
+ }
+
+ pm->mins[2] = -24;
+
+ if (pm->s.pm_type == PM_DEAD)
+ {
+ pm->s.pm_flags |= PMF_DUCKED;
+ }
+ else if (pm->cmd.upmove < 0 && (pm->s.pm_flags & PMF_ON_GROUND) )
+ { // duck
+ pm->s.pm_flags |= PMF_DUCKED;
+ }
+ else
+ { // stand up if possible
+ if (pm->s.pm_flags & PMF_DUCKED)
+ {
+ // try to stand up
+ pm->maxs[2] = 32;
+ trace = pm->trace (pml.origin, pm->mins, pm->maxs, pml.origin);
+ if (!trace.allsolid)
+ pm->s.pm_flags &= ~PMF_DUCKED;
+ }
+ }
+
+ if (pm->s.pm_flags & PMF_DUCKED)
+ {
+ pm->maxs[2] = 4;
+ pm->viewheight = -2;
+ }
+ else
+ {
+ pm->maxs[2] = 32;
+ pm->viewheight = 22;
+ }
+}
+
+
+/*
+==============
+PM_DeadMove
+==============
+*/
+void PM_DeadMove (void)
+{
+ float forward;
+
+ if (!pm->groundentity)
+ return;
+
+ // extra friction
+
+ forward = VectorLength (pml.velocity);
+ forward -= 20;
+ if (forward <= 0)
+ {
+ VectorClear (pml.velocity);
+ }
+ else
+ {
+ VectorNormalize (pml.velocity);
+ VectorScale (pml.velocity, forward, pml.velocity);
+ }
+}
+
+
+qboolean PM_GoodPosition (void)
+{
+ trace_t trace;
+ vec3_t origin, end;
+ int i;
+
+ if (pm->s.pm_type == PM_SPECTATOR)
+ return true;
+
+ for (i=0 ; i<3 ; i++)
+ origin[i] = end[i] = pm->s.origin[i]*0.125;
+ trace = pm->trace (origin, pm->mins, pm->maxs, end);
+
+ return !trace.allsolid;
+}
+
+/*
+================
+PM_SnapPosition
+
+On exit, the origin will have a value that is pre-quantized to the 0.125
+precision of the network channel and in a valid position.
+================
+*/
+void PM_SnapPosition (void)
+{
+ int sign[3];
+ int i, j, bits;
+ short base[3];
+ // try all single bits first
+ static int jitterbits[8] = {0,4,1,2,3,5,6,7};
+
+ // snap velocity to eigths
+ for (i=0 ; i<3 ; i++)
+ pm->s.velocity[i] = (int)(pml.velocity[i]*8);
+
+ for (i=0 ; i<3 ; i++)
+ {
+ if (pml.origin[i] >= 0)
+ sign[i] = 1;
+ else
+ sign[i] = -1;
+ pm->s.origin[i] = (int)(pml.origin[i]*8);
+ if (pm->s.origin[i]*0.125 == pml.origin[i])
+ sign[i] = 0;
+ }
+ VectorCopy (pm->s.origin, base);
+
+ // try all combinations
+ for (j=0 ; j<8 ; j++)
+ {
+ bits = jitterbits[j];
+ VectorCopy (base, pm->s.origin);
+ for (i=0 ; i<3 ; i++)
+ if (bits & (1<<i) )
+ pm->s.origin[i] += sign[i];
+
+ if (PM_GoodPosition ())
+ return;
+ }
+
+ // go back to the last position
+ VectorCopy (pml.previous_origin, pm->s.origin);
+// Com_DPrintf ("using previous_origin\n");
+}
+
+/*
+================
+PM_InitialSnapPosition
+
+================
+*/
+/* NO LONGER USED
+void PM_InitialSnapPosition (void)
+{
+ int x, y, z;
+ short base[3];
+
+ VectorCopy (pm->s.origin, base);
+
+ for (z=1 ; z>=-1 ; z--)
+ {
+ pm->s.origin[2] = base[2] + z;
+ for (y=1 ; y>=-1 ; y--)
+ {
+ pm->s.origin[1] = base[1] + y;
+ for (x=1 ; x>=-1 ; x--)
+ {
+ pm->s.origin[0] = base[0] + x;
+ if (PM_GoodPosition ())
+ {
+ pml.origin[0] = pm->s.origin[0]*0.125;
+ pml.origin[1] = pm->s.origin[1]*0.125;
+ pml.origin[2] = pm->s.origin[2]*0.125;
+ VectorCopy (pm->s.origin, pml.previous_origin);
+ return;
+ }
+ }
+ }
+ }
+
+ Com_DPrintf ("Bad InitialSnapPosition\n");
+}
+*/
+/*
+================
+PM_InitialSnapPosition
+
+================
+*/
+void PM_InitialSnapPosition(void)
+{
+ int x, y, z;
+ short base[3];
+ static int offset[3] = { 0, -1, 1 };
+
+ VectorCopy (pm->s.origin, base);
+
+ for ( z = 0; z < 3; z++ ) {
+ pm->s.origin[2] = base[2] + offset[ z ];
+ for ( y = 0; y < 3; y++ ) {
+ pm->s.origin[1] = base[1] + offset[ y ];
+ for ( x = 0; x < 3; x++ ) {
+ pm->s.origin[0] = base[0] + offset[ x ];
+ if (PM_GoodPosition ()) {
+ pml.origin[0] = pm->s.origin[0]*0.125;
+ pml.origin[1] = pm->s.origin[1]*0.125;
+ pml.origin[2] = pm->s.origin[2]*0.125;
+ VectorCopy (pm->s.origin, pml.previous_origin);
+ return;
+ }
+ }
+ }
+ }
+
+ Com_DPrintf ("Bad InitialSnapPosition\n");
+}
+
+/*
+================
+PM_ClampAngles
+
+================
+*/
+void PM_ClampAngles (void)
+{
+ short temp;
+ int i;
+
+ if (pm->s.pm_flags & PMF_TIME_TELEPORT)
+ {
+ pm->viewangles[YAW] = SHORT2ANGLE(pm->cmd.angles[YAW] + pm->s.delta_angles[YAW]);
+ pm->viewangles[PITCH] = 0;
+ pm->viewangles[ROLL] = 0;
+ }
+ else
+ {
+ // circularly clamp the angles with deltas
+ for (i=0 ; i<3 ; i++)
+ {
+ temp = pm->cmd.angles[i] + pm->s.delta_angles[i];
+ pm->viewangles[i] = SHORT2ANGLE(temp);
+ }
+
+ // don't let the player look up or down more than 90 degrees
+ if (pm->viewangles[PITCH] > 89 && pm->viewangles[PITCH] < 180)
+ pm->viewangles[PITCH] = 89;
+ else if (pm->viewangles[PITCH] < 271 && pm->viewangles[PITCH] >= 180)
+ pm->viewangles[PITCH] = 271;
+ }
+ AngleVectors (pm->viewangles, pml.forward, pml.right, pml.up);
+}
+
+/*
+================
+Pmove
+
+Can be called by either the server or the client
+================
+*/
+void Pmove (pmove_t *pmove)
+{
+ pm = pmove;
+
+ // clear results
+ pm->numtouch = 0;
+ VectorClear (pm->viewangles);
+ pm->viewheight = 0;
+ pm->groundentity = 0;
+ pm->watertype = 0;
+ pm->waterlevel = 0;
+
+ // clear all pmove local vars
+ memset (&pml, 0, sizeof(pml));
+
+ // convert origin and velocity to float values
+ pml.origin[0] = pm->s.origin[0]*0.125;
+ pml.origin[1] = pm->s.origin[1]*0.125;
+ pml.origin[2] = pm->s.origin[2]*0.125;
+
+ pml.velocity[0] = pm->s.velocity[0]*0.125;
+ pml.velocity[1] = pm->s.velocity[1]*0.125;
+ pml.velocity[2] = pm->s.velocity[2]*0.125;
+
+ // save old org in case we get stuck
+ VectorCopy (pm->s.origin, pml.previous_origin);
+
+ pml.frametime = pm->cmd.msec * 0.001;
+
+ PM_ClampAngles ();
+
+ if (pm->s.pm_type == PM_SPECTATOR)
+ {
+ PM_FlyMove (false);
+ PM_SnapPosition ();
+ return;
+ }
+
+ if (pm->s.pm_type >= PM_DEAD)
+ {
+ pm->cmd.forwardmove = 0;
+ pm->cmd.sidemove = 0;
+ pm->cmd.upmove = 0;
+ }
+
+ if (pm->s.pm_type == PM_FREEZE)
+ return; // no movement at all
+
+ // set mins, maxs, and viewheight
+ PM_CheckDuck ();
+
+ if (pm->snapinitial)
+ PM_InitialSnapPosition ();
+
+ // set groundentity, watertype, and waterlevel
+ PM_CatagorizePosition ();
+
+ if (pm->s.pm_type == PM_DEAD)
+ PM_DeadMove ();
+
+ PM_CheckSpecialMovement ();
+
+ // drop timing counter
+ if (pm->s.pm_time)
+ {
+ int msec;
+
+ msec = pm->cmd.msec >> 3;
+ if (!msec)
+ msec = 1;
+ if ( msec >= pm->s.pm_time)
+ {
+ pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
+ pm->s.pm_time = 0;
+ }
+ else
+ pm->s.pm_time -= msec;
+ }
+
+ if (pm->s.pm_flags & PMF_TIME_TELEPORT)
+ { // teleport pause stays exactly in place
+ }
+ else if (pm->s.pm_flags & PMF_TIME_WATERJUMP)
+ { // waterjump has no control, but falls
+ pml.velocity[2] -= pm->s.gravity * pml.frametime;
+ if (pml.velocity[2] < 0)
+ { // cancel as soon as we are falling down again
+ pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
+ pm->s.pm_time = 0;
+ }
+
+ PM_StepSlideMove ();
+ }
+ else
+ {
+ PM_CheckJump ();
+
+ PM_Friction ();
+
+ if (pm->waterlevel >= 2)
+ PM_WaterMove ();
+ else {
+ vec3_t angles;
+
+ VectorCopy(pm->viewangles, angles);
+ if (angles[PITCH] > 180)
+ angles[PITCH] = angles[PITCH] - 360;
+ angles[PITCH] /= 3;
+
+ AngleVectors (angles, pml.forward, pml.right, pml.up);
+
+ PM_AirMove ();
+ }
+ }
+
+ // set groundentity, watertype, and waterlevel for final spot
+ PM_CatagorizePosition ();
+
+ PM_SnapPosition ();
+}
+
--- a/q_shared.h
+++ /dev/null
@@ -1,1149 +1,0 @@
-// q_shared.h -- included first by ALL program modules
-
-//#define id386
-
-typedef unsigned char byte;
-typedef enum {false, true} qboolean;
-
-typedef struct edict_t edict_t;
-
-// angle indexes
-#define PITCH 0 // up / down
-#define YAW 1 // left / right
-#define ROLL 2 // fall over
-
-#define MAX_STRING_CHARS 1024 // max length of a string passed to Cmd_TokenizeString
-#define MAX_STRING_TOKENS 80 // max tokens resulting from Cmd_TokenizeString
-#define MAX_TOKEN_CHARS 128 // max length of an individual token
-
-#define MAX_QPATH 64 // max length of a quake game pathname
-#define MAX_OSPATH 128 // max length of a filesystem pathname
-
-//
-// per-level limits
-//
-#define MAX_CLIENTS 256 // absolute limit
-#define MAX_EDICTS 1024 // must change protocol to increase more
-#define MAX_LIGHTSTYLES 256
-#define MAX_MODELS 256 // these are sent over the net as bytes
-#define MAX_SOUNDS 256 // so they cannot be blindly increased
-#define MAX_IMAGES 256
-#define MAX_ITEMS 256
-#define MAX_GENERAL (MAX_CLIENTS*2) // general config strings
-
-
-// game print flags
-#define PRINT_LOW 0 // pickup messages
-#define PRINT_MEDIUM 1 // death messages
-#define PRINT_HIGH 2 // critical messages
-#define PRINT_CHAT 3 // chat messages
-
-
-// destination class for gi.multicast()
-typedef enum
-{
-MULTICAST_ALL,
-MULTICAST_PHS,
-MULTICAST_PVS,
-MULTICAST_ALL_R,
-MULTICAST_PHS_R,
-MULTICAST_PVS_R
-} multicast_t;
-
-
-/*
-==============================================================
-
-MATHLIB
-
-==============================================================
-*/
-
-typedef float vec_t;
-typedef vec_t vec3_t[3];
-typedef vec_t vec5_t[5];
-
-typedef int fixed4_t;
-typedef int fixed8_t;
-typedef int fixed16_t;
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
-#endif
-
-struct cplane_s;
-
-extern vec3_t vec3_origin;
-
-#define nanmask (255<<23)
-
-#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
-
-#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
-#define VectorSubtract(a,b,c) (c[0]=a[0]-b[0],c[1]=a[1]-b[1],c[2]=a[2]-b[2])
-#define VectorAdd(a,b,c) (c[0]=a[0]+b[0],c[1]=a[1]+b[1],c[2]=a[2]+b[2])
-#define VectorCopy(a,b) (b[0]=a[0],b[1]=a[1],b[2]=a[2])
-#define VectorClear(a) (a[0]=a[1]=a[2]=0)
-#define VectorNegate(a,b) (b[0]=-a[0],b[1]=-a[1],b[2]=-a[2])
-#define VectorSet(v, x, y, z) (v[0]=(x), v[1]=(y), v[2]=(z))
-
-void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc);
-
-// just in case you do't want to use the macros
-vec_t _DotProduct (vec3_t v1, vec3_t v2);
-void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out);
-void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out);
-void _VectorCopy (vec3_t in, vec3_t out);
-
-void ClearBounds (vec3_t mins, vec3_t maxs);
-void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs);
-int VectorCompare (vec3_t v1, vec3_t v2);
-vec_t VectorLength (vec3_t v);
-void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross);
-vec_t VectorNormalize (vec3_t v); // returns vector length
-vec_t VectorNormalize2 (vec3_t v, vec3_t out);
-void VectorInverse (vec3_t v);
-void VectorScale (vec3_t in, vec_t scale, vec3_t out);
-
-void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]);
-void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]);
-
-void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
-int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *plane);
-float anglemod(float a);
-float LerpAngle (float a1, float a2, float frac);
-
-#define BOX_ON_PLANE_SIDE(emins, emaxs, p) \
- (((p)->type < 3)? \
- ( \
- ((p)->dist <= (emins)[(p)->type])? \
- 1 \
- : \
- ( \
- ((p)->dist >= (emaxs)[(p)->type])?\
- 2 \
- : \
- 3 \
- ) \
- ) \
- : \
- BoxOnPlaneSide( (emins), (emaxs), (p)))
-
-void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal );
-void PerpendicularVector( vec3_t dst, const vec3_t src );
-void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees );
-
-
-//=============================================
-
-char *COM_SkipPath (char *pathname);
-void COM_StripExtension (char *in, char *out);
-void COM_FileBase (char *in, char *out);
-void COM_FilePath (char *in, char *out);
-void COM_DefaultExtension (char *path, char *extension);
-
-char *COM_Parse (char **data_p);
-// data is an in/out parm, returns a parsed out token
-
-void Com_sprintf (char *dest, int size, char *fmt, ...);
-
-void Com_PageInMemory (byte *buffer, int size);
-
-//=============================================
-
-short BigShort(short l);
-short LittleShort(short l);
-int BigLong (int l);
-int LittleLong (int l);
-float BigFloat (float l);
-float LittleFloat (float l);
-
-void Swap_Init (void);
-char *va(char *format, ...);
-
-//=============================================
-
-//
-// key / value info strings
-//
-#define MAX_INFO_KEY 64
-#define MAX_INFO_VALUE 64
-#define MAX_INFO_STRING 512
-
-char *Info_ValueForKey (char *s, char *key);
-void Info_RemoveKey (char *s, char *key);
-void Info_SetValueForKey (char *s, char *key, char *value);
-qboolean Info_Validate (char *s);
-
-/*
-==============================================================
-
-SYSTEM SPECIFIC
-
-==============================================================
-*/
-
-extern int curtime; // time returned by last Sys_Milliseconds
-
-int Sys_Milliseconds (void);
-void Sys_Mkdir (char *path);
-vlong flen(int);
-
-// large block stack allocation routines
-void *Hunk_Begin (int maxsize);
-void *Hunk_Alloc (int size);
-void Hunk_Free (void *buf);
-int Hunk_End (void);
-
-// directory searching
-#define SFF_ARCH 0x01
-#define SFF_HIDDEN 0x02
-#define SFF_RDONLY 0x04
-#define SFF_SUBDIR 0x08
-#define SFF_SYSTEM 0x10
-
-/*
-** pass in an attribute mask of things you wish to REJECT
-*/
-char *Sys_FindFirst (char *path, uint musthave, uint canthave );
-char *Sys_FindNext ( uint musthave, uint canthave );
-void Sys_FindClose (void);
-
-
-// this is only here so the functions in q_shared.c and q_shwin.c can link
-void Sys_Error (char *error, ...);
-void Com_Printf (char *msg, ...);
-
-
-/*
-==========================================================
-
-CVARS (console variables)
-
-==========================================================
-*/
-
-#ifndef CVAR
-#define CVAR
-
-#define CVAR_ARCHIVE 1 // set to cause it to be saved to vars.rc
-#define CVAR_USERINFO 2 // added to userinfo when changed
-#define CVAR_SERVERINFO 4 // added to serverinfo when changed
-#define CVAR_NOSET 8 // don't allow change from console at all,
- // but can be set from the command line
-#define CVAR_LATCH 16 // save changes until server restart
-
-// nothing outside the Cvar_*() functions should modify these fields!
-typedef struct cvar_s
-{
- char *name;
- char *string;
- char *latched_string; // for CVAR_LATCH vars
- int flags;
- qboolean modified; // set each time the cvar is changed
- float value;
- struct cvar_s *next;
-} cvar_t;
-
-#endif // CVAR
-
-/*
-==============================================================
-
-COLLISION DETECTION
-
-==============================================================
-*/
-
-// lower bits are stronger, and will eat weaker brushes completely
-#define CONTENTS_SOLID 1 // an eye is never valid in a solid
-#define CONTENTS_WINDOW 2 // translucent, but not watery
-#define CONTENTS_AUX 4
-#define CONTENTS_LAVA 8
-#define CONTENTS_SLIME 16
-#define CONTENTS_WATER 32
-#define CONTENTS_MIST 64
-#define LAST_VISIBLE_CONTENTS 64
-
-// remaining contents are non-visible, and don't eat brushes
-
-#define CONTENTS_AREAPORTAL 0x8000
-
-#define CONTENTS_PLAYERCLIP 0x10000
-#define CONTENTS_MONSTERCLIP 0x20000
-
-// currents can be added to any other contents, and may be mixed
-#define CONTENTS_CURRENT_0 0x40000
-#define CONTENTS_CURRENT_90 0x80000
-#define CONTENTS_CURRENT_180 0x100000
-#define CONTENTS_CURRENT_270 0x200000
-#define CONTENTS_CURRENT_UP 0x400000
-#define CONTENTS_CURRENT_DOWN 0x800000
-
-#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity
-
-#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game
-#define CONTENTS_DEADMONSTER 0x4000000
-#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs
-#define CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans
-#define CONTENTS_LADDER 0x20000000
-
-
-
-#define SURF_LIGHT 0x1 // value will hold the light strength
-
-#define SURF_SLICK 0x2 // effects game physics
-
-#define SURF_SKY 0x4 // don't draw, but add to skybox
-#define SURF_WARP 0x8 // turbulent water warp
-#define SURF_TRANS33 0x10
-#define SURF_TRANS66 0x20
-#define SURF_FLOWING 0x40 // scroll towards angle
-#define SURF_NODRAW 0x80 // don't bother referencing the texture
-
-
-
-// content masks
-#define MASK_ALL (-1)
-#define MASK_SOLID (CONTENTS_SOLID|CONTENTS_WINDOW)
-#define MASK_PLAYERSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER)
-#define MASK_DEADSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW)
-#define MASK_MONSTERSOLID (CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER)
-#define MASK_WATER (CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME)
-#define MASK_OPAQUE (CONTENTS_SOLID|CONTENTS_SLIME|CONTENTS_LAVA)
-#define MASK_SHOT (CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_WINDOW|CONTENTS_DEADMONSTER)
-#define MASK_CURRENT (CONTENTS_CURRENT_0|CONTENTS_CURRENT_90|CONTENTS_CURRENT_180|CONTENTS_CURRENT_270|CONTENTS_CURRENT_UP|CONTENTS_CURRENT_DOWN)
-
-
-// gi.BoxEdicts() can return a list of either solid or trigger entities
-// FIXME: eliminate AREA_ distinction?
-#define AREA_SOLID 1
-#define AREA_TRIGGERS 2
-
-
-// plane_t structure
-// !!! if this is changed, it must be changed in asm code too !!!
-typedef struct cplane_s
-{
- vec3_t normal;
- float dist;
- byte type; // for fast side tests
- byte signbits; // signx + (signy<<1) + (signz<<1)
- byte pad[2];
-} cplane_t;
-
-// structure offset for asm code
-#define CPLANE_NORMAL_X 0
-#define CPLANE_NORMAL_Y 4
-#define CPLANE_NORMAL_Z 8
-#define CPLANE_DIST 12
-#define CPLANE_TYPE 16
-#define CPLANE_SIGNBITS 17
-#define CPLANE_PAD0 18
-#define CPLANE_PAD1 19
-
-typedef struct cmodel_s
-{
- vec3_t mins, maxs;
- vec3_t origin; // for sounds or lights
- int headnode;
-} cmodel_t;
-
-typedef struct csurface_s
-{
- char name[16];
- int flags;
- int value;
-} csurface_t;
-
-typedef struct mapsurface_s // used internally due to name len probs //ZOID
-{
- csurface_t c;
- char rname[32];
-} mapsurface_t;
-
-// a trace is returned when a box is swept through the world
-typedef struct
-{
- qboolean allsolid; // if true, plane is not valid
- qboolean startsolid; // if true, the initial point was in a solid area
- float fraction; // time completed, 1.0 = didn't hit anything
- vec3_t endpos; // final position
- cplane_t plane; // surface normal at impact
- csurface_t *surface; // surface hit
- int contents; // contents on other side of surface hit
- edict_t *ent; // not set by CM_*() functions
-} trace_t;
-
-
-
-// pmove_state_t is the information necessary for client side movement
-// prediction
-typedef enum
-{
- // can accelerate and turn
- PM_NORMAL,
- PM_SPECTATOR,
- // no acceleration or turning
- PM_DEAD,
- PM_GIB, // different bounding box
- PM_FREEZE
-} pmtype_t;
-
-// pmove->pm_flags
-#define PMF_DUCKED 1
-#define PMF_JUMP_HELD 2
-#define PMF_ON_GROUND 4
-#define PMF_TIME_WATERJUMP 8 // pm_time is waterjump
-#define PMF_TIME_LAND 16 // pm_time is time before rejump
-#define PMF_TIME_TELEPORT 32 // pm_time is non-moving time
-#define PMF_NO_PREDICTION 64 // temporarily disables prediction (used for grappling hook)
-
-// this structure needs to be communicated bit-accurate
-// from the server to the client to guarantee that
-// prediction stays in sync, so no floats are used.
-// if any part of the game code modifies this struct, it
-// will result in a prediction error of some degree.
-typedef struct
-{
- pmtype_t pm_type;
-
- short origin[3]; // 12.3
- short velocity[3]; // 12.3
- byte pm_flags; // ducked, jump_held, etc
- byte pm_time; // each unit = 8 ms
- short gravity;
- short delta_angles[3]; // add to command angles to get view direction
- // changed by spawns, rotating objects, and teleporters
-} pmove_state_t;
-
-
-//
-// button bits
-//
-#define BUTTON_ATTACK 1
-#define BUTTON_USE 2
-#define BUTTON_ANY 128 // any key whatsoever
-
-
-// usercmd_t is sent to the server each client frame
-typedef struct usercmd_s
-{
- byte msec;
- byte buttons;
- short angles[3];
- short forwardmove, sidemove, upmove;
- byte impulse; // remove?
- byte lightlevel; // light level the player is standing on
-} usercmd_t;
-
-
-#define MAXTOUCH 32
-typedef struct
-{
- // state (in / out)
- pmove_state_t s;
-
- // command (in)
- usercmd_t cmd;
- qboolean snapinitial; // if s has been changed outside pmove
-
- // results (out)
- int numtouch;
- edict_t *touchents[MAXTOUCH];
-
- vec3_t viewangles; // clamped
- float viewheight;
-
- vec3_t mins, maxs; // bounding box size
-
- edict_t *groundentity;
- int watertype;
- int waterlevel;
-
- // callbacks to test the world
- trace_t (*trace) (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
- int (*pointcontents) (vec3_t point);
-} pmove_t;
-
-
-// entity_state_t->effects
-// Effects are things handled on the client side (lights, particles, frame animations)
-// that happen constantly on the given entity.
-// An entity that has effects will be sent to the client
-// even if it has a zero index model.
-#define EF_ROTATE 0x00000001 // rotate (bonus items)
-#define EF_GIB 0x00000002 // leave a trail
-#define EF_BLASTER 0x00000008 // redlight + trail
-#define EF_ROCKET 0x00000010 // redlight + trail
-#define EF_GRENADE 0x00000020
-#define EF_HYPERBLASTER 0x00000040
-#define EF_BFG 0x00000080
-#define EF_COLOR_SHELL 0x00000100
-#define EF_POWERSCREEN 0x00000200
-#define EF_ANIM01 0x00000400 // automatically cycle between frames 0 and 1 at 2 hz
-#define EF_ANIM23 0x00000800 // automatically cycle between frames 2 and 3 at 2 hz
-#define EF_ANIM_ALL 0x00001000 // automatically cycle through all frames at 2hz
-#define EF_ANIM_ALLFAST 0x00002000 // automatically cycle through all frames at 10hz
-#define EF_FLIES 0x00004000
-#define EF_QUAD 0x00008000
-#define EF_PENT 0x00010000
-#define EF_TELEPORTER 0x00020000 // particle fountain
-#define EF_FLAG1 0x00040000
-#define EF_FLAG2 0x00080000
-// RAFAEL
-#define EF_IONRIPPER 0x00100000
-#define EF_GREENGIB 0x00200000
-#define EF_BLUEHYPERBLASTER 0x00400000
-#define EF_SPINNINGLIGHTS 0x00800000
-#define EF_PLASMA 0x01000000
-#define EF_TRAP 0x02000000
-
-//ROGUE
-#define EF_TRACKER 0x04000000
-#define EF_DOUBLE 0x08000000
-#define EF_SPHERETRANS 0x10000000
-#define EF_TAGTRAIL 0x20000000
-#define EF_HALF_DAMAGE 0x40000000
-#define EF_TRACKERTRAIL 0x80000000
-//ROGUE
-
-// entity_state_t->renderfx flags
-#define RF_MINLIGHT 1 // allways have some light (viewmodel)
-#define RF_VIEWERMODEL 2 // don't draw through eyes, only mirrors
-#define RF_WEAPONMODEL 4 // only draw through eyes
-#define RF_FULLBRIGHT 8 // allways draw full intensity
-#define RF_DEPTHHACK 16 // for view weapon Z crunching
-#define RF_TRANSLUCENT 32
-#define RF_FRAMELERP 64
-#define RF_BEAM 128
-#define RF_CUSTOMSKIN 256 // skin is an index in image_precache
-#define RF_GLOW 512 // pulse lighting for bonus items
-#define RF_SHELL_RED 1024
-#define RF_SHELL_GREEN 2048
-#define RF_SHELL_BLUE 4096
-
-//ROGUE
-#define RF_IR_VISIBLE 0x00008000 // 32768
-#define RF_SHELL_DOUBLE 0x00010000 // 65536
-#define RF_SHELL_HALF_DAM 0x00020000
-#define RF_USE_DISGUISE 0x00040000
-//ROGUE
-
-// player_state_t->refdef flags
-#define RDF_UNDERWATER 1 // warp the screen as apropriate
-#define RDF_NOWORLDMODEL 2 // used for player configuration screen
-
-//ROGUE
-#define RDF_IRGOGGLES 4
-#define RDF_UVGOGGLES 8
-//ROGUE
-
-//
-// muzzle flashes / player effects
-//
-#define MZ_BLASTER 0
-#define MZ_MACHINEGUN 1
-#define MZ_SHOTGUN 2
-#define MZ_CHAINGUN1 3
-#define MZ_CHAINGUN2 4
-#define MZ_CHAINGUN3 5
-#define MZ_RAILGUN 6
-#define MZ_ROCKET 7
-#define MZ_GRENADE 8
-#define MZ_LOGIN 9
-#define MZ_LOGOUT 10
-#define MZ_RESPAWN 11
-#define MZ_BFG 12
-#define MZ_SSHOTGUN 13
-#define MZ_HYPERBLASTER 14
-#define MZ_ITEMRESPAWN 15
-// RAFAEL
-#define MZ_IONRIPPER 16
-#define MZ_BLUEHYPERBLASTER 17
-#define MZ_PHALANX 18
-#define MZ_SILENCED 128 // bit flag ORed with one of the above numbers
-
-//ROGUE
-#define MZ_ETF_RIFLE 30
-#define MZ_UNUSED 31
-#define MZ_SHOTGUN2 32
-#define MZ_HEATBEAM 33
-#define MZ_BLASTER2 34
-#define MZ_TRACKER 35
-#define MZ_NUKE1 36
-#define MZ_NUKE2 37
-#define MZ_NUKE4 38
-#define MZ_NUKE8 39
-//ROGUE
-
-//
-// monster muzzle flashes
-//
-#define MZ2_TANK_BLASTER_1 1
-#define MZ2_TANK_BLASTER_2 2
-#define MZ2_TANK_BLASTER_3 3
-#define MZ2_TANK_MACHINEGUN_1 4
-#define MZ2_TANK_MACHINEGUN_2 5
-#define MZ2_TANK_MACHINEGUN_3 6
-#define MZ2_TANK_MACHINEGUN_4 7
-#define MZ2_TANK_MACHINEGUN_5 8
-#define MZ2_TANK_MACHINEGUN_6 9
-#define MZ2_TANK_MACHINEGUN_7 10
-#define MZ2_TANK_MACHINEGUN_8 11
-#define MZ2_TANK_MACHINEGUN_9 12
-#define MZ2_TANK_MACHINEGUN_10 13
-#define MZ2_TANK_MACHINEGUN_11 14
-#define MZ2_TANK_MACHINEGUN_12 15
-#define MZ2_TANK_MACHINEGUN_13 16
-#define MZ2_TANK_MACHINEGUN_14 17
-#define MZ2_TANK_MACHINEGUN_15 18
-#define MZ2_TANK_MACHINEGUN_16 19
-#define MZ2_TANK_MACHINEGUN_17 20
-#define MZ2_TANK_MACHINEGUN_18 21
-#define MZ2_TANK_MACHINEGUN_19 22
-#define MZ2_TANK_ROCKET_1 23
-#define MZ2_TANK_ROCKET_2 24
-#define MZ2_TANK_ROCKET_3 25
-
-#define MZ2_INFANTRY_MACHINEGUN_1 26
-#define MZ2_INFANTRY_MACHINEGUN_2 27
-#define MZ2_INFANTRY_MACHINEGUN_3 28
-#define MZ2_INFANTRY_MACHINEGUN_4 29
-#define MZ2_INFANTRY_MACHINEGUN_5 30
-#define MZ2_INFANTRY_MACHINEGUN_6 31
-#define MZ2_INFANTRY_MACHINEGUN_7 32
-#define MZ2_INFANTRY_MACHINEGUN_8 33
-#define MZ2_INFANTRY_MACHINEGUN_9 34
-#define MZ2_INFANTRY_MACHINEGUN_10 35
-#define MZ2_INFANTRY_MACHINEGUN_11 36
-#define MZ2_INFANTRY_MACHINEGUN_12 37
-#define MZ2_INFANTRY_MACHINEGUN_13 38
-
-#define MZ2_SOLDIER_BLASTER_1 39
-#define MZ2_SOLDIER_BLASTER_2 40
-#define MZ2_SOLDIER_SHOTGUN_1 41
-#define MZ2_SOLDIER_SHOTGUN_2 42
-#define MZ2_SOLDIER_MACHINEGUN_1 43
-#define MZ2_SOLDIER_MACHINEGUN_2 44
-
-#define MZ2_GUNNER_MACHINEGUN_1 45
-#define MZ2_GUNNER_MACHINEGUN_2 46
-#define MZ2_GUNNER_MACHINEGUN_3 47
-#define MZ2_GUNNER_MACHINEGUN_4 48
-#define MZ2_GUNNER_MACHINEGUN_5 49
-#define MZ2_GUNNER_MACHINEGUN_6 50
-#define MZ2_GUNNER_MACHINEGUN_7 51
-#define MZ2_GUNNER_MACHINEGUN_8 52
-#define MZ2_GUNNER_GRENADE_1 53
-#define MZ2_GUNNER_GRENADE_2 54
-#define MZ2_GUNNER_GRENADE_3 55
-#define MZ2_GUNNER_GRENADE_4 56
-
-#define MZ2_CHICK_ROCKET_1 57
-
-#define MZ2_FLYER_BLASTER_1 58
-#define MZ2_FLYER_BLASTER_2 59
-
-#define MZ2_MEDIC_BLASTER_1 60
-
-#define MZ2_GLADIATOR_RAILGUN_1 61
-
-#define MZ2_HOVER_BLASTER_1 62
-
-#define MZ2_ACTOR_MACHINEGUN_1 63
-
-#define MZ2_SUPERTANK_MACHINEGUN_1 64
-#define MZ2_SUPERTANK_MACHINEGUN_2 65
-#define MZ2_SUPERTANK_MACHINEGUN_3 66
-#define MZ2_SUPERTANK_MACHINEGUN_4 67
-#define MZ2_SUPERTANK_MACHINEGUN_5 68
-#define MZ2_SUPERTANK_MACHINEGUN_6 69
-#define MZ2_SUPERTANK_ROCKET_1 70
-#define MZ2_SUPERTANK_ROCKET_2 71
-#define MZ2_SUPERTANK_ROCKET_3 72
-
-#define MZ2_BOSS2_MACHINEGUN_L1 73
-#define MZ2_BOSS2_MACHINEGUN_L2 74
-#define MZ2_BOSS2_MACHINEGUN_L3 75
-#define MZ2_BOSS2_MACHINEGUN_L4 76
-#define MZ2_BOSS2_MACHINEGUN_L5 77
-#define MZ2_BOSS2_ROCKET_1 78
-#define MZ2_BOSS2_ROCKET_2 79
-#define MZ2_BOSS2_ROCKET_3 80
-#define MZ2_BOSS2_ROCKET_4 81
-
-#define MZ2_FLOAT_BLASTER_1 82
-
-#define MZ2_SOLDIER_BLASTER_3 83
-#define MZ2_SOLDIER_SHOTGUN_3 84
-#define MZ2_SOLDIER_MACHINEGUN_3 85
-#define MZ2_SOLDIER_BLASTER_4 86
-#define MZ2_SOLDIER_SHOTGUN_4 87
-#define MZ2_SOLDIER_MACHINEGUN_4 88
-#define MZ2_SOLDIER_BLASTER_5 89
-#define MZ2_SOLDIER_SHOTGUN_5 90
-#define MZ2_SOLDIER_MACHINEGUN_5 91
-#define MZ2_SOLDIER_BLASTER_6 92
-#define MZ2_SOLDIER_SHOTGUN_6 93
-#define MZ2_SOLDIER_MACHINEGUN_6 94
-#define MZ2_SOLDIER_BLASTER_7 95
-#define MZ2_SOLDIER_SHOTGUN_7 96
-#define MZ2_SOLDIER_MACHINEGUN_7 97
-#define MZ2_SOLDIER_BLASTER_8 98
-#define MZ2_SOLDIER_SHOTGUN_8 99
-#define MZ2_SOLDIER_MACHINEGUN_8 100
-
-// --- Xian shit below ---
-#define MZ2_MAKRON_BFG 101
-#define MZ2_MAKRON_BLASTER_1 102
-#define MZ2_MAKRON_BLASTER_2 103
-#define MZ2_MAKRON_BLASTER_3 104
-#define MZ2_MAKRON_BLASTER_4 105
-#define MZ2_MAKRON_BLASTER_5 106
-#define MZ2_MAKRON_BLASTER_6 107
-#define MZ2_MAKRON_BLASTER_7 108
-#define MZ2_MAKRON_BLASTER_8 109
-#define MZ2_MAKRON_BLASTER_9 110
-#define MZ2_MAKRON_BLASTER_10 111
-#define MZ2_MAKRON_BLASTER_11 112
-#define MZ2_MAKRON_BLASTER_12 113
-#define MZ2_MAKRON_BLASTER_13 114
-#define MZ2_MAKRON_BLASTER_14 115
-#define MZ2_MAKRON_BLASTER_15 116
-#define MZ2_MAKRON_BLASTER_16 117
-#define MZ2_MAKRON_BLASTER_17 118
-#define MZ2_MAKRON_RAILGUN_1 119
-#define MZ2_JORG_MACHINEGUN_L1 120
-#define MZ2_JORG_MACHINEGUN_L2 121
-#define MZ2_JORG_MACHINEGUN_L3 122
-#define MZ2_JORG_MACHINEGUN_L4 123
-#define MZ2_JORG_MACHINEGUN_L5 124
-#define MZ2_JORG_MACHINEGUN_L6 125
-#define MZ2_JORG_MACHINEGUN_R1 126
-#define MZ2_JORG_MACHINEGUN_R2 127
-#define MZ2_JORG_MACHINEGUN_R3 128
-#define MZ2_JORG_MACHINEGUN_R4 129
-#define MZ2_JORG_MACHINEGUN_R5 130
-#define MZ2_JORG_MACHINEGUN_R6 131
-#define MZ2_JORG_BFG_1 132
-#define MZ2_BOSS2_MACHINEGUN_R1 133
-#define MZ2_BOSS2_MACHINEGUN_R2 134
-#define MZ2_BOSS2_MACHINEGUN_R3 135
-#define MZ2_BOSS2_MACHINEGUN_R4 136
-#define MZ2_BOSS2_MACHINEGUN_R5 137
-
-//ROGUE
-#define MZ2_CARRIER_MACHINEGUN_L1 138
-#define MZ2_CARRIER_MACHINEGUN_R1 139
-#define MZ2_CARRIER_GRENADE 140
-#define MZ2_TURRET_MACHINEGUN 141
-#define MZ2_TURRET_ROCKET 142
-#define MZ2_TURRET_BLASTER 143
-#define MZ2_STALKER_BLASTER 144
-#define MZ2_DAEDALUS_BLASTER 145
-#define MZ2_MEDIC_BLASTER_2 146
-#define MZ2_CARRIER_RAILGUN 147
-#define MZ2_WIDOW_DISRUPTOR 148
-#define MZ2_WIDOW_BLASTER 149
-#define MZ2_WIDOW_RAIL 150
-#define MZ2_WIDOW_PLASMABEAM 151 // PMM - not used
-#define MZ2_CARRIER_MACHINEGUN_L2 152
-#define MZ2_CARRIER_MACHINEGUN_R2 153
-#define MZ2_WIDOW_RAIL_LEFT 154
-#define MZ2_WIDOW_RAIL_RIGHT 155
-#define MZ2_WIDOW_BLASTER_SWEEP1 156
-#define MZ2_WIDOW_BLASTER_SWEEP2 157
-#define MZ2_WIDOW_BLASTER_SWEEP3 158
-#define MZ2_WIDOW_BLASTER_SWEEP4 159
-#define MZ2_WIDOW_BLASTER_SWEEP5 160
-#define MZ2_WIDOW_BLASTER_SWEEP6 161
-#define MZ2_WIDOW_BLASTER_SWEEP7 162
-#define MZ2_WIDOW_BLASTER_SWEEP8 163
-#define MZ2_WIDOW_BLASTER_SWEEP9 164
-#define MZ2_WIDOW_BLASTER_100 165
-#define MZ2_WIDOW_BLASTER_90 166
-#define MZ2_WIDOW_BLASTER_80 167
-#define MZ2_WIDOW_BLASTER_70 168
-#define MZ2_WIDOW_BLASTER_60 169
-#define MZ2_WIDOW_BLASTER_50 170
-#define MZ2_WIDOW_BLASTER_40 171
-#define MZ2_WIDOW_BLASTER_30 172
-#define MZ2_WIDOW_BLASTER_20 173
-#define MZ2_WIDOW_BLASTER_10 174
-#define MZ2_WIDOW_BLASTER_0 175
-#define MZ2_WIDOW_BLASTER_10L 176
-#define MZ2_WIDOW_BLASTER_20L 177
-#define MZ2_WIDOW_BLASTER_30L 178
-#define MZ2_WIDOW_BLASTER_40L 179
-#define MZ2_WIDOW_BLASTER_50L 180
-#define MZ2_WIDOW_BLASTER_60L 181
-#define MZ2_WIDOW_BLASTER_70L 182
-#define MZ2_WIDOW_RUN_1 183
-#define MZ2_WIDOW_RUN_2 184
-#define MZ2_WIDOW_RUN_3 185
-#define MZ2_WIDOW_RUN_4 186
-#define MZ2_WIDOW_RUN_5 187
-#define MZ2_WIDOW_RUN_6 188
-#define MZ2_WIDOW_RUN_7 189
-#define MZ2_WIDOW_RUN_8 190
-#define MZ2_CARRIER_ROCKET_1 191
-#define MZ2_CARRIER_ROCKET_2 192
-#define MZ2_CARRIER_ROCKET_3 193
-#define MZ2_CARRIER_ROCKET_4 194
-#define MZ2_WIDOW2_BEAMER_1 195
-#define MZ2_WIDOW2_BEAMER_2 196
-#define MZ2_WIDOW2_BEAMER_3 197
-#define MZ2_WIDOW2_BEAMER_4 198
-#define MZ2_WIDOW2_BEAMER_5 199
-#define MZ2_WIDOW2_BEAM_SWEEP_1 200
-#define MZ2_WIDOW2_BEAM_SWEEP_2 201
-#define MZ2_WIDOW2_BEAM_SWEEP_3 202
-#define MZ2_WIDOW2_BEAM_SWEEP_4 203
-#define MZ2_WIDOW2_BEAM_SWEEP_5 204
-#define MZ2_WIDOW2_BEAM_SWEEP_6 205
-#define MZ2_WIDOW2_BEAM_SWEEP_7 206
-#define MZ2_WIDOW2_BEAM_SWEEP_8 207
-#define MZ2_WIDOW2_BEAM_SWEEP_9 208
-#define MZ2_WIDOW2_BEAM_SWEEP_10 209
-#define MZ2_WIDOW2_BEAM_SWEEP_11 210
-
-// ROGUE
-
-extern vec3_t monster_flash_offset [];
-
-
-// temp entity events
-//
-// Temp entity events are for things that happen
-// at a location seperate from any existing entity.
-// Temporary entity messages are explicitly constructed
-// and broadcast.
-typedef enum
-{
- TE_GUNSHOT,
- TE_BLOOD,
- TE_BLASTER,
- TE_RAILTRAIL,
- TE_SHOTGUN,
- TE_EXPLOSION1,
- TE_EXPLOSION2,
- TE_ROCKET_EXPLOSION,
- TE_GRENADE_EXPLOSION,
- TE_SPARKS,
- TE_SPLASH,
- TE_BUBBLETRAIL,
- TE_SCREEN_SPARKS,
- TE_SHIELD_SPARKS,
- TE_BULLET_SPARKS,
- TE_LASER_SPARKS,
- TE_PARASITE_ATTACK,
- TE_ROCKET_EXPLOSION_WATER,
- TE_GRENADE_EXPLOSION_WATER,
- TE_MEDIC_CABLE_ATTACK,
- TE_BFG_EXPLOSION,
- TE_BFG_BIGEXPLOSION,
- TE_BOSSTPORT, // used as '22' in a map, so DON'T RENUMBER!!!
- TE_BFG_LASER,
- TE_GRAPPLE_CABLE,
- TE_WELDING_SPARKS,
- TE_GREENBLOOD,
- TE_BLUEHYPERBLASTER,
- TE_PLASMA_EXPLOSION,
- TE_TUNNEL_SPARKS,
-//ROGUE
- TE_BLASTER2,
- TE_RAILTRAIL2,
- TE_FLAME,
- TE_LIGHTNING,
- TE_DEBUGTRAIL,
- TE_PLAIN_EXPLOSION,
- TE_FLASHLIGHT,
- TE_FORCEWALL,
- TE_HEATBEAM,
- TE_MONSTER_HEATBEAM,
- TE_STEAM,
- TE_BUBBLETRAIL2,
- TE_MOREBLOOD,
- TE_HEATBEAM_SPARKS,
- TE_HEATBEAM_STEAM,
- TE_CHAINFIST_SMOKE,
- TE_ELECTRIC_SPARKS,
- TE_TRACKER_EXPLOSION,
- TE_TELEPORT_EFFECT,
- TE_DBALL_GOAL,
- TE_WIDOWBEAMOUT,
- TE_NUKEBLAST,
- TE_WIDOWSPLASH,
- TE_EXPLOSION1_BIG,
- TE_EXPLOSION1_NP,
- TE_FLECHETTE
-//ROGUE
-} temp_event_t;
-
-#define SPLASH_UNKNOWN 0
-#define SPLASH_SPARKS 1
-#define SPLASH_BLUE_WATER 2
-#define SPLASH_BROWN_WATER 3
-#define SPLASH_SLIME 4
-#define SPLASH_LAVA 5
-#define SPLASH_BLOOD 6
-
-
-// sound channels
-// channel 0 never willingly overrides
-// other channels (1-7) allways override a playing sound on that channel
-#define CHAN_AUTO 0
-#define CHAN_WEAPON 1
-#define CHAN_VOICE 2
-#define CHAN_ITEM 3
-#define CHAN_BODY 4
-// modifier flags
-#define CHAN_NO_PHS_ADD 8 // send to all clients, not just ones in PHS (ATTN 0 will also do this)
-#define CHAN_RELIABLE 16 // send by reliable message, not datagram
-
-
-// sound attenuation values
-#define ATTN_NONE 0 // full volume the entire level
-#define ATTN_NORM 1
-#define ATTN_IDLE 2
-#define ATTN_STATIC 3 // diminish very rapidly with distance
-
-
-// player_state->stats[] indexes
-#define STAT_HEALTH_ICON 0
-#define STAT_HEALTH 1
-#define STAT_AMMO_ICON 2
-#define STAT_AMMO 3
-#define STAT_ARMOR_ICON 4
-#define STAT_ARMOR 5
-#define STAT_SELECTED_ICON 6
-#define STAT_PICKUP_ICON 7
-#define STAT_PICKUP_STRING 8
-#define STAT_TIMER_ICON 9
-#define STAT_TIMER 10
-#define STAT_HELPICON 11
-#define STAT_SELECTED_ITEM 12
-#define STAT_LAYOUTS 13
-#define STAT_FRAGS 14
-#define STAT_FLASHES 15 // cleared each frame, 1 = health, 2 = armor
-#define STAT_CHASE 16
-#define STAT_SPECTATOR 17
-
-#define MAX_STATS 32
-
-
-// dmflags->value flags
-#define DF_NO_HEALTH 0x00000001 // 1
-#define DF_NO_ITEMS 0x00000002 // 2
-#define DF_WEAPONS_STAY 0x00000004 // 4
-#define DF_NO_FALLING 0x00000008 // 8
-#define DF_INSTANT_ITEMS 0x00000010 // 16
-#define DF_SAME_LEVEL 0x00000020 // 32
-#define DF_SKINTEAMS 0x00000040 // 64
-#define DF_MODELTEAMS 0x00000080 // 128
-#define DF_NO_FRIENDLY_FIRE 0x00000100 // 256
-#define DF_SPAWN_FARTHEST 0x00000200 // 512
-#define DF_FORCE_RESPAWN 0x00000400 // 1024
-#define DF_NO_ARMOR 0x00000800 // 2048
-#define DF_ALLOW_EXIT 0x00001000 // 4096
-#define DF_INFINITE_AMMO 0x00002000 // 8192
-#define DF_QUAD_DROP 0x00004000 // 16384
-#define DF_FIXED_FOV 0x00008000 // 32768
-
-// RAFAEL
-#define DF_QUADFIRE_DROP 0x00010000 // 65536
-
-//ROGUE
-#define DF_NO_MINES 0x00020000
-#define DF_NO_STACK_DOUBLE 0x00040000
-#define DF_NO_NUKES 0x00080000
-#define DF_NO_SPHERES 0x00100000
-//ROGUE
-
-/*
-ROGUE - VERSIONS
-1234 08/13/1998 Activision
-1235 08/14/1998 Id Software
-1236 08/15/1998 Steve Tietze
-1237 08/15/1998 Phil Dobranski
-1238 08/15/1998 John Sheley
-1239 08/17/1998 Barrett Alexander
-1230 08/17/1998 Brandon Fish
-1245 08/17/1998 Don MacAskill
-1246 08/17/1998 David "Zoid" Kirsch
-1247 08/17/1998 Manu Smith
-1248 08/17/1998 Geoff Scully
-1249 08/17/1998 Andy Van Fossen
-1240 08/20/1998 Activision Build 2
-1256 08/20/1998 Ranger Clan
-1257 08/20/1998 Ensemble Studios
-1258 08/21/1998 Robert Duffy
-1259 08/21/1998 Stephen Seachord
-1250 08/21/1998 Stephen Heaslip
-1267 08/21/1998 Samir Sandesara
-1268 08/21/1998 Oliver Wyman
-1269 08/21/1998 Steven Marchegiano
-1260 08/21/1998 Build #2 for Nihilistic
-1278 08/21/1998 Build #2 for Ensemble
-
-9999 08/20/1998 Internal Use
-*/
-#define ROGUE_VERSION_ID 1278
-
-#define ROGUE_VERSION_STRING "08/21/1998 Beta 2 for Ensemble"
-
-// ROGUE
-/*
-==========================================================
-
- ELEMENTS COMMUNICATED ACROSS THE NET
-
-==========================================================
-*/
-
-#define ANGLE2SHORT(x) ((int)((x)*65536/360) & 65535)
-#define SHORT2ANGLE(x) ((x)*(360.0/65536))
-
-
-//
-// config strings are a general means of communication from
-// the server to all connected clients.
-// Each config string can be at most MAX_QPATH characters.
-//
-#define CS_NAME 0
-#define CS_CDTRACK 1
-#define CS_SKY 2
-#define CS_SKYAXIS 3 // %f %f %f format
-#define CS_SKYROTATE 4
-#define CS_STATUSBAR 5 // display program string
-
-#define CS_AIRACCEL 29 // air acceleration control
-#define CS_MAXCLIENTS 30
-#define CS_MAPCHECKSUM 31 // for catching cheater maps
-
-#define CS_MODELS 32
-#define CS_SOUNDS (CS_MODELS+MAX_MODELS)
-#define CS_IMAGES (CS_SOUNDS+MAX_SOUNDS)
-#define CS_LIGHTS (CS_IMAGES+MAX_IMAGES)
-#define CS_ITEMS (CS_LIGHTS+MAX_LIGHTSTYLES)
-#define CS_PLAYERSKINS (CS_ITEMS+MAX_ITEMS)
-#define CS_GENERAL (CS_PLAYERSKINS+MAX_CLIENTS)
-#define MAX_CONFIGSTRINGS (CS_GENERAL+MAX_GENERAL)
-
-
-//==============================================
-
-
-// entity_state_t->event values
-// ertity events are for effects that take place reletive
-// to an existing entities origin. Very network efficient.
-// All muzzle flashes really should be converted to events...
-typedef enum
-{
- EV_NONE,
- EV_ITEM_RESPAWN,
- EV_FOOTSTEP,
- EV_FALLSHORT,
- EV_FALL,
- EV_FALLFAR,
- EV_PLAYER_TELEPORT,
- EV_OTHER_TELEPORT
-} entity_event_t;
-
-
-// entity_state_t is the information conveyed from the server
-// in an update message about entities that the client will
-// need to render in some way
-typedef struct entity_state_s
-{
- int number; // edict index
-
- vec3_t origin;
- vec3_t angles;
- vec3_t old_origin; // for lerping
- int modelindex;
- int modelindex2, modelindex3, modelindex4; // weapons, CTF flags, etc
- int frame;
- int skinnum;
- unsigned int effects; // PGM - we're filling it, so it needs to be unsigned
- int renderfx;
- int solid; // for client side prediction, 8*(bits 0-4) is x/y radius
- // 8*(bits 5-9) is z down distance, 8(bits10-15) is z up
- // gi.linkentity sets this properly
- int sound; // for looping sounds, to guarantee shutoff
- int event; // impulse events -- muzzle flashes, footsteps, etc
- // events only go out for a single frame, they
- // are automatically cleared each frame
-} entity_state_t;
-
-//==============================================
-
-
-// player_state_t is the information needed in addition to pmove_state_t
-// to rendered a view. There will only be 10 player_state_t sent each second,
-// but the number of pmove_state_t changes will be reletive to client
-// frame rates
-typedef struct
-{
- pmove_state_t pmove; // for prediction
-
- // these fields do not need to be communicated bit-precise
-
- vec3_t viewangles; // for fixed views
- vec3_t viewoffset; // add to pmovestate->origin
- vec3_t kick_angles; // add to view direction to get render angles
- // set by weapon kicks, pain effects, etc
-
- vec3_t gunangles;
- vec3_t gunoffset;
- int gunindex;
- int gunframe;
-
- float blend[4]; // rgba full screen effect
-
- float fov; // horizontal field of view
-
- int rdflags; // refdef flags
-
- short stats[MAX_STATS]; // fast status bar updates
-} player_state_t;
-
-
-// ==================
-// PGM
-#define VIDREF_GL 1
-#define VIDREF_SOFT 2
-#define VIDREF_OTHER 3
-
-extern int vidref_val;
-// PGM
-// ==================
-
-/* FIXME: figure out how to do this cleanly without kilometric headers */
-
-/* game dll */
-#include "../game/game.h" /* baseq2 */
-#include "../game/g_local.h"
-//#include "../ctf/game.h" /* ctf */
-//#include "../ctf/p_menu.h"
-//#include "../ctf/g_ctf.h"
-/* common */
-#include "../qcommon/qcommon.h"
-#include "../qcommon/qfiles.h"
-/* client */
-#include "../client/cdaudio.h"
-#include "../client/ref.h"
-#include "../client/vid.h"
-#include "../client/screen.h"
-#include "../client/snd_loc.h"
-#include "../client/sound.h"
-#include "../client/input.h"
-#include "../client/keys.h"
-#include "../client/console.h"
-#include "../client/client.h"
-#include "../client/qmenu.h"
-/* refresh */
-#include "../ref/r_local.h"
-/* server */
-#include "../server/server.h"
--- a/qcommon/cmd.c
+++ /dev/null
@@ -1,876 +1,0 @@
-// cmd.c -- Quake script command processing module
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-void Cmd_ForwardToServer (void);
-
-#define MAX_ALIAS_NAME 32
-
-typedef struct cmdalias_s
-{
- struct cmdalias_s *next;
- char name[MAX_ALIAS_NAME];
- char *value;
-} cmdalias_t;
-
-cmdalias_t *cmd_alias;
-
-qboolean cmd_wait;
-
-#define ALIAS_LOOP_COUNT 16
-int alias_count; // for detecting runaway loops
-
-
-//=============================================================================
-
-/*
-============
-Cmd_Wait_f
-
-Causes execution of the remainder of the command buffer to be delayed until
-next frame. This allows commands like:
-bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2"
-============
-*/
-void Cmd_Wait_f (void)
-{
- cmd_wait = true;
-}
-
-
-/*
-=============================================================================
-
- COMMAND BUFFER
-
-=============================================================================
-*/
-
-sizebuf_t cmd_text;
-byte cmd_text_buf[8192];
-
-byte defer_text_buf[8192];
-
-/*
-============
-Cbuf_Init
-============
-*/
-void Cbuf_Init (void)
-{
- SZ_Init (&cmd_text, cmd_text_buf, sizeof(cmd_text_buf));
-}
-
-/*
-============
-Cbuf_AddText
-
-Adds command text at the end of the buffer
-============
-*/
-void Cbuf_AddText (char *text)
-{
- int l;
-
- l = strlen (text);
-
- if (cmd_text.cursize + l >= cmd_text.maxsize)
- {
- Com_Printf ("Cbuf_AddText: overflow\n");
- return;
- }
- SZ_Write (&cmd_text, text, strlen (text));
-}
-
-
-/*
-============
-Cbuf_InsertText
-
-Adds command text immediately after the current command
-Adds a \n to the text
-FIXME: actually change the command buffer to do less copying
-============
-*/
-void Cbuf_InsertText (char *text)
-{
- char *temp;
- int templen;
-
-// copy off any commands still remaining in the exec buffer
- templen = cmd_text.cursize;
- if (templen)
- {
- temp = Z_Malloc (templen);
- memcpy (temp, cmd_text.data, templen);
- SZ_Clear (&cmd_text);
- }
- else
- temp = NULL; // shut up compiler
-
-// add the entire text of the file
- Cbuf_AddText (text);
-
-// add the copied off data
- if (templen)
- {
- SZ_Write (&cmd_text, temp, templen);
- Z_Free (temp);
- }
-}
-
-
-/*
-============
-Cbuf_CopyToDefer
-============
-*/
-void Cbuf_CopyToDefer (void)
-{
- memcpy(defer_text_buf, cmd_text_buf, cmd_text.cursize);
- defer_text_buf[cmd_text.cursize] = 0;
- cmd_text.cursize = 0;
-}
-
-/*
-============
-Cbuf_InsertFromDefer
-============
-*/
-void Cbuf_InsertFromDefer (void)
-{
- Cbuf_InsertText ((char *)defer_text_buf);
- defer_text_buf[0] = 0;
-}
-
-
-/*
-============
-Cbuf_ExecuteText
-============
-*/
-void Cbuf_ExecuteText (int exec_when, char *text)
-{
- switch (exec_when)
- {
- case EXEC_NOW:
- Cmd_ExecuteString (text);
- break;
- case EXEC_INSERT:
- Cbuf_InsertText (text);
- break;
- case EXEC_APPEND:
- Cbuf_AddText (text);
- break;
- default:
- Com_Error (ERR_FATAL, "Cbuf_ExecuteText: bad exec_when");
- }
-}
-
-/*
-============
-Cbuf_Execute
-============
-*/
-void Cbuf_Execute (void)
-{
- int i;
- char *text;
- char line[1024];
- int quotes;
-
- alias_count = 0; // don't allow infinite alias loops
-
- while (cmd_text.cursize)
- {
-// find a \n or ; line break
- text = (char *)cmd_text.data;
-
- quotes = 0;
- for (i=0 ; i< cmd_text.cursize ; i++)
- {
- if (text[i] == '"')
- quotes++;
- if ( !(quotes&1) && text[i] == ';')
- break; // don't break if inside a quoted string
- if (text[i] == '\n')
- break;
- }
-
-
- memcpy (line, text, i);
- line[i] = 0;
-
-// delete the text from the command buffer and move remaining commands down
-// this is necessary because commands (exec, alias) can insert data at the
-// beginning of the text buffer
-
- if (i == cmd_text.cursize)
- cmd_text.cursize = 0;
- else
- {
- i++;
- cmd_text.cursize -= i;
- memmove (text, text+i, cmd_text.cursize);
- }
-
-// execute the command line
- Cmd_ExecuteString (line);
-
- if (cmd_wait)
- {
- // skip out while text still remains in buffer, leaving it
- // for next frame
- cmd_wait = false;
- break;
- }
- }
-}
-
-
-/*
-===============
-Cbuf_AddEarlyCommands
-
-Adds command line parameters as script statements
-Commands lead with a +, and continue until another +
-
-Set commands are added early, so they are guaranteed to be set before
-the client and server initialize for the first time.
-
-Other commands are added late, after all initialization is complete.
-===============
-*/
-void Cbuf_AddEarlyCommands (qboolean clear)
-{
- int i;
- char *s;
-
- for (i=0 ; i<COM_Argc() ; i++)
- {
- s = COM_Argv(i);
- if (strcmp (s, "+set"))
- continue;
- Cbuf_AddText (va("set %s %s\n", COM_Argv(i+1), COM_Argv(i+2)));
- if (clear)
- {
- COM_ClearArgv(i);
- COM_ClearArgv(i+1);
- COM_ClearArgv(i+2);
- }
- i+=2;
- }
-}
-
-/*
-=================
-Cbuf_AddLateCommands
-
-Adds command line parameters as script statements
-Commands lead with a + and continue until another + or -
-quake +vid_ref gl +map amlev1
-
-Returns true if any late commands were added, which
-will keep the demoloop from immediately starting
-=================
-*/
-qboolean Cbuf_AddLateCommands (void)
-{
- int i, j;
- int s;
- char *text, *build, c;
- int argc;
- qboolean ret;
-
-// build the combined string to parse from
- s = 0;
- argc = COM_Argc();
- for (i=1 ; i<argc ; i++)
- {
- s += strlen (COM_Argv(i)) + 1;
- }
- if (!s)
- return false;
-
- text = Z_Malloc (s+1);
- text[0] = 0;
- for (i=1 ; i<argc ; i++)
- {
- strcat (text,COM_Argv(i));
- if (i != argc-1)
- strcat (text, " ");
- }
-
-// pull out the commands
- build = Z_Malloc (s+1);
- build[0] = 0;
-
- for (i=0 ; i<s-1 ; i++)
- {
- if (text[i] == '+')
- {
- i++;
-
- for (j=i ; (text[j] != '+') && (text[j] != '-') && (text[j] != 0) ; j++)
- ;
-
- c = text[j];
- text[j] = 0;
-
- strcat (build, text+i);
- strcat (build, "\n");
- text[j] = c;
- i = j-1;
- }
- }
-
- ret = (build[0] != 0);
- if (ret)
- Cbuf_AddText (build);
-
- Z_Free (text);
- Z_Free (build);
-
- return ret;
-}
-
-
-/*
-==============================================================================
-
- SCRIPT COMMANDS
-
-==============================================================================
-*/
-
-
-/*
-===============
-Cmd_Exec_f
-===============
-*/
-void Cmd_Exec_f (void)
-{
- char *f, *f2;
- int len;
-
- if (Cmd_Argc () != 2)
- {
- Com_Printf ("exec <filename> : execute a script file\n");
- return;
- }
-
- len = FS_LoadFile (Cmd_Argv(1), (void **)&f);
- if (!f)
- {
- Com_Printf ("couldn't exec %s\n",Cmd_Argv(1));
- return;
- }
- Com_Printf ("execing %s\n",Cmd_Argv(1));
-
- // the file doesn't have a trailing 0, so we need to copy it off
- f2 = Z_Malloc(len+1);
- memcpy (f2, f, len);
- f2[len] = 0;
-
- Cbuf_InsertText (f2);
-
- Z_Free (f2);
- FS_FreeFile (f);
-}
-
-
-/*
-===============
-Cmd_Echo_f
-
-Just prints the rest of the line to the console
-===============
-*/
-void Cmd_Echo_f (void)
-{
- int i;
-
- for (i=1 ; i<Cmd_Argc() ; i++)
- Com_Printf ("%s ",Cmd_Argv(i));
- Com_Printf ("\n");
-}
-
-/*
-===============
-Cmd_Alias_f
-
-Creates a new command that executes a command string (possibly ; seperated)
-===============
-*/
-void Cmd_Alias_f (void)
-{
- cmdalias_t *a;
- char cmd[1024];
- int i, c;
- char *s;
-
- if (Cmd_Argc() == 1)
- {
- Com_Printf ("Current alias commands:\n");
- for (a = cmd_alias ; a ; a=a->next)
- Com_Printf ("%s : %s\n", a->name, a->value);
- return;
- }
-
- s = Cmd_Argv(1);
- if (strlen(s) >= MAX_ALIAS_NAME)
- {
- Com_Printf ("Alias name is too long\n");
- return;
- }
-
- // if the alias already exists, reuse it
- for (a = cmd_alias ; a ; a=a->next)
- {
- if (!strcmp(s, a->name))
- {
- Z_Free (a->value);
- break;
- }
- }
-
- if (!a)
- {
- a = Z_Malloc (sizeof(cmdalias_t));
- a->next = cmd_alias;
- cmd_alias = a;
- }
- strcpy (a->name, s);
-
-// copy the rest of the command line
- cmd[0] = 0; // start out with a null string
- c = Cmd_Argc();
- for (i=2 ; i< c ; i++)
- {
- strcat (cmd, Cmd_Argv(i));
- if (i != (c - 1))
- strcat (cmd, " ");
- }
- strcat (cmd, "\n");
-
- a->value = CopyString (cmd);
-}
-
-/*
-=============================================================================
-
- COMMAND EXECUTION
-
-=============================================================================
-*/
-
-typedef struct cmd_function_s
-{
- struct cmd_function_s *next;
- char *name;
- xcommand_t function;
-} cmd_function_t;
-
-
-static int cmd_argc;
-static char *cmd_argv[MAX_STRING_TOKENS];
-static char *cmd_null_string = "";
-static char cmd_args[MAX_STRING_CHARS];
-
-static cmd_function_t *cmd_functions; // possible commands to execute
-
-/*
-============
-Cmd_Argc
-============
-*/
-int Cmd_Argc (void)
-{
- return cmd_argc;
-}
-
-/*
-============
-Cmd_Argv
-============
-*/
-char *Cmd_Argv (int arg)
-{
- if ( (unsigned)arg >= cmd_argc )
- return cmd_null_string;
- return cmd_argv[arg];
-}
-
-/*
-============
-Cmd_Args
-
-Returns a single string containing argv(1) to argv(argc()-1)
-============
-*/
-char *Cmd_Args (void)
-{
- return cmd_args;
-}
-
-
-/*
-======================
-Cmd_MacroExpandString
-======================
-*/
-char *Cmd_MacroExpandString (char *text)
-{
- int i, j, count, len;
- qboolean inquote;
- char *scan;
- static char expanded[MAX_STRING_CHARS];
- char temporary[MAX_STRING_CHARS];
- char *token, *start;
-
- inquote = false;
- scan = text;
-
- len = strlen (scan);
- if (len >= MAX_STRING_CHARS)
- {
- Com_Printf ("Line exceeded %i chars, discarded.\n", MAX_STRING_CHARS);
- return NULL;
- }
-
- count = 0;
-
- for (i=0 ; i<len ; i++)
- {
- if (scan[i] == '"')
- inquote ^= 1;
- if (inquote)
- continue; // don't expand inside quotes
- if (scan[i] != '$')
- continue;
- // scan out the complete macro
- start = scan+i+1;
- token = COM_Parse (&start);
- if (!start)
- continue;
-
- token = Cvar_VariableString (token);
-
- j = strlen(token);
- len += j;
- if (len >= MAX_STRING_CHARS)
- {
- Com_Printf ("Expanded line exceeded %i chars, discarded.\n", MAX_STRING_CHARS);
- return NULL;
- }
-
- strncpy (temporary, scan, i);
- strcpy (temporary+i, token);
- strcpy (temporary+i+j, start);
-
- strcpy (expanded, temporary);
- scan = expanded;
- i--;
-
- if (++count == 100)
- {
- Com_Printf ("Macro expansion loop, discarded.\n");
- return NULL;
- }
- }
-
- if (inquote)
- {
- Com_Printf ("Line has unmatched quote, discarded.\n");
- return NULL;
- }
-
- return scan;
-}
-
-
-/*
-============
-Cmd_TokenizeString
-
-Parses the given string into command line tokens.
-$Cvars will be expanded unless they are in a quoted token
-============
-*/
-void Cmd_TokenizeString (char *text, qboolean macroExpand)
-{
- int i;
- char *com_token;
-
-// clear the args from the last string
- for (i=0 ; i<cmd_argc ; i++)
- Z_Free (cmd_argv[i]);
-
- cmd_argc = 0;
- cmd_args[0] = 0;
-
- // macro expand the text
- if (macroExpand)
- text = Cmd_MacroExpandString (text);
- if (!text)
- return;
-
- while (1)
- {
-// skip whitespace up to a /n
- while (*text && *text <= ' ' && *text != '\n')
- {
- text++;
- }
-
- if (*text == '\n')
- { // a newline seperates commands in the buffer
- text++;
- break;
- }
-
- if (!*text)
- return;
-
- // set cmd_args to everything after the first arg
- if (cmd_argc == 1)
- {
- int l;
-
- strcpy (cmd_args, text);
-
- // strip off any trailing whitespace
- l = strlen(cmd_args) - 1;
- for ( ; l >= 0 ; l--)
- if (cmd_args[l] <= ' ')
- cmd_args[l] = 0;
- else
- break;
- }
-
- com_token = COM_Parse (&text);
- if (!text)
- return;
-
- if (cmd_argc < MAX_STRING_TOKENS)
- {
- cmd_argv[cmd_argc] = Z_Malloc (strlen(com_token)+1);
- strcpy (cmd_argv[cmd_argc], com_token);
- cmd_argc++;
- }
- }
-
-}
-
-
-/*
-============
-Cmd_AddCommand
-============
-*/
-void Cmd_AddCommand (char *cmd_name, xcommand_t function)
-{
- cmd_function_t *cmd;
-
-// fail if the command is a variable name
- if (Cvar_VariableString(cmd_name)[0])
- {
- Com_Printf ("Cmd_AddCommand: %s already defined as a var\n", cmd_name);
- return;
- }
-
-// fail if the command already exists
- for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
- {
- if (!strcmp (cmd_name, cmd->name))
- {
- Com_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name);
- return;
- }
- }
-
- cmd = Z_Malloc (sizeof(cmd_function_t));
- cmd->name = cmd_name;
- cmd->function = function;
- cmd->next = cmd_functions;
- cmd_functions = cmd;
-}
-
-/*
-============
-Cmd_RemoveCommand
-============
-*/
-void Cmd_RemoveCommand (char *cmd_name)
-{
- cmd_function_t *cmd, **back;
-
- back = &cmd_functions;
- while (1)
- {
- cmd = *back;
- if (!cmd)
- {
- Com_Printf ("Cmd_RemoveCommand: %s not added\n", cmd_name);
- return;
- }
- if (!strcmp (cmd_name, cmd->name))
- {
- *back = cmd->next;
- Z_Free (cmd);
- return;
- }
- back = &cmd->next;
- }
-}
-
-/*
-============
-Cmd_Exists
-============
-*/
-qboolean Cmd_Exists (char *cmd_name)
-{
- cmd_function_t *cmd;
-
- for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
- {
- if (!strcmp (cmd_name,cmd->name))
- return true;
- }
-
- return false;
-}
-
-
-
-/*
-============
-Cmd_CompleteCommand
-============
-*/
-char *Cmd_CompleteCommand (char *partial)
-{
- cmd_function_t *cmd;
- int len;
- cmdalias_t *a;
-
- len = strlen(partial);
-
- if (!len)
- return NULL;
-
-// check for exact match
- for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
- if (!strcmp (partial,cmd->name))
- return cmd->name;
- for (a=cmd_alias ; a ; a=a->next)
- if (!strcmp (partial, a->name))
- return a->name;
-
-// check for partial match
- for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
- if (!strncmp (partial,cmd->name, len))
- return cmd->name;
- for (a=cmd_alias ; a ; a=a->next)
- if (!strncmp (partial, a->name, len))
- return a->name;
-
- return NULL;
-}
-
-
-/*
-============
-Cmd_ExecuteString
-
-A complete command line has been parsed, so try to execute it
-FIXME: lookupnoadd the token to speed search?
-============
-*/
-void Cmd_ExecuteString (char *text)
-{
- cmd_function_t *cmd;
- cmdalias_t *a;
-
- Cmd_TokenizeString (text, true);
-
- // execute the command line
- if (!Cmd_Argc())
- return; // no tokens
-
- // check functions
- for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
- {
- if (!cistrcmp (cmd_argv[0],cmd->name))
- {
- if (!cmd->function)
- { // forward to server command
- Cmd_ExecuteString (va("cmd %s", text));
- }
- else
- cmd->function ();
- return;
- }
- }
-
- // check alias
- for (a=cmd_alias ; a ; a=a->next)
- {
- if (!cistrcmp (cmd_argv[0], a->name))
- {
- if (++alias_count == ALIAS_LOOP_COUNT)
- {
- Com_Printf ("ALIAS_LOOP_COUNT\n");
- return;
- }
- Cbuf_InsertText (a->value);
- return;
- }
- }
-
- // check cvars
- if (Cvar_Command ())
- return;
-
- // send it as a server command if we are connected
- Cmd_ForwardToServer ();
-}
-
-/*
-============
-Cmd_List_f
-============
-*/
-void Cmd_List_f (void)
-{
- cmd_function_t *cmd;
- int i;
-
- i = 0;
- for (cmd=cmd_functions ; cmd ; cmd=cmd->next, i++)
- Com_Printf ("%s\n", cmd->name);
- Com_Printf ("%i commands\n", i);
-}
-
-/*
-============
-Cmd_Init
-============
-*/
-void Cmd_Init (void)
-{
-//
-// register our commands
-//
- Cmd_AddCommand ("cmdlist",Cmd_List_f);
- Cmd_AddCommand ("exec",Cmd_Exec_f);
- Cmd_AddCommand ("echo",Cmd_Echo_f);
- Cmd_AddCommand ("alias",Cmd_Alias_f);
- Cmd_AddCommand ("wait", Cmd_Wait_f);
-}
-
--- a/qcommon/cmodel.c
+++ /dev/null
@@ -1,1745 +1,0 @@
-// cmodel.c -- model loading
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-typedef struct
-{
- cplane_t *plane;
- int children[2]; // negative numbers are leafs
-} cnode_t;
-
-typedef struct
-{
- cplane_t *plane;
- mapsurface_t *surface;
-} cbrushside_t;
-
-typedef struct
-{
- int contents;
- int cluster;
- int area;
- unsigned short firstleafbrush;
- unsigned short numleafbrushes;
-} cleaf_t;
-
-typedef struct
-{
- int contents;
- int numsides;
- int firstbrushside;
- int checkcount; // to avoid repeated testings
-} cbrush_t;
-
-typedef struct
-{
- int numareaportals;
- int firstareaportal;
- int floodnum; // if two areas have equal floodnums, they are connected
- int floodvalid;
-} carea_t;
-
-int checkcount;
-
-char map_name[MAX_QPATH];
-
-int numbrushsides;
-cbrushside_t map_brushsides[MAX_MAP_BRUSHSIDES];
-
-int numtexinfo;
-mapsurface_t map_surfaces[MAX_MAP_TEXINFO];
-
-int numplanes;
-cplane_t map_planes[MAX_MAP_PLANES+6]; // extra for box hull
-
-int numnodes;
-cnode_t map_nodes[MAX_MAP_NODES+6]; // extra for box hull
-
-int numleafs = 1; // allow leaf funcs to be called without a map
-cleaf_t map_leafs[MAX_MAP_LEAFS];
-int emptyleaf, solidleaf;
-
-int numleafbrushes;
-unsigned short map_leafbrushes[MAX_MAP_LEAFBRUSHES];
-
-int numcmodels;
-cmodel_t map_cmodels[MAX_MAP_MODELS];
-
-int numbrushes;
-cbrush_t map_brushes[MAX_MAP_BRUSHES];
-
-int numvisibility;
-byte map_visibility[MAX_MAP_VISIBILITY];
-dvis_t *map_vis = (dvis_t *)map_visibility;
-
-int numentitychars;
-char map_entitystring[MAX_MAP_ENTSTRING];
-
-int numareas = 1;
-carea_t map_areas[MAX_MAP_AREAS];
-
-int numareaportals;
-dareaportal_t map_areaportals[MAX_MAP_AREAPORTALS];
-
-int numclusters = 1;
-
-mapsurface_t nullsurface;
-
-int floodvalid;
-
-qboolean portalopen[MAX_MAP_AREAPORTALS];
-
-
-cvar_t *map_noareas;
-
-void CM_InitBoxHull (void);
-void FloodAreaConnections (void);
-
-
-int c_pointcontents;
-int c_traces, c_brush_traces;
-
-
-/*
-===============================================================================
-
- MAP LOADING
-
-===============================================================================
-*/
-
-byte *cmod_base;
-
-/*
-=================
-CMod_LoadSubmodels
-=================
-*/
-void CMod_LoadSubmodels (lump_t *l)
-{
- dmodel_t *in;
- cmodel_t *out;
- int i, j, count;
-
- in = (void *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l->filelen / sizeof(*in);
-
- if (count < 1)
- Com_Error (ERR_DROP, "Map with no models");
- if (count > MAX_MAP_MODELS)
- Com_Error (ERR_DROP, "Map has too many models");
-
- numcmodels = count;
-
- for ( i=0 ; i<count ; i++, in++)
- {
- out = &map_cmodels[i];
-
- for (j=0 ; j<3 ; j++)
- { // spread the mins / maxs by a pixel
- out->mins[j] = LittleFloat (in->mins[j]) - 1;
- out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
- out->origin[j] = LittleFloat (in->origin[j]);
- }
- out->headnode = LittleLong (in->headnode);
- }
-}
-
-
-/*
-=================
-CMod_LoadSurfaces
-=================
-*/
-void CMod_LoadSurfaces (lump_t *l)
-{
- texinfo_t *in;
- mapsurface_t *out;
- int i, count;
-
- in = (void *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l->filelen / sizeof(*in);
- if (count < 1)
- Com_Error (ERR_DROP, "Map with no surfaces");
- if (count > MAX_MAP_TEXINFO)
- Com_Error (ERR_DROP, "Map has too many surfaces");
-
- numtexinfo = count;
- out = map_surfaces;
-
- for ( i=0 ; i<count ; i++, in++, out++)
- {
- strncpy (out->c.name, in->texture, sizeof(out->c.name)-1);
- strncpy (out->rname, in->texture, sizeof(out->rname)-1);
- out->c.flags = LittleLong (in->flags);
- out->c.value = LittleLong (in->value);
- }
-}
-
-
-/*
-=================
-CMod_LoadNodes
-
-=================
-*/
-void CMod_LoadNodes (lump_t *l)
-{
- dnode_t *in;
- int child;
- cnode_t *out;
- int i, j, count;
-
- in = (void *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l->filelen / sizeof(*in);
-
- if (count < 1)
- Com_Error (ERR_DROP, "Map has no nodes");
- if (count > MAX_MAP_NODES)
- Com_Error (ERR_DROP, "Map has too many nodes");
-
- out = map_nodes;
-
- numnodes = count;
-
- for (i=0 ; i<count ; i++, out++, in++)
- {
- out->plane = map_planes + LittleLong(in->planenum);
- for (j=0 ; j<2 ; j++)
- {
- child = LittleLong (in->children[j]);
- out->children[j] = child;
- }
- }
-
-}
-
-/*
-=================
-CMod_LoadBrushes
-
-=================
-*/
-void CMod_LoadBrushes (lump_t *l)
-{
- dbrush_t *in;
- cbrush_t *out;
- int i, count;
-
- in = (void *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l->filelen / sizeof(*in);
-
- if (count > MAX_MAP_BRUSHES)
- Com_Error (ERR_DROP, "Map has too many brushes");
-
- out = map_brushes;
-
- numbrushes = count;
-
- for (i=0 ; i<count ; i++, out++, in++)
- {
- out->firstbrushside = LittleLong(in->firstside);
- out->numsides = LittleLong(in->numsides);
- out->contents = LittleLong(in->contents);
- }
-
-}
-
-/*
-=================
-CMod_LoadLeafs
-=================
-*/
-void CMod_LoadLeafs (lump_t *l)
-{
- int i;
- cleaf_t *out;
- dleaf_t *in;
- int count;
-
- in = (void *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l->filelen / sizeof(*in);
-
- if (count < 1)
- Com_Error (ERR_DROP, "Map with no leafs");
- // need to save space for box planes
- if (count > MAX_MAP_PLANES)
- Com_Error (ERR_DROP, "Map has too many planes");
-
- out = map_leafs;
- numleafs = count;
- numclusters = 0;
-
- for ( i=0 ; i<count ; i++, in++, out++)
- {
- out->contents = LittleLong (in->contents);
- out->cluster = LittleShort (in->cluster);
- out->area = LittleShort (in->area);
- out->firstleafbrush = LittleShort (in->firstleafbrush);
- out->numleafbrushes = LittleShort (in->numleafbrushes);
-
- if (out->cluster >= numclusters)
- numclusters = out->cluster + 1;
- }
-
- if (map_leafs[0].contents != CONTENTS_SOLID)
- Com_Error (ERR_DROP, "Map leaf 0 is not CONTENTS_SOLID");
- solidleaf = 0;
- emptyleaf = -1;
- for (i=1 ; i<numleafs ; i++)
- {
- if (!map_leafs[i].contents)
- {
- emptyleaf = i;
- break;
- }
- }
- if (emptyleaf == -1)
- Com_Error (ERR_DROP, "Map does not have an empty leaf");
-}
-
-/*
-=================
-CMod_LoadPlanes
-=================
-*/
-void CMod_LoadPlanes (lump_t *l)
-{
- int i, j;
- cplane_t *out;
- dplane_t *in;
- int count;
- int bits;
-
- in = (void *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l->filelen / sizeof(*in);
-
- if (count < 1)
- Com_Error (ERR_DROP, "Map with no planes");
- // need to save space for box planes
- if (count > MAX_MAP_PLANES)
- Com_Error (ERR_DROP, "Map has too many planes");
-
- out = map_planes;
- numplanes = count;
-
- for ( i=0 ; i<count ; i++, in++, out++)
- {
- bits = 0;
- for (j=0 ; j<3 ; j++)
- {
- out->normal[j] = LittleFloat (in->normal[j]);
- if (out->normal[j] < 0)
- bits |= 1<<j;
- }
-
- out->dist = LittleFloat (in->dist);
- out->type = LittleLong (in->type);
- out->signbits = bits;
- }
-}
-
-/*
-=================
-CMod_LoadLeafBrushes
-=================
-*/
-void CMod_LoadLeafBrushes (lump_t *l)
-{
- int i;
- unsigned short *out;
- unsigned short *in;
- int count;
-
- in = (void *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l->filelen / sizeof(*in);
-
- if (count < 1)
- Com_Error (ERR_DROP, "Map with no planes");
- // need to save space for box planes
- if (count > MAX_MAP_LEAFBRUSHES)
- Com_Error (ERR_DROP, "Map has too many leafbrushes");
-
- out = map_leafbrushes;
- numleafbrushes = count;
-
- for ( i=0 ; i<count ; i++, in++, out++)
- *out = LittleShort (*in);
-}
-
-/*
-=================
-CMod_LoadBrushSides
-=================
-*/
-void CMod_LoadBrushSides (lump_t *l)
-{
- int i, j;
- cbrushside_t *out;
- dbrushside_t *in;
- int count;
- int num;
-
- in = (void *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l->filelen / sizeof(*in);
-
- // need to save space for box planes
- if (count > MAX_MAP_BRUSHSIDES)
- Com_Error (ERR_DROP, "Map has too many planes");
-
- out = map_brushsides;
- numbrushsides = count;
-
- for ( i=0 ; i<count ; i++, in++, out++)
- {
- num = LittleShort (in->planenum);
- out->plane = &map_planes[num];
- j = LittleShort (in->texinfo);
- if (j >= numtexinfo)
- Com_Error (ERR_DROP, "Bad brushside texinfo");
- out->surface = &map_surfaces[j];
- }
-}
-
-/*
-=================
-CMod_LoadAreas
-=================
-*/
-void CMod_LoadAreas (lump_t *l)
-{
- int i;
- carea_t *out;
- darea_t *in;
- int count;
-
- in = (void *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l->filelen / sizeof(*in);
-
- if (count > MAX_MAP_AREAS)
- Com_Error (ERR_DROP, "Map has too many areas");
-
- out = map_areas;
- numareas = count;
-
- for ( i=0 ; i<count ; i++, in++, out++)
- {
- out->numareaportals = LittleLong (in->numareaportals);
- out->firstareaportal = LittleLong (in->firstareaportal);
- out->floodvalid = 0;
- out->floodnum = 0;
- }
-}
-
-/*
-=================
-CMod_LoadAreaPortals
-=================
-*/
-void CMod_LoadAreaPortals (lump_t *l)
-{
- int i;
- dareaportal_t *out;
- dareaportal_t *in;
- int count;
-
- in = (void *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l->filelen / sizeof(*in);
-
- if (count > MAX_MAP_AREAS)
- Com_Error (ERR_DROP, "Map has too many areas");
-
- out = map_areaportals;
- numareaportals = count;
-
- for ( i=0 ; i<count ; i++, in++, out++)
- {
- out->portalnum = LittleLong (in->portalnum);
- out->otherarea = LittleLong (in->otherarea);
- }
-}
-
-/*
-=================
-CMod_LoadVisibility
-=================
-*/
-void CMod_LoadVisibility (lump_t *l)
-{
- int i;
-
- numvisibility = l->filelen;
- if (l->filelen > MAX_MAP_VISIBILITY)
- Com_Error (ERR_DROP, "Map has too large visibility lump");
-
- memcpy (map_visibility, cmod_base + l->fileofs, l->filelen);
-
- map_vis->numclusters = LittleLong (map_vis->numclusters);
- for (i=0 ; i<map_vis->numclusters ; i++)
- {
- map_vis->bitofs[i][0] = LittleLong (map_vis->bitofs[i][0]);
- map_vis->bitofs[i][1] = LittleLong (map_vis->bitofs[i][1]);
- }
-}
-
-
-/*
-=================
-CMod_LoadEntityString
-=================
-*/
-void CMod_LoadEntityString (lump_t *l)
-{
- numentitychars = l->filelen;
- if (l->filelen > MAX_MAP_ENTSTRING)
- Com_Error (ERR_DROP, "Map has too large entity lump");
-
- memcpy (map_entitystring, cmod_base + l->fileofs, l->filelen);
-}
-
-
-
-/*
-==================
-CM_LoadMap
-
-Loads in the map and all submodels
-==================
-*/
-cmodel_t *CM_LoadMap (char *name, qboolean clientload, unsigned *checksum)
-{
- unsigned *buf;
- int i;
- dheader_t header;
- int length;
- static unsigned last_checksum;
-
- map_noareas = Cvar_Get ("map_noareas", "0", 0);
-
- if ( !strcmp (map_name, name) && (clientload || !Cvar_VariableValue ("flushmap")) )
- {
- *checksum = last_checksum;
- if (!clientload)
- {
- memset (portalopen, 0, sizeof(portalopen));
- FloodAreaConnections ();
- }
- return &map_cmodels[0]; // still have the right version
- }
-
- // free old stuff
- numplanes = 0;
- numnodes = 0;
- numleafs = 0;
- numcmodels = 0;
- numvisibility = 0;
- numentitychars = 0;
- map_entitystring[0] = 0;
- map_name[0] = 0;
-
- if (!name || !name[0])
- {
- numleafs = 1;
- numclusters = 1;
- numareas = 1;
- *checksum = 0;
- return &map_cmodels[0]; // cinematic servers won't have anything at all
- }
-
- //
- // load the file
- //
- length = FS_LoadFile (name, (void **)&buf);
- if (!buf)
- Com_Error (ERR_DROP, "Couldn't load %s", name);
-
- last_checksum = LittleLong (Com_BlockChecksum (buf, length));
- *checksum = last_checksum;
-
- header = *(dheader_t *)buf;
- for (i=0 ; i<sizeof(dheader_t)/sizeof(int) ; i++)
- ((int *)&header)[i] = LittleLong ( ((int *)&header)[i]);
-
- if (header.version != BSPVERSION)
- Com_Error (ERR_DROP, "CMod_LoadBrushModel: %s has wrong version number (%i should be %i)"
- , name, header.version, BSPVERSION);
-
- cmod_base = (byte *)buf;
-
- // load into heap
- CMod_LoadSurfaces (&header.lumps[LUMP_TEXINFO]);
- CMod_LoadLeafs (&header.lumps[LUMP_LEAFS]);
- CMod_LoadLeafBrushes (&header.lumps[LUMP_LEAFBRUSHES]);
- CMod_LoadPlanes (&header.lumps[LUMP_PLANES]);
- CMod_LoadBrushes (&header.lumps[LUMP_BRUSHES]);
- CMod_LoadBrushSides (&header.lumps[LUMP_BRUSHSIDES]);
- CMod_LoadSubmodels (&header.lumps[LUMP_MODELS]);
- CMod_LoadNodes (&header.lumps[LUMP_NODES]);
- CMod_LoadAreas (&header.lumps[LUMP_AREAS]);
- CMod_LoadAreaPortals (&header.lumps[LUMP_AREAPORTALS]);
- CMod_LoadVisibility (&header.lumps[LUMP_VISIBILITY]);
- CMod_LoadEntityString (&header.lumps[LUMP_ENTITIES]);
-
- FS_FreeFile (buf);
-
- CM_InitBoxHull ();
-
- memset (portalopen, 0, sizeof(portalopen));
- FloodAreaConnections ();
-
- strcpy (map_name, name);
-
- return &map_cmodels[0];
-}
-
-/*
-==================
-CM_InlineModel
-==================
-*/
-cmodel_t *CM_InlineModel (char *name)
-{
- int num;
-
- if (!name || name[0] != '*')
- Com_Error (ERR_DROP, "CM_InlineModel: bad name");
- num = atoi (name+1);
- if (num < 1 || num >= numcmodels)
- Com_Error (ERR_DROP, "CM_InlineModel: bad number");
-
- return &map_cmodels[num];
-}
-
-int CM_NumClusters (void)
-{
- return numclusters;
-}
-
-int CM_NumInlineModels (void)
-{
- return numcmodels;
-}
-
-char *CM_EntityString (void)
-{
- return map_entitystring;
-}
-
-int CM_LeafContents (int leafnum)
-{
- if (leafnum < 0 || leafnum >= numleafs)
- Com_Error (ERR_DROP, "CM_LeafContents: bad number");
- return map_leafs[leafnum].contents;
-}
-
-int CM_LeafCluster (int leafnum)
-{
- if (leafnum < 0 || leafnum >= numleafs)
- Com_Error (ERR_DROP, "CM_LeafCluster: bad number");
- return map_leafs[leafnum].cluster;
-}
-
-int CM_LeafArea (int leafnum)
-{
- if (leafnum < 0 || leafnum >= numleafs)
- Com_Error (ERR_DROP, "CM_LeafArea: bad number");
- return map_leafs[leafnum].area;
-}
-
-//=======================================================================
-
-
-cplane_t *box_planes;
-int box_headnode;
-cbrush_t *box_brush;
-cleaf_t *box_leaf;
-
-/*
-===================
-CM_InitBoxHull
-
-Set up the planes and nodes so that the six floats of a bounding box
-can just be stored out and get a proper clipping hull structure.
-===================
-*/
-void CM_InitBoxHull (void)
-{
- int i;
- int side;
- cnode_t *c;
- cplane_t *p;
- cbrushside_t *s;
-
- box_headnode = numnodes;
- box_planes = &map_planes[numplanes];
- if (numnodes+6 > MAX_MAP_NODES
- || numbrushes+1 > MAX_MAP_BRUSHES
- || numleafbrushes+1 > MAX_MAP_LEAFBRUSHES
- || numbrushsides+6 > MAX_MAP_BRUSHSIDES
- || numplanes+12 > MAX_MAP_PLANES)
- Com_Error (ERR_DROP, "Not enough room for box tree");
-
- box_brush = &map_brushes[numbrushes];
- box_brush->numsides = 6;
- box_brush->firstbrushside = numbrushsides;
- box_brush->contents = CONTENTS_MONSTER;
-
- box_leaf = &map_leafs[numleafs];
- box_leaf->contents = CONTENTS_MONSTER;
- box_leaf->firstleafbrush = numleafbrushes;
- box_leaf->numleafbrushes = 1;
-
- map_leafbrushes[numleafbrushes] = numbrushes;
-
- for (i=0 ; i<6 ; i++)
- {
- side = i&1;
-
- // brush sides
- s = &map_brushsides[numbrushsides+i];
- s->plane = map_planes + (numplanes+i*2+side);
- s->surface = &nullsurface;
-
- // nodes
- c = &map_nodes[box_headnode+i];
- c->plane = map_planes + (numplanes+i*2);
- c->children[side] = -1 - emptyleaf;
- if (i != 5)
- c->children[side^1] = box_headnode+i + 1;
- else
- c->children[side^1] = -1 - numleafs;
-
- // planes
- p = &box_planes[i*2];
- p->type = i>>1;
- p->signbits = 0;
- VectorClear (p->normal);
- p->normal[i>>1] = 1;
-
- p = &box_planes[i*2+1];
- p->type = 3 + (i>>1);
- p->signbits = 0;
- VectorClear (p->normal);
- p->normal[i>>1] = -1;
- }
-}
-
-
-/*
-===================
-CM_HeadnodeForBox
-
-To keep everything totally uniform, bounding boxes are turned into small
-BSP trees instead of being compared directly.
-===================
-*/
-int CM_HeadnodeForBox (vec3_t mins, vec3_t maxs)
-{
- box_planes[0].dist = maxs[0];
- box_planes[1].dist = -maxs[0];
- box_planes[2].dist = mins[0];
- box_planes[3].dist = -mins[0];
- box_planes[4].dist = maxs[1];
- box_planes[5].dist = -maxs[1];
- box_planes[6].dist = mins[1];
- box_planes[7].dist = -mins[1];
- box_planes[8].dist = maxs[2];
- box_planes[9].dist = -maxs[2];
- box_planes[10].dist = mins[2];
- box_planes[11].dist = -mins[2];
-
- return box_headnode;
-}
-
-
-/*
-==================
-CM_PointLeafnum_r
-
-==================
-*/
-int CM_PointLeafnum_r (vec3_t p, int num)
-{
- float d;
- cnode_t *node;
- cplane_t *plane;
-
- while (num >= 0)
- {
- node = map_nodes + num;
- plane = node->plane;
-
- if (plane->type < 3)
- d = p[plane->type] - plane->dist;
- else
- d = DotProduct (plane->normal, p) - plane->dist;
- if (d < 0)
- num = node->children[1];
- else
- num = node->children[0];
- }
-
- c_pointcontents++; // optimize counter
-
- return -1 - num;
-}
-
-int CM_PointLeafnum (vec3_t p)
-{
- if (!numplanes)
- return 0; // sound may call this without map loaded
- return CM_PointLeafnum_r (p, 0);
-}
-
-
-
-/*
-=============
-CM_BoxLeafnums
-
-Fills in a list of all the leafs touched
-=============
-*/
-int leaf_count, leaf_maxcount;
-int *leaf_list;
-float *leaf_mins, *leaf_maxs;
-int leaf_topnode;
-
-void CM_BoxLeafnums_r (int nodenum)
-{
- cplane_t *plane;
- cnode_t *node;
- int s;
-
- while (1)
- {
- if (nodenum < 0)
- {
- if (leaf_count >= leaf_maxcount)
- {
-// Com_Printf ("CM_BoxLeafnums_r: overflow\n");
- return;
- }
- leaf_list[leaf_count++] = -1 - nodenum;
- return;
- }
-
- node = &map_nodes[nodenum];
- plane = node->plane;
-// s = BoxOnPlaneSide (leaf_mins, leaf_maxs, plane);
- s = BOX_ON_PLANE_SIDE(leaf_mins, leaf_maxs, plane);
- if (s == 1)
- nodenum = node->children[0];
- else if (s == 2)
- nodenum = node->children[1];
- else
- { // go down both
- if (leaf_topnode == -1)
- leaf_topnode = nodenum;
- CM_BoxLeafnums_r (node->children[0]);
- nodenum = node->children[1];
- }
-
- }
-}
-
-int CM_BoxLeafnums_headnode (vec3_t mins, vec3_t maxs, int *list, int listsize, int headnode, int *topnode)
-{
- leaf_list = list;
- leaf_count = 0;
- leaf_maxcount = listsize;
- leaf_mins = mins;
- leaf_maxs = maxs;
-
- leaf_topnode = -1;
-
- CM_BoxLeafnums_r (headnode);
-
- if (topnode)
- *topnode = leaf_topnode;
-
- return leaf_count;
-}
-
-int CM_BoxLeafnums (vec3_t mins, vec3_t maxs, int *list, int listsize, int *topnode)
-{
- return CM_BoxLeafnums_headnode (mins, maxs, list,
- listsize, map_cmodels[0].headnode, topnode);
-}
-
-
-
-/*
-==================
-CM_PointContents
-
-==================
-*/
-int CM_PointContents (vec3_t p, int headnode)
-{
- int l;
-
- if (!numnodes) // map not loaded
- return 0;
-
- l = CM_PointLeafnum_r (p, headnode);
-
- return map_leafs[l].contents;
-}
-
-/*
-==================
-CM_TransformedPointContents
-
-Handles offseting and rotation of the end points for moving and
-rotating entities
-==================
-*/
-int CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t angles)
-{
- vec3_t p_l;
- vec3_t temp;
- vec3_t forward, right, up;
- int l;
-
- // subtract origin offset
- VectorSubtract (p, origin, p_l);
-
- // rotate start and end into the models frame of reference
- if (headnode != box_headnode &&
- (angles[0] || angles[1] || angles[2]) )
- {
- AngleVectors (angles, forward, right, up);
-
- VectorCopy (p_l, temp);
- p_l[0] = DotProduct (temp, forward);
- p_l[1] = -DotProduct (temp, right);
- p_l[2] = DotProduct (temp, up);
- }
-
- l = CM_PointLeafnum_r (p_l, headnode);
-
- return map_leafs[l].contents;
-}
-
-
-/*
-===============================================================================
-
-BOX TRACING
-
-===============================================================================
-*/
-
-// 1/32 epsilon to keep floating point happy
-#define DIST_EPSILON (0.03125)
-
-vec3_t trace_start, trace_end;
-vec3_t trace_mins, trace_maxs;
-vec3_t trace_extents;
-
-trace_t trace_trace;
-int trace_contents;
-qboolean trace_ispoint; // optimized case
-
-/*
-================
-CM_ClipBoxToBrush
-================
-*/
-void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2,
- trace_t *trace, cbrush_t *brush)
-{
- int i, j;
- cplane_t *plane, *clipplane;
- float dist;
- float enterfrac, leavefrac;
- vec3_t ofs;
- float d1, d2;
- qboolean getout, startout;
- float f;
- cbrushside_t *side, *leadside;
-
- enterfrac = -1;
- leavefrac = 1;
- clipplane = NULL;
-
- if (!brush->numsides)
- return;
-
- c_brush_traces++;
-
- getout = false;
- startout = false;
- leadside = NULL;
-
- for (i=0 ; i<brush->numsides ; i++)
- {
- side = &map_brushsides[brush->firstbrushside+i];
- plane = side->plane;
-
- // FIXME: special case for axial
-
- if (!trace_ispoint)
- { // general box case
-
- // push the plane out apropriately for mins/maxs
-
- // FIXME: use signbits into 8 way lookup for each mins/maxs
- for (j=0 ; j<3 ; j++)
- {
- if (plane->normal[j] < 0)
- ofs[j] = maxs[j];
- else
- ofs[j] = mins[j];
- }
- dist = DotProduct (ofs, plane->normal);
- dist = plane->dist - dist;
- }
- else
- { // special point case
- dist = plane->dist;
- }
-
- d1 = DotProduct (p1, plane->normal) - dist;
- d2 = DotProduct (p2, plane->normal) - dist;
-
- if (d2 > 0)
- getout = true; // endpoint is not in solid
- if (d1 > 0)
- startout = true;
-
- // if completely in front of face, no intersection
- if (d1 > 0 && d2 >= d1)
- return;
-
- if (d1 <= 0 && d2 <= 0)
- continue;
-
- // crosses face
- if (d1 > d2)
- { // enter
- f = (d1-DIST_EPSILON) / (d1-d2);
- if (f > enterfrac)
- {
- enterfrac = f;
- clipplane = plane;
- leadside = side;
- }
- }
- else
- { // leave
- f = (d1+DIST_EPSILON) / (d1-d2);
- if (f < leavefrac)
- leavefrac = f;
- }
- }
-
- if (!startout)
- { // original point was inside brush
- trace->startsolid = true;
- if (!getout)
- trace->allsolid = true;
- return;
- }
- if (enterfrac < leavefrac)
- {
- if (enterfrac > -1 && enterfrac < trace->fraction)
- {
- if (enterfrac < 0)
- enterfrac = 0;
- trace->fraction = enterfrac;
- trace->plane = *clipplane;
- trace->surface = &(leadside->surface->c);
- trace->contents = brush->contents;
- }
- }
-}
-
-/*
-================
-CM_TestBoxInBrush
-================
-*/
-void CM_TestBoxInBrush (vec3_t mins, vec3_t maxs, vec3_t p1,
- trace_t *trace, cbrush_t *brush)
-{
- int i, j;
- cplane_t *plane;
- float dist;
- vec3_t ofs;
- float d1;
- cbrushside_t *side;
-
- if (!brush->numsides)
- return;
-
- for (i=0 ; i<brush->numsides ; i++)
- {
- side = &map_brushsides[brush->firstbrushside+i];
- plane = side->plane;
-
- // FIXME: special case for axial
-
- // general box case
-
- // push the plane out apropriately for mins/maxs
-
- // FIXME: use signbits into 8 way lookup for each mins/maxs
- for (j=0 ; j<3 ; j++)
- {
- if (plane->normal[j] < 0)
- ofs[j] = maxs[j];
- else
- ofs[j] = mins[j];
- }
- dist = DotProduct (ofs, plane->normal);
- dist = plane->dist - dist;
-
- d1 = DotProduct (p1, plane->normal) - dist;
-
- // if completely in front of face, no intersection
- if (d1 > 0)
- return;
-
- }
-
- // inside this brush
- trace->startsolid = trace->allsolid = true;
- trace->fraction = 0;
- trace->contents = brush->contents;
-}
-
-
-/*
-================
-CM_TraceToLeaf
-================
-*/
-void CM_TraceToLeaf (int leafnum)
-{
- int k;
- int brushnum;
- cleaf_t *leaf;
- cbrush_t *b;
-
- leaf = &map_leafs[leafnum];
- if ( !(leaf->contents & trace_contents))
- return;
- // trace line against all brushes in the leaf
- for (k=0 ; k<leaf->numleafbrushes ; k++)
- {
- brushnum = map_leafbrushes[leaf->firstleafbrush+k];
- b = &map_brushes[brushnum];
- if (b->checkcount == checkcount)
- continue; // already checked this brush in another leaf
- b->checkcount = checkcount;
-
- if ( !(b->contents & trace_contents))
- continue;
- CM_ClipBoxToBrush (trace_mins, trace_maxs, trace_start, trace_end, &trace_trace, b);
- if (!trace_trace.fraction)
- return;
- }
-
-}
-
-
-/*
-================
-CM_TestInLeaf
-================
-*/
-void CM_TestInLeaf (int leafnum)
-{
- int k;
- int brushnum;
- cleaf_t *leaf;
- cbrush_t *b;
-
- leaf = &map_leafs[leafnum];
- if ( !(leaf->contents & trace_contents))
- return;
- // trace line against all brushes in the leaf
- for (k=0 ; k<leaf->numleafbrushes ; k++)
- {
- brushnum = map_leafbrushes[leaf->firstleafbrush+k];
- b = &map_brushes[brushnum];
- if (b->checkcount == checkcount)
- continue; // already checked this brush in another leaf
- b->checkcount = checkcount;
-
- if ( !(b->contents & trace_contents))
- continue;
- CM_TestBoxInBrush (trace_mins, trace_maxs, trace_start, &trace_trace, b);
- if (!trace_trace.fraction)
- return;
- }
-
-}
-
-
-/*
-==================
-CM_RecursiveHullCheck
-
-==================
-*/
-void CM_RecursiveHullCheck (int num, float p1f, float p2f, vec3_t p1, vec3_t p2)
-{
- cnode_t *node;
- cplane_t *plane;
- float t1, t2, offset;
- float frac, frac2;
- float idist;
- int i;
- vec3_t mid;
- int side;
- float midf;
-
- if (trace_trace.fraction <= p1f)
- return; // already hit something nearer
-
- // if < 0, we are in a leaf node
- if (num < 0)
- {
- CM_TraceToLeaf (-1-num);
- return;
- }
-
- //
- // find the point distances to the seperating plane
- // and the offset for the size of the box
- //
- node = map_nodes + num;
- plane = node->plane;
-
- if (plane->type < 3)
- {
- t1 = p1[plane->type] - plane->dist;
- t2 = p2[plane->type] - plane->dist;
- offset = trace_extents[plane->type];
- }
- else
- {
- t1 = DotProduct (plane->normal, p1) - plane->dist;
- t2 = DotProduct (plane->normal, p2) - plane->dist;
- if (trace_ispoint)
- offset = 0;
- else
- offset = fabs(trace_extents[0]*plane->normal[0]) +
- fabs(trace_extents[1]*plane->normal[1]) +
- fabs(trace_extents[2]*plane->normal[2]);
- }
-
-
- /*
- CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2);
- CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2);
- return;
- */
-
- // see which sides we need to consider
- if (t1 >= offset && t2 >= offset)
- {
- CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2);
- return;
- }
- if (t1 < -offset && t2 < -offset)
- {
- CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2);
- return;
- }
-
- // put the crosspoint DIST_EPSILON pixels on the near side
- if (t1 < t2)
- {
- idist = 1.0/(t1-t2);
- side = 1;
- frac2 = (t1 + offset + DIST_EPSILON)*idist;
- frac = (t1 - offset + DIST_EPSILON)*idist;
- }
- else if (t1 > t2)
- {
- idist = 1.0/(t1-t2);
- side = 0;
- frac2 = (t1 - offset - DIST_EPSILON)*idist;
- frac = (t1 + offset + DIST_EPSILON)*idist;
- }
- else
- {
- side = 0;
- frac = 1;
- frac2 = 0;
- }
-
- // move up to the node
- if (frac < 0)
- frac = 0;
- if (frac > 1)
- frac = 1;
-
- midf = p1f + (p2f - p1f)*frac;
- for (i=0 ; i<3 ; i++)
- mid[i] = p1[i] + frac*(p2[i] - p1[i]);
-
- CM_RecursiveHullCheck (node->children[side], p1f, midf, p1, mid);
-
-
- // go past the node
- if (frac2 < 0)
- frac2 = 0;
- if (frac2 > 1)
- frac2 = 1;
-
- midf = p1f + (p2f - p1f)*frac2;
- for (i=0 ; i<3 ; i++)
- mid[i] = p1[i] + frac2*(p2[i] - p1[i]);
-
- CM_RecursiveHullCheck (node->children[side^1], midf, p2f, mid, p2);
-}
-
-
-
-//======================================================================
-
-/*
-==================
-CM_BoxTrace
-==================
-*/
-trace_t CM_BoxTrace (vec3_t start, vec3_t end,
- vec3_t mins, vec3_t maxs,
- int headnode, int brushmask)
-{
- int i;
-
- checkcount++; // for multi-check avoidance
-
- c_traces++; // for statistics, may be zeroed
-
- // fill in a default trace
- memset (&trace_trace, 0, sizeof(trace_trace));
- trace_trace.fraction = 1;
- trace_trace.surface = &(nullsurface.c);
-
- if (!numnodes) // map not loaded
- return trace_trace;
-
- trace_contents = brushmask;
- VectorCopy (start, trace_start);
- VectorCopy (end, trace_end);
- VectorCopy (mins, trace_mins);
- VectorCopy (maxs, trace_maxs);
-
- //
- // check for position test special case
- //
- if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2])
- {
- int leafs[1024];
- int i, numleafs;
- vec3_t c1, c2;
- int topnode;
-
- VectorAdd (start, mins, c1);
- VectorAdd (start, maxs, c2);
- for (i=0 ; i<3 ; i++)
- {
- c1[i] -= 1;
- c2[i] += 1;
- }
-
- numleafs = CM_BoxLeafnums_headnode (c1, c2, leafs, 1024, headnode, &topnode);
- for (i=0 ; i<numleafs ; i++)
- {
- CM_TestInLeaf (leafs[i]);
- if (trace_trace.allsolid)
- break;
- }
- VectorCopy (start, trace_trace.endpos);
- return trace_trace;
- }
-
- //
- // check for point special case
- //
- if (mins[0] == 0 && mins[1] == 0 && mins[2] == 0
- && maxs[0] == 0 && maxs[1] == 0 && maxs[2] == 0)
- {
- trace_ispoint = true;
- VectorClear (trace_extents);
- }
- else
- {
- trace_ispoint = false;
- trace_extents[0] = -mins[0] > maxs[0] ? -mins[0] : maxs[0];
- trace_extents[1] = -mins[1] > maxs[1] ? -mins[1] : maxs[1];
- trace_extents[2] = -mins[2] > maxs[2] ? -mins[2] : maxs[2];
- }
-
- //
- // general sweeping through world
- //
- CM_RecursiveHullCheck (headnode, 0, 1, start, end);
-
- if (trace_trace.fraction == 1)
- {
- VectorCopy (end, trace_trace.endpos);
- }
- else
- {
- for (i=0 ; i<3 ; i++)
- trace_trace.endpos[i] = start[i] + trace_trace.fraction * (end[i] - start[i]);
- }
- return trace_trace;
-}
-
-
-/*
-==================
-CM_TransformedBoxTrace
-
-Handles offseting and rotation of the end points for moving and
-rotating entities
-==================
-*/
-
-
-trace_t CM_TransformedBoxTrace (vec3_t start, vec3_t end,
- vec3_t mins, vec3_t maxs,
- int headnode, int brushmask,
- vec3_t origin, vec3_t angles)
-{
- trace_t trace;
- vec3_t start_l, end_l;
- vec3_t a;
- vec3_t forward, right, up;
- vec3_t temp;
- qboolean rotated;
-
- // subtract origin offset
- VectorSubtract (start, origin, start_l);
- VectorSubtract (end, origin, end_l);
-
- // rotate start and end into the models frame of reference
- if (headnode != box_headnode &&
- (angles[0] || angles[1] || angles[2]) )
- rotated = true;
- else
- rotated = false;
-
- if (rotated)
- {
- AngleVectors (angles, forward, right, up);
-
- VectorCopy (start_l, temp);
- start_l[0] = DotProduct (temp, forward);
- start_l[1] = -DotProduct (temp, right);
- start_l[2] = DotProduct (temp, up);
-
- VectorCopy (end_l, temp);
- end_l[0] = DotProduct (temp, forward);
- end_l[1] = -DotProduct (temp, right);
- end_l[2] = DotProduct (temp, up);
- }
-
- // sweep the box through the model
- trace = CM_BoxTrace (start_l, end_l, mins, maxs, headnode, brushmask);
-
- if (rotated && trace.fraction != 1.0)
- {
- // FIXME: figure out how to do this with existing angles
- VectorNegate (angles, a);
- AngleVectors (a, forward, right, up);
-
- VectorCopy (trace.plane.normal, temp);
- trace.plane.normal[0] = DotProduct (temp, forward);
- trace.plane.normal[1] = -DotProduct (temp, right);
- trace.plane.normal[2] = DotProduct (temp, up);
- }
-
- trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]);
- trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]);
- trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]);
-
- return trace;
-}
-
-/*
-===============================================================================
-
-PVS / PHS
-
-===============================================================================
-*/
-
-/*
-===================
-CM_DecompressVis
-===================
-*/
-void CM_DecompressVis (byte *in, byte *out)
-{
- int c;
- byte *out_p;
- int row;
-
- row = (numclusters+7)>>3;
- out_p = out;
-
- if (!in || !numvisibility)
- { // no vis info, so make all visible
- while (row)
- {
- *out_p++ = 0xff;
- row--;
- }
- return;
- }
-
- do
- {
- if (*in)
- {
- *out_p++ = *in++;
- continue;
- }
-
- c = in[1];
- in += 2;
- if ((out_p - out) + c > row)
- {
- c = row - (out_p - out);
- Com_DPrintf ("warning: Vis decompression overrun\n");
- }
- while (c)
- {
- *out_p++ = 0;
- c--;
- }
- } while (out_p - out < row);
-}
-
-byte pvsrow[MAX_MAP_LEAFS/8];
-byte phsrow[MAX_MAP_LEAFS/8];
-
-byte *CM_ClusterPVS (int cluster)
-{
- if (cluster == -1)
- memset (pvsrow, 0, (numclusters+7)>>3);
- else
- CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PVS], pvsrow);
- return pvsrow;
-}
-
-byte *CM_ClusterPHS (int cluster)
-{
- if (cluster == -1)
- memset (phsrow, 0, (numclusters+7)>>3);
- else
- CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PHS], phsrow);
- return phsrow;
-}
-
-
-/*
-===============================================================================
-
-AREAPORTALS
-
-===============================================================================
-*/
-
-void FloodArea_r (carea_t *area, int floodnum)
-{
- int i;
- dareaportal_t *p;
-
- if (area->floodvalid == floodvalid)
- {
- if (area->floodnum == floodnum)
- return;
- Com_Error (ERR_DROP, "FloodArea_r: reflooded");
- }
-
- area->floodnum = floodnum;
- area->floodvalid = floodvalid;
- p = &map_areaportals[area->firstareaportal];
- for (i=0 ; i<area->numareaportals ; i++, p++)
- {
- if (portalopen[p->portalnum])
- FloodArea_r (&map_areas[p->otherarea], floodnum);
- }
-}
-
-/*
-====================
-FloodAreaConnections
-
-
-====================
-*/
-void FloodAreaConnections (void)
-{
- int i;
- carea_t *area;
- int floodnum;
-
- // all current floods are now invalid
- floodvalid++;
- floodnum = 0;
-
- // area 0 is not used
- for (i=1 ; i<numareas ; i++)
- {
- area = &map_areas[i];
- if (area->floodvalid == floodvalid)
- continue; // already flooded into
- floodnum++;
- FloodArea_r (area, floodnum);
- }
-
-}
-
-void CM_SetAreaPortalState (int portalnum, qboolean open)
-{
- if (portalnum > numareaportals)
- Com_Error (ERR_DROP, "areaportal > numareaportals");
-
- portalopen[portalnum] = open;
- FloodAreaConnections ();
-}
-
-qboolean CM_AreasConnected (int area1, int area2)
-{
- if (map_noareas->value)
- return true;
-
- if (area1 > numareas || area2 > numareas)
- Com_Error (ERR_DROP, "area > numareas");
-
- if (map_areas[area1].floodnum == map_areas[area2].floodnum)
- return true;
- return false;
-}
-
-
-/*
-=================
-CM_WriteAreaBits
-
-Writes a length byte followed by a bit vector of all the areas
-that area in the same flood as the area parameter
-
-This is used by the client refreshes to cull visibility
-=================
-*/
-int CM_WriteAreaBits (byte *buffer, int area)
-{
- int i;
- int floodnum;
- int bytes;
-
- bytes = (numareas+7)>>3;
-
- if (map_noareas->value)
- { // for debugging, send everything
- memset (buffer, 255, bytes);
- }
- else
- {
- memset (buffer, 0, bytes);
-
- floodnum = map_areas[area].floodnum;
- for (i=0 ; i<numareas ; i++)
- {
- if (map_areas[i].floodnum == floodnum || !area)
- buffer[i>>3] |= 1<<(i&7);
- }
- }
-
- return bytes;
-}
-
-
-/*
-===================
-CM_WritePortalState
-
-Writes the portal state to a savegame file
-===================
-*/
-void CM_WritePortalState (FILE *f)
-{
- fwrite (portalopen, sizeof(portalopen), 1, f);
-}
-
-/*
-===================
-CM_ReadPortalState
-
-Reads the portal state from a savegame file
-and recalculates the area connections
-===================
-*/
-void CM_ReadPortalState (FILE *f)
-{
- FS_Read (portalopen, sizeof(portalopen), f);
- FloodAreaConnections ();
-}
-
-/*
-=============
-CM_HeadnodeVisible
-
-Returns true if any leaf under headnode has a cluster that
-is potentially visible
-=============
-*/
-qboolean CM_HeadnodeVisible (int nodenum, byte *visbits)
-{
- int leafnum;
- int cluster;
- cnode_t *node;
-
- if (nodenum < 0)
- {
- leafnum = -1-nodenum;
- cluster = map_leafs[leafnum].cluster;
- if (cluster == -1)
- return false;
- if (visbits[cluster>>3] & (1<<(cluster&7)))
- return true;
- return false;
- }
-
- node = &map_nodes[nodenum];
- if (CM_HeadnodeVisible(node->children[0], visbits))
- return true;
- return CM_HeadnodeVisible(node->children[1], visbits);
-}
-
--- a/qcommon/common.c
+++ /dev/null
@@ -1,1563 +1,0 @@
-// common.c -- misc functions used in client and server
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-#define MAXPRINTMSG 4096
-
-#define MAX_NUM_ARGVS 50
-
-
-int com_argc;
-char *com_argv[MAX_NUM_ARGVS+1];
-
-int realtime;
-
-jmp_buf abortframe; // an ERR_DROP occured, exit the entire frame
-
-
-FILE *log_stats_file;
-
-cvar_t *host_speeds;
-cvar_t *log_stats;
-cvar_t *developer;
-cvar_t *timescale;
-cvar_t *fixedtime;
-cvar_t *logfile_active; // 1 = buffer log, 2 = flush after each print
-cvar_t *showtrace;
-cvar_t *dedicated;
-
-FILE *logfile;
-
-int server_state;
-
-// host_speeds times
-int time_before_game;
-int time_after_game;
-int time_before_ref;
-int time_after_ref;
-
-/*
-============================================================================
-
-CLIENT / SERVER interactions
-
-============================================================================
-*/
-
-static int rd_target;
-static char *rd_buffer;
-static int rd_buffersize;
-static void (*rd_flush)(int target, char *buffer);
-
-void Com_BeginRedirect (int target, char *buffer, int buffersize, void (*flush))
-{
- if (!target || !buffer || !buffersize || !flush)
- return;
- rd_target = target;
- rd_buffer = buffer;
- rd_buffersize = buffersize;
- rd_flush = flush;
-
- *rd_buffer = 0;
-}
-
-void Com_EndRedirect (void)
-{
- rd_flush(rd_target, rd_buffer);
-
- rd_target = 0;
- rd_buffer = NULL;
- rd_buffersize = 0;
- rd_flush = NULL;
-}
-
-/*
-=============
-Com_Printf
-
-Both client and server can use this, and it will output
-to the apropriate place.
-=============
-*/
-void Com_Printf (char *fmt, ...)
-{
- va_list argptr;
- char msg[MAXPRINTMSG];
-
- va_start (argptr,fmt);
- vsprintf (msg,fmt,argptr);
- va_end (argptr);
-
- if (rd_target)
- {
- if ((strlen (msg) + strlen(rd_buffer)) > (rd_buffersize - 1))
- {
- rd_flush(rd_target, rd_buffer);
- *rd_buffer = 0;
- }
- strcat (rd_buffer, msg);
- return;
- }
-
- Con_Print (msg);
-
- // also echo to debugging console
- Sys_ConsoleOutput (msg);
-
- // logfile
- if (logfile_active && logfile_active->value)
- {
- char name[MAX_QPATH];
-
- if (!logfile)
- {
- Com_sprintf (name, sizeof(name), "%s/qconsole.log", FS_Gamedir ());
- logfile = fopen (name, "w");
- }
- if (logfile)
- fprintf (logfile, "%s", msg);
- if (logfile_active->value > 1)
- fflush (logfile); // force it to save every time
- }
-}
-
-
-/*
-================
-Com_DPrintf
-
-A Com_Printf that only shows up if the "developer" cvar is set
-================
-*/
-void Com_DPrintf (char *fmt, ...)
-{
- va_list argptr;
- char msg[MAXPRINTMSG];
-
- if (!developer || !developer->value)
- return; // don't confuse non-developers with techie stuff...
-
- va_start (argptr,fmt);
- vsprintf (msg,fmt,argptr);
- va_end (argptr);
-
- Com_Printf ("%s", msg);
-}
-
-
-/*
-=============
-Com_Error
-
-Both client and server can use this, and it will
-do the apropriate things.
-=============
-*/
-void Com_Error (int code, char *fmt, ...)
-{
- va_list argptr;
- static char msg[MAXPRINTMSG];
- static qboolean recursive;
-
- if (recursive)
- Sys_Error ("recursive error after: %s", msg);
- recursive = true;
-
- va_start (argptr,fmt);
- vsprintf (msg,fmt,argptr);
- va_end (argptr);
-
- if (code == ERR_DISCONNECT)
- {
- CL_Drop ();
- recursive = false;
- longjmp (abortframe, -1);
- }
- else if (code == ERR_DROP)
- {
- Com_Printf ("********************\nERROR: %s\n********************\n", msg);
- SV_Shutdown (va("Server crashed: %s\n", msg), false);
- CL_Drop ();
- recursive = false;
- longjmp (abortframe, -1);
- }
- else
- {
- SV_Shutdown (va("Server fatal crashed: %s\n", msg), false);
- CL_Shutdown ();
- }
-
- if (logfile)
- {
- fclose (logfile);
- logfile = NULL;
- }
-
- Sys_Error ("%s", msg);
-}
-
-
-/*
-=============
-Com_Quit
-
-Both client and server can use this, and it will
-do the apropriate things.
-=============
-*/
-void Com_Quit (void)
-{
- SV_Shutdown ("Server quit\n", false);
- CL_Shutdown ();
-
- if (logfile)
- {
- fclose (logfile);
- logfile = NULL;
- }
-
- Sys_Quit ();
-}
-
-
-/*
-==================
-Com_ServerState
-==================
-*/
-int Com_ServerState (void)
-{
- return server_state;
-}
-
-/*
-==================
-Com_SetServerState
-==================
-*/
-void Com_SetServerState (int state)
-{
- server_state = state;
-}
-
-
-/*
-==============================================================================
-
- MESSAGE IO FUNCTIONS
-
-Handles byte ordering and avoids alignment errors
-==============================================================================
-*/
-
-vec3_t bytedirs[NUMVERTEXNORMALS] =
-{
-#include "../anorms.h"
-};
-
-//
-// writing functions
-//
-
-void MSG_WriteChar (sizebuf_t *sb, int c)
-{
- byte *buf;
-
-#ifdef PARANOID
- if (c < -128 || c > 127)
- Com_Error (ERR_FATAL, "MSG_WriteChar: range error");
-#endif
-
- buf = SZ_GetSpace (sb, 1);
- buf[0] = c;
-}
-
-void MSG_WriteByte (sizebuf_t *sb, int c)
-{
- byte *buf;
-
-#ifdef PARANOID
- if (c < 0 || c > 255)
- Com_Error (ERR_FATAL, "MSG_WriteByte: range error");
-#endif
-
- buf = SZ_GetSpace (sb, 1);
- buf[0] = c;
-}
-
-void MSG_WriteShort (sizebuf_t *sb, int c)
-{
- byte *buf;
-
-#ifdef PARANOID
- if (c < ((short)0x8000) || c > (short)0x7fff)
- Com_Error (ERR_FATAL, "MSG_WriteShort: range error");
-#endif
-
- buf = SZ_GetSpace (sb, 2);
- buf[0] = c&0xff;
- buf[1] = c>>8;
-}
-
-void MSG_WriteLong (sizebuf_t *sb, int c)
-{
- byte *buf;
-
- buf = SZ_GetSpace (sb, 4);
- buf[0] = c&0xff;
- buf[1] = (c>>8)&0xff;
- buf[2] = (c>>16)&0xff;
- buf[3] = c>>24;
-}
-
-void MSG_WriteFloat (sizebuf_t *sb, float f)
-{
- union
- {
- float f;
- int l;
- } dat;
-
-
- dat.f = f;
- dat.l = LittleLong (dat.l);
-
- SZ_Write (sb, &dat.l, 4);
-}
-
-void MSG_WriteString (sizebuf_t *sb, char *s)
-{
- if (!s)
- SZ_Write (sb, "", 1);
- else
- SZ_Write (sb, s, strlen(s)+1);
-}
-
-void MSG_WriteCoord (sizebuf_t *sb, float f)
-{
- MSG_WriteShort (sb, (int)(f*8));
-}
-
-void MSG_WritePos (sizebuf_t *sb, vec3_t pos)
-{
- MSG_WriteShort (sb, (int)(pos[0]*8));
- MSG_WriteShort (sb, (int)(pos[1]*8));
- MSG_WriteShort (sb, (int)(pos[2]*8));
-}
-
-void MSG_WriteAngle (sizebuf_t *sb, float f)
-{
- MSG_WriteByte (sb, (int)(f*256/360) & 255);
-}
-
-void MSG_WriteAngle16 (sizebuf_t *sb, float f)
-{
- MSG_WriteShort (sb, ANGLE2SHORT(f));
-}
-
-
-void MSG_WriteDeltaUsercmd (sizebuf_t *buf, usercmd_t *from, usercmd_t *cmd)
-{
- int bits;
-
-//
-// send the movement message
-//
- bits = 0;
- if (cmd->angles[0] != from->angles[0])
- bits |= CM_ANGLE1;
- if (cmd->angles[1] != from->angles[1])
- bits |= CM_ANGLE2;
- if (cmd->angles[2] != from->angles[2])
- bits |= CM_ANGLE3;
- if (cmd->forwardmove != from->forwardmove)
- bits |= CM_FORWARD;
- if (cmd->sidemove != from->sidemove)
- bits |= CM_SIDE;
- if (cmd->upmove != from->upmove)
- bits |= CM_UP;
- if (cmd->buttons != from->buttons)
- bits |= CM_BUTTONS;
- if (cmd->impulse != from->impulse)
- bits |= CM_IMPULSE;
-
- MSG_WriteByte (buf, bits);
-
- if (bits & CM_ANGLE1)
- MSG_WriteShort (buf, cmd->angles[0]);
- if (bits & CM_ANGLE2)
- MSG_WriteShort (buf, cmd->angles[1]);
- if (bits & CM_ANGLE3)
- MSG_WriteShort (buf, cmd->angles[2]);
-
- if (bits & CM_FORWARD)
- MSG_WriteShort (buf, cmd->forwardmove);
- if (bits & CM_SIDE)
- MSG_WriteShort (buf, cmd->sidemove);
- if (bits & CM_UP)
- MSG_WriteShort (buf, cmd->upmove);
-
- if (bits & CM_BUTTONS)
- MSG_WriteByte (buf, cmd->buttons);
- if (bits & CM_IMPULSE)
- MSG_WriteByte (buf, cmd->impulse);
-
- MSG_WriteByte (buf, cmd->msec);
- MSG_WriteByte (buf, cmd->lightlevel);
-}
-
-
-void MSG_WriteDir (sizebuf_t *sb, vec3_t dir)
-{
- int i, best;
- float d, bestd;
-
- if (!dir)
- {
- MSG_WriteByte (sb, 0);
- return;
- }
-
- bestd = 0;
- best = 0;
- for (i=0 ; i<NUMVERTEXNORMALS ; i++)
- {
- d = DotProduct (dir, bytedirs[i]);
- if (d > bestd)
- {
- bestd = d;
- best = i;
- }
- }
- MSG_WriteByte (sb, best);
-}
-
-
-void MSG_ReadDir (sizebuf_t *sb, vec3_t dir)
-{
- int b;
-
- b = MSG_ReadByte (sb);
- if (b >= NUMVERTEXNORMALS)
- Com_Error (ERR_DROP, "MSF_ReadDir: out of range");
- VectorCopy (bytedirs[b], dir);
-}
-
-
-/*
-==================
-MSG_WriteDeltaEntity
-
-Writes part of a packetentities message.
-Can delta from either a baseline or a previous packet_entity
-==================
-*/
-void MSG_WriteDeltaEntity (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, qboolean newentity)
-{
- int bits;
-
- if (!to->number)
- Com_Error (ERR_FATAL, "Unset entity number");
- if (to->number >= MAX_EDICTS)
- Com_Error (ERR_FATAL, "Entity number >= MAX_EDICTS");
-
-// send an update
- bits = 0;
-
- if (to->number >= 256)
- bits |= U_NUMBER16; // number8 is implicit otherwise
-
- if (to->origin[0] != from->origin[0])
- bits |= U_ORIGIN1;
- if (to->origin[1] != from->origin[1])
- bits |= U_ORIGIN2;
- if (to->origin[2] != from->origin[2])
- bits |= U_ORIGIN3;
-
- if ( to->angles[0] != from->angles[0] )
- bits |= U_ANGLE1;
- if ( to->angles[1] != from->angles[1] )
- bits |= U_ANGLE2;
- if ( to->angles[2] != from->angles[2] )
- bits |= U_ANGLE3;
-
- if ( to->skinnum != from->skinnum )
- {
- if ((unsigned)to->skinnum < 256)
- bits |= U_SKIN8;
- else if ((unsigned)to->skinnum < 0x10000)
- bits |= U_SKIN16;
- else
- bits |= (U_SKIN8|U_SKIN16);
- }
-
- if ( to->frame != from->frame )
- {
- if (to->frame < 256)
- bits |= U_FRAME8;
- else
- bits |= U_FRAME16;
- }
-
- if ( to->effects != from->effects )
- {
- if (to->effects < 256)
- bits |= U_EFFECTS8;
- else if (to->effects < 0x8000)
- bits |= U_EFFECTS16;
- else
- bits |= U_EFFECTS8|U_EFFECTS16;
- }
-
- if ( to->renderfx != from->renderfx )
- {
- if (to->renderfx < 256)
- bits |= U_RENDERFX8;
- else if (to->renderfx < 0x8000)
- bits |= U_RENDERFX16;
- else
- bits |= U_RENDERFX8|U_RENDERFX16;
- }
-
- if ( to->solid != from->solid )
- bits |= U_SOLID;
-
- // event is not delta compressed, just 0 compressed
- if ( to->event )
- bits |= U_EVENT;
-
- if ( to->modelindex != from->modelindex )
- bits |= U_MODEL;
- if ( to->modelindex2 != from->modelindex2 )
- bits |= U_MODEL2;
- if ( to->modelindex3 != from->modelindex3 )
- bits |= U_MODEL3;
- if ( to->modelindex4 != from->modelindex4 )
- bits |= U_MODEL4;
-
- if ( to->sound != from->sound )
- bits |= U_SOUND;
-
- if (newentity || (to->renderfx & RF_BEAM))
- bits |= U_OLDORIGIN;
-
- //
- // write the message
- //
- if (!bits && !force)
- return; // nothing to send!
-
- //----------
-
- if (bits & 0xff000000)
- bits |= U_MOREBITS3 | U_MOREBITS2 | U_MOREBITS1;
- else if (bits & 0x00ff0000)
- bits |= U_MOREBITS2 | U_MOREBITS1;
- else if (bits & 0x0000ff00)
- bits |= U_MOREBITS1;
-
- MSG_WriteByte (msg, bits&255 );
-
- if (bits & 0xff000000)
- {
- MSG_WriteByte (msg, (bits>>8)&255 );
- MSG_WriteByte (msg, (bits>>16)&255 );
- MSG_WriteByte (msg, (bits>>24)&255 );
- }
- else if (bits & 0x00ff0000)
- {
- MSG_WriteByte (msg, (bits>>8)&255 );
- MSG_WriteByte (msg, (bits>>16)&255 );
- }
- else if (bits & 0x0000ff00)
- {
- MSG_WriteByte (msg, (bits>>8)&255 );
- }
-
- //----------
-
- if (bits & U_NUMBER16)
- MSG_WriteShort (msg, to->number);
- else
- MSG_WriteByte (msg, to->number);
-
- if (bits & U_MODEL)
- MSG_WriteByte (msg, to->modelindex);
- if (bits & U_MODEL2)
- MSG_WriteByte (msg, to->modelindex2);
- if (bits & U_MODEL3)
- MSG_WriteByte (msg, to->modelindex3);
- if (bits & U_MODEL4)
- MSG_WriteByte (msg, to->modelindex4);
-
- if (bits & U_FRAME8)
- MSG_WriteByte (msg, to->frame);
- if (bits & U_FRAME16)
- MSG_WriteShort (msg, to->frame);
-
- if ((bits & U_SKIN8) && (bits & U_SKIN16)) //used for laser colors
- MSG_WriteLong (msg, to->skinnum);
- else if (bits & U_SKIN8)
- MSG_WriteByte (msg, to->skinnum);
- else if (bits & U_SKIN16)
- MSG_WriteShort (msg, to->skinnum);
-
-
- if ( (bits & (U_EFFECTS8|U_EFFECTS16)) == (U_EFFECTS8|U_EFFECTS16) )
- MSG_WriteLong (msg, to->effects);
- else if (bits & U_EFFECTS8)
- MSG_WriteByte (msg, to->effects);
- else if (bits & U_EFFECTS16)
- MSG_WriteShort (msg, to->effects);
-
- if ( (bits & (U_RENDERFX8|U_RENDERFX16)) == (U_RENDERFX8|U_RENDERFX16) )
- MSG_WriteLong (msg, to->renderfx);
- else if (bits & U_RENDERFX8)
- MSG_WriteByte (msg, to->renderfx);
- else if (bits & U_RENDERFX16)
- MSG_WriteShort (msg, to->renderfx);
-
- if (bits & U_ORIGIN1)
- MSG_WriteCoord (msg, to->origin[0]);
- if (bits & U_ORIGIN2)
- MSG_WriteCoord (msg, to->origin[1]);
- if (bits & U_ORIGIN3)
- MSG_WriteCoord (msg, to->origin[2]);
-
- if (bits & U_ANGLE1)
- MSG_WriteAngle(msg, to->angles[0]);
- if (bits & U_ANGLE2)
- MSG_WriteAngle(msg, to->angles[1]);
- if (bits & U_ANGLE3)
- MSG_WriteAngle(msg, to->angles[2]);
-
- if (bits & U_OLDORIGIN)
- {
- MSG_WriteCoord (msg, to->old_origin[0]);
- MSG_WriteCoord (msg, to->old_origin[1]);
- MSG_WriteCoord (msg, to->old_origin[2]);
- }
-
- if (bits & U_SOUND)
- MSG_WriteByte (msg, to->sound);
- if (bits & U_EVENT)
- MSG_WriteByte (msg, to->event);
- if (bits & U_SOLID)
- MSG_WriteShort (msg, to->solid);
-}
-
-
-//============================================================
-
-//
-// reading functions
-//
-
-void MSG_BeginReading (sizebuf_t *msg)
-{
- msg->readcount = 0;
-}
-
-// returns -1 if no more characters are available
-int MSG_ReadChar (sizebuf_t *msg_read)
-{
- int c;
-
- if (msg_read->readcount+1 > msg_read->cursize)
- c = -1;
- else
- c = (signed char)msg_read->data[msg_read->readcount];
- msg_read->readcount++;
-
- return c;
-}
-
-int MSG_ReadByte (sizebuf_t *msg_read)
-{
- int c;
-
- if (msg_read->readcount+1 > msg_read->cursize)
- c = -1;
- else
- c = (unsigned char)msg_read->data[msg_read->readcount];
- msg_read->readcount++;
-
- return c;
-}
-
-int MSG_ReadShort (sizebuf_t *msg_read)
-{
- int c;
-
- if (msg_read->readcount+2 > msg_read->cursize)
- c = -1;
- else
- c = (short)(msg_read->data[msg_read->readcount]
- + (msg_read->data[msg_read->readcount+1]<<8));
-
- msg_read->readcount += 2;
-
- return c;
-}
-
-int MSG_ReadLong (sizebuf_t *msg_read)
-{
- int c;
-
- if (msg_read->readcount+4 > msg_read->cursize)
- c = -1;
- else
- c = msg_read->data[msg_read->readcount]
- + (msg_read->data[msg_read->readcount+1]<<8)
- + (msg_read->data[msg_read->readcount+2]<<16)
- + (msg_read->data[msg_read->readcount+3]<<24);
-
- msg_read->readcount += 4;
-
- return c;
-}
-
-float MSG_ReadFloat (sizebuf_t *msg_read)
-{
- union
- {
- byte b[4];
- float f;
- int l;
- } dat;
-
- if (msg_read->readcount+4 > msg_read->cursize)
- dat.f = -1;
- else
- {
- dat.b[0] = msg_read->data[msg_read->readcount];
- dat.b[1] = msg_read->data[msg_read->readcount+1];
- dat.b[2] = msg_read->data[msg_read->readcount+2];
- dat.b[3] = msg_read->data[msg_read->readcount+3];
- }
- msg_read->readcount += 4;
-
- dat.l = LittleLong (dat.l);
-
- return dat.f;
-}
-
-char *MSG_ReadString (sizebuf_t *msg_read)
-{
- static char string[2048];
- int l,c;
-
- l = 0;
- do
- {
- c = MSG_ReadChar (msg_read);
- if (c == -1 || c == 0)
- break;
- string[l] = c;
- l++;
- } while (l < sizeof(string)-1);
-
- string[l] = 0;
-
- return string;
-}
-
-char *MSG_ReadStringLine (sizebuf_t *msg_read)
-{
- static char string[2048];
- int l,c;
-
- l = 0;
- do
- {
- c = MSG_ReadChar (msg_read);
- if (c == -1 || c == 0 || c == '\n')
- break;
- string[l] = c;
- l++;
- } while (l < sizeof(string)-1);
-
- string[l] = 0;
-
- return string;
-}
-
-float MSG_ReadCoord (sizebuf_t *msg_read)
-{
- return MSG_ReadShort(msg_read) * (1.0/8);
-}
-
-void MSG_ReadPos (sizebuf_t *msg_read, vec3_t pos)
-{
- pos[0] = MSG_ReadShort(msg_read) * (1.0/8);
- pos[1] = MSG_ReadShort(msg_read) * (1.0/8);
- pos[2] = MSG_ReadShort(msg_read) * (1.0/8);
-}
-
-float MSG_ReadAngle (sizebuf_t *msg_read)
-{
- return MSG_ReadChar(msg_read) * (360.0/256);
-}
-
-float MSG_ReadAngle16 (sizebuf_t *msg_read)
-{
- return SHORT2ANGLE(MSG_ReadShort(msg_read));
-}
-
-void MSG_ReadDeltaUsercmd (sizebuf_t *msg_read, usercmd_t *from, usercmd_t *move)
-{
- int bits;
-
- memcpy (move, from, sizeof(*move));
-
- bits = MSG_ReadByte (msg_read);
-
-// read current angles
- if (bits & CM_ANGLE1)
- move->angles[0] = MSG_ReadShort (msg_read);
- if (bits & CM_ANGLE2)
- move->angles[1] = MSG_ReadShort (msg_read);
- if (bits & CM_ANGLE3)
- move->angles[2] = MSG_ReadShort (msg_read);
-
-// read movement
- if (bits & CM_FORWARD)
- move->forwardmove = MSG_ReadShort (msg_read);
- if (bits & CM_SIDE)
- move->sidemove = MSG_ReadShort (msg_read);
- if (bits & CM_UP)
- move->upmove = MSG_ReadShort (msg_read);
-
-// read buttons
- if (bits & CM_BUTTONS)
- move->buttons = MSG_ReadByte (msg_read);
-
- if (bits & CM_IMPULSE)
- move->impulse = MSG_ReadByte (msg_read);
-
-// read time to run command
- move->msec = MSG_ReadByte (msg_read);
-
-// read the light level
- move->lightlevel = MSG_ReadByte (msg_read);
-}
-
-
-void MSG_ReadData (sizebuf_t *msg_read, void *data, int len)
-{
- int i;
-
- for (i=0 ; i<len ; i++)
- ((byte *)data)[i] = MSG_ReadByte (msg_read);
-}
-
-
-//===========================================================================
-
-void SZ_Init (sizebuf_t *buf, byte *data, int length)
-{
- memset (buf, 0, sizeof(*buf));
- buf->data = data;
- buf->maxsize = length;
-}
-
-void SZ_Clear (sizebuf_t *buf)
-{
- buf->cursize = 0;
- buf->overflowed = false;
-}
-
-void *SZ_GetSpace (sizebuf_t *buf, int length)
-{
- void *data;
-
- if (buf->cursize + length > buf->maxsize)
- {
- if (!buf->allowoverflow)
- Com_Error (ERR_FATAL, "SZ_GetSpace: overflow without allowoverflow set");
-
- if (length > buf->maxsize)
- Com_Error (ERR_FATAL, "SZ_GetSpace: %i is > full buffer size", length);
-
- Com_Printf ("SZ_GetSpace: overflow\n");
- SZ_Clear (buf);
- buf->overflowed = true;
- }
-
- data = buf->data + buf->cursize;
- buf->cursize += length;
-
- return data;
-}
-
-void SZ_Write (sizebuf_t *buf, void *data, int length)
-{
- memcpy (SZ_GetSpace(buf,length),data,length);
-}
-
-void SZ_Print (sizebuf_t *buf, char *data)
-{
- int len;
-
- len = strlen(data)+1;
-
- if (buf->cursize)
- {
- if (buf->data[buf->cursize-1])
- memcpy ((byte *)SZ_GetSpace(buf, len),data,len); // no trailing 0
- else
- memcpy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0
- }
- else
- memcpy ((byte *)SZ_GetSpace(buf, len),data,len);
-}
-
-
-//============================================================================
-
-
-/*
-================
-COM_CheckParm
-
-Returns the position (1 to argc-1) in the program's argument list
-where the given parameter apears, or 0 if not present
-================
-*/
-int COM_CheckParm (char *parm)
-{
- int i;
-
- for (i=1 ; i<com_argc ; i++)
- {
- if (!strcmp (parm,com_argv[i]))
- return i;
- }
-
- return 0;
-}
-
-int COM_Argc (void)
-{
- return com_argc;
-}
-
-char *COM_Argv (int arg)
-{
- if (arg < 0 || arg >= com_argc || !com_argv[arg])
- return "";
- return com_argv[arg];
-}
-
-void COM_ClearArgv (int arg)
-{
- if (arg < 0 || arg >= com_argc || !com_argv[arg])
- return;
- com_argv[arg] = "";
-}
-
-
-/*
-================
-COM_InitArgv
-================
-*/
-void COM_InitArgv (int argc, char **argv)
-{
- int i;
-
- if (argc > MAX_NUM_ARGVS)
- Com_Error (ERR_FATAL, "argc > MAX_NUM_ARGVS");
- com_argc = argc;
- for (i=0 ; i<argc ; i++)
- {
- if (!argv[i] || strlen(argv[i]) >= MAX_TOKEN_CHARS )
- com_argv[i] = "";
- else
- com_argv[i] = argv[i];
- }
-}
-
-/*
-================
-COM_AddParm
-
-Adds the given string at the end of the current argument list
-================
-*/
-void COM_AddParm (char *parm)
-{
- if (com_argc == MAX_NUM_ARGVS)
- Com_Error (ERR_FATAL, "COM_AddParm: MAX_NUM)ARGS");
- com_argv[com_argc++] = parm;
-}
-
-
-
-
-/// just for debugging
-int memsearch (byte *start, int count, int search)
-{
- int i;
-
- for (i=0 ; i<count ; i++)
- if (start[i] == search)
- return i;
- return -1;
-}
-
-
-char *CopyString (char *in)
-{
- char *out;
-
- out = Z_Malloc (strlen(in)+1);
- strcpy (out, in);
- return out;
-}
-
-
-
-void Info_Print (char *s)
-{
- char key[512];
- char value[512];
- char *o;
- int l;
-
- if (*s == '\\')
- s++;
- while (*s)
- {
- o = key;
- while (*s && *s != '\\')
- *o++ = *s++;
-
- l = o - key;
- if (l < 20)
- {
- memset (o, ' ', 20-l);
- key[20] = 0;
- }
- else
- *o = 0;
- Com_Printf ("%s", key);
-
- if (!*s)
- {
- Com_Printf ("MISSING VALUE\n");
- return;
- }
-
- o = value;
- s++;
- while (*s && *s != '\\')
- *o++ = *s++;
- *o = 0;
-
- if (*s)
- s++;
- Com_Printf ("%s\n", value);
- }
-}
-
-
-/*
-==============================================================================
-
- ZONE MEMORY ALLOCATION
-
-just cleared malloc with counters now...
-
-==============================================================================
-*/
-
-#define Z_MAGIC 0x1d1d
-
-
-typedef struct zhead_s
-{
- struct zhead_s *prev, *next;
- short magic;
- short tag; // for group free
- int size;
-} zhead_t;
-
-zhead_t z_chain;
-int z_count, z_bytes;
-
-/*
-========================
-Z_Free
-========================
-*/
-void Z_Free (void *ptr)
-{
- zhead_t *z;
-
- z = ((zhead_t *)ptr) - 1;
-
- if (z->magic != Z_MAGIC)
- Com_Error (ERR_FATAL, "Z_Free: bad magic");
-
- z->prev->next = z->next;
- z->next->prev = z->prev;
-
- z_count--;
- z_bytes -= z->size;
- free (z);
-}
-
-
-/*
-========================
-Z_Stats_f
-========================
-*/
-void Z_Stats_f (void)
-{
- Com_Printf ("%i bytes in %i blocks\n", z_bytes, z_count);
-}
-
-/*
-========================
-Z_FreeTags
-========================
-*/
-void Z_FreeTags (int tag)
-{
- zhead_t *z, *next;
-
- for (z=z_chain.next ; z != &z_chain ; z=next)
- {
- next = z->next;
- if (z->tag == tag)
- Z_Free ((void *)(z+1));
- }
-}
-
-/*
-========================
-Z_TagMalloc
-========================
-*/
-void *Z_TagMalloc (int size, int tag)
-{
- zhead_t *z;
-
- size = size + sizeof(zhead_t);
- z = malloc(size);
- if (!z)
- Com_Error (ERR_FATAL, "Z_Malloc: failed on allocation of %i bytes",size);
- memset (z, 0, size);
- z_count++;
- z_bytes += size;
- z->magic = Z_MAGIC;
- z->tag = tag;
- z->size = size;
-
- z->next = z_chain.next;
- z->prev = &z_chain;
- z_chain.next->prev = z;
- z_chain.next = z;
-
- return (void *)(z+1);
-}
-
-/*
-========================
-Z_Malloc
-========================
-*/
-void *Z_Malloc (int size)
-{
- return Z_TagMalloc (size, 0);
-}
-
-
-//============================================================================
-
-
-/*
-====================
-COM_BlockSequenceCheckByte
-
-For proxy protecting
-
-// THIS IS MASSIVELY BROKEN! CHALLENGE MAY BE NEGATIVE
-// DON'T USE THIS FUNCTION!!!!!
-
-====================
-*/
-byte COM_BlockSequenceCheckByte (byte */*base*/, int /*length*/, int /*sequence*/, int /*challenge*/)
-{
- Sys_Error("COM_BlockSequenceCheckByte called\n");
-
-/*
- int checksum;
- byte buf[68];
- byte *p;
- float temp;
- byte c;
-
- temp = bytedirs[(sequence/3) % NUMVERTEXNORMALS][sequence % 3];
- temp = LittleFloat(temp);
- p = ((byte *)&temp);
-
- if (length > 60)
- length = 60;
- memcpy (buf, base, length);
-
- buf[length] = (sequence & 0xff) ^ p[0];
- buf[length+1] = p[1];
- buf[length+2] = ((sequence>>8) & 0xff) ^ p[2];
- buf[length+3] = p[3];
-
- temp = bytedirs[((sequence+challenge)/3) % NUMVERTEXNORMALS][(sequence+challenge) % 3];
- temp = LittleFloat(temp);
- p = ((byte *)&temp);
-
- buf[length+4] = (sequence & 0xff) ^ p[3];
- buf[length+5] = (challenge & 0xff) ^ p[2];
- buf[length+6] = ((sequence>>8) & 0xff) ^ p[1];
- buf[length+7] = ((challenge >> 7) & 0xff) ^ p[0];
-
- length += 8;
-
- checksum = LittleLong(Com_BlockChecksum (buf, length));
-
- checksum &= 0xff;
-
- return checksum;
-*/
- return 0;
-}
-
-static byte chktbl[1024] = {
-0x84, 0x47, 0x51, 0xc1, 0x93, 0x22, 0x21, 0x24, 0x2f, 0x66, 0x60, 0x4d, 0xb0, 0x7c, 0xda,
-0x88, 0x54, 0x15, 0x2b, 0xc6, 0x6c, 0x89, 0xc5, 0x9d, 0x48, 0xee, 0xe6, 0x8a, 0xb5, 0xf4,
-0xcb, 0xfb, 0xf1, 0x0c, 0x2e, 0xa0, 0xd7, 0xc9, 0x1f, 0xd6, 0x06, 0x9a, 0x09, 0x41, 0x54,
-0x67, 0x46, 0xc7, 0x74, 0xe3, 0xc8, 0xb6, 0x5d, 0xa6, 0x36, 0xc4, 0xab, 0x2c, 0x7e, 0x85,
-0xa8, 0xa4, 0xa6, 0x4d, 0x96, 0x19, 0x19, 0x9a, 0xcc, 0xd8, 0xac, 0x39, 0x5e, 0x3c, 0xf2,
-0xf5, 0x5a, 0x72, 0xe5, 0xa9, 0xd1, 0xb3, 0x23, 0x82, 0x6f, 0x29, 0xcb, 0xd1, 0xcc, 0x71,
-0xfb, 0xea, 0x92, 0xeb, 0x1c, 0xca, 0x4c, 0x70, 0xfe, 0x4d, 0xc9, 0x67, 0x43, 0x47, 0x94,
-0xb9, 0x47, 0xbc, 0x3f, 0x01, 0xab, 0x7b, 0xa6, 0xe2, 0x76, 0xef, 0x5a, 0x7a, 0x29, 0x0b,
-0x51, 0x54, 0x67, 0xd8, 0x1c, 0x14, 0x3e, 0x29, 0xec, 0xe9, 0x2d, 0x48, 0x67, 0xff, 0xed,
-0x54, 0x4f, 0x48, 0xc0, 0xaa, 0x61, 0xf7, 0x78, 0x12, 0x03, 0x7a, 0x9e, 0x8b, 0xcf, 0x83,
-0x7b, 0xae, 0xca, 0x7b, 0xd9, 0xe9, 0x53, 0x2a, 0xeb, 0xd2, 0xd8, 0xcd, 0xa3, 0x10, 0x25,
-0x78, 0x5a, 0xb5, 0x23, 0x06, 0x93, 0xb7, 0x84, 0xd2, 0xbd, 0x96, 0x75, 0xa5, 0x5e, 0xcf,
-0x4e, 0xe9, 0x50, 0xa1, 0xe6, 0x9d, 0xb1, 0xe3, 0x85, 0x66, 0x28, 0x4e, 0x43, 0xdc, 0x6e,
-0xbb, 0x33, 0x9e, 0xf3, 0x0d, 0x00, 0xc1, 0xcf, 0x67, 0x34, 0x06, 0x7c, 0x71, 0xe3, 0x63,
-0xb7, 0xb7, 0xdf, 0x92, 0xc4, 0xc2, 0x25, 0x5c, 0xff, 0xc3, 0x6e, 0xfc, 0xaa, 0x1e, 0x2a,
-0x48, 0x11, 0x1c, 0x36, 0x68, 0x78, 0x86, 0x79, 0x30, 0xc3, 0xd6, 0xde, 0xbc, 0x3a, 0x2a,
-0x6d, 0x1e, 0x46, 0xdd, 0xe0, 0x80, 0x1e, 0x44, 0x3b, 0x6f, 0xaf, 0x31, 0xda, 0xa2, 0xbd,
-0x77, 0x06, 0x56, 0xc0, 0xb7, 0x92, 0x4b, 0x37, 0xc0, 0xfc, 0xc2, 0xd5, 0xfb, 0xa8, 0xda,
-0xf5, 0x57, 0xa8, 0x18, 0xc0, 0xdf, 0xe7, 0xaa, 0x2a, 0xe0, 0x7c, 0x6f, 0x77, 0xb1, 0x26,
-0xba, 0xf9, 0x2e, 0x1d, 0x16, 0xcb, 0xb8, 0xa2, 0x44, 0xd5, 0x2f, 0x1a, 0x79, 0x74, 0x87,
-0x4b, 0x00, 0xc9, 0x4a, 0x3a, 0x65, 0x8f, 0xe6, 0x5d, 0xe5, 0x0a, 0x77, 0xd8, 0x1a, 0x14,
-0x41, 0x75, 0xb1, 0xe2, 0x50, 0x2c, 0x93, 0x38, 0x2b, 0x6d, 0xf3, 0xf6, 0xdb, 0x1f, 0xcd,
-0xff, 0x14, 0x70, 0xe7, 0x16, 0xe8, 0x3d, 0xf0, 0xe3, 0xbc, 0x5e, 0xb6, 0x3f, 0xcc, 0x81,
-0x24, 0x67, 0xf3, 0x97, 0x3b, 0xfe, 0x3a, 0x96, 0x85, 0xdf, 0xe4, 0x6e, 0x3c, 0x85, 0x05,
-0x0e, 0xa3, 0x2b, 0x07, 0xc8, 0xbf, 0xe5, 0x13, 0x82, 0x62, 0x08, 0x61, 0x69, 0x4b, 0x47,
-0x62, 0x73, 0x44, 0x64, 0x8e, 0xe2, 0x91, 0xa6, 0x9a, 0xb7, 0xe9, 0x04, 0xb6, 0x54, 0x0c,
-0xc5, 0xa9, 0x47, 0xa6, 0xc9, 0x08, 0xfe, 0x4e, 0xa6, 0xcc, 0x8a, 0x5b, 0x90, 0x6f, 0x2b,
-0x3f, 0xb6, 0x0a, 0x96, 0xc0, 0x78, 0x58, 0x3c, 0x76, 0x6d, 0x94, 0x1a, 0xe4, 0x4e, 0xb8,
-0x38, 0xbb, 0xf5, 0xeb, 0x29, 0xd8, 0xb0, 0xf3, 0x15, 0x1e, 0x99, 0x96, 0x3c, 0x5d, 0x63,
-0xd5, 0xb1, 0xad, 0x52, 0xb8, 0x55, 0x70, 0x75, 0x3e, 0x1a, 0xd5, 0xda, 0xf6, 0x7a, 0x48,
-0x7d, 0x44, 0x41, 0xf9, 0x11, 0xce, 0xd7, 0xca, 0xa5, 0x3d, 0x7a, 0x79, 0x7e, 0x7d, 0x25,
-0x1b, 0x77, 0xbc, 0xf7, 0xc7, 0x0f, 0x84, 0x95, 0x10, 0x92, 0x67, 0x15, 0x11, 0x5a, 0x5e,
-0x41, 0x66, 0x0f, 0x38, 0x03, 0xb2, 0xf1, 0x5d, 0xf8, 0xab, 0xc0, 0x02, 0x76, 0x84, 0x28,
-0xf4, 0x9d, 0x56, 0x46, 0x60, 0x20, 0xdb, 0x68, 0xa7, 0xbb, 0xee, 0xac, 0x15, 0x01, 0x2f,
-0x20, 0x09, 0xdb, 0xc0, 0x16, 0xa1, 0x89, 0xf9, 0x94, 0x59, 0x00, 0xc1, 0x76, 0xbf, 0xc1,
-0x4d, 0x5d, 0x2d, 0xa9, 0x85, 0x2c, 0xd6, 0xd3, 0x14, 0xcc, 0x02, 0xc3, 0xc2, 0xfa, 0x6b,
-0xb7, 0xa6, 0xef, 0xdd, 0x12, 0x26, 0xa4, 0x63, 0xe3, 0x62, 0xbd, 0x56, 0x8a, 0x52, 0x2b,
-0xb9, 0xdf, 0x09, 0xbc, 0x0e, 0x97, 0xa9, 0xb0, 0x82, 0x46, 0x08, 0xd5, 0x1a, 0x8e, 0x1b,
-0xa7, 0x90, 0x98, 0xb9, 0xbb, 0x3c, 0x17, 0x9a, 0xf2, 0x82, 0xba, 0x64, 0x0a, 0x7f, 0xca,
-0x5a, 0x8c, 0x7c, 0xd3, 0x79, 0x09, 0x5b, 0x26, 0xbb, 0xbd, 0x25, 0xdf, 0x3d, 0x6f, 0x9a,
-0x8f, 0xee, 0x21, 0x66, 0xb0, 0x8d, 0x84, 0x4c, 0x91, 0x45, 0xd4, 0x77, 0x4f, 0xb3, 0x8c,
-0xbc, 0xa8, 0x99, 0xaa, 0x19, 0x53, 0x7c, 0x02, 0x87, 0xbb, 0x0b, 0x7c, 0x1a, 0x2d, 0xdf,
-0x48, 0x44, 0x06, 0xd6, 0x7d, 0x0c, 0x2d, 0x35, 0x76, 0xae, 0xc4, 0x5f, 0x71, 0x85, 0x97,
-0xc4, 0x3d, 0xef, 0x52, 0xbe, 0x00, 0xe4, 0xcd, 0x49, 0xd1, 0xd1, 0x1c, 0x3c, 0xd0, 0x1c,
-0x42, 0xaf, 0xd4, 0xbd, 0x58, 0x34, 0x07, 0x32, 0xee, 0xb9, 0xb5, 0xea, 0xff, 0xd7, 0x8c,
-0x0d, 0x2e, 0x2f, 0xaf, 0x87, 0xbb, 0xe6, 0x52, 0x71, 0x22, 0xf5, 0x25, 0x17, 0xa1, 0x82,
-0x04, 0xc2, 0x4a, 0xbd, 0x57, 0xc6, 0xab, 0xc8, 0x35, 0x0c, 0x3c, 0xd9, 0xc2, 0x43, 0xdb,
-0x27, 0x92, 0xcf, 0xb8, 0x25, 0x60, 0xfa, 0x21, 0x3b, 0x04, 0x52, 0xc8, 0x96, 0xba, 0x74,
-0xe3, 0x67, 0x3e, 0x8e, 0x8d, 0x61, 0x90, 0x92, 0x59, 0xb6, 0x1a, 0x1c, 0x5e, 0x21, 0xc1,
-0x65, 0xe5, 0xa6, 0x34, 0x05, 0x6f, 0xc5, 0x60, 0xb1, 0x83, 0xc1, 0xd5, 0xd5, 0xed, 0xd9,
-0xc7, 0x11, 0x7b, 0x49, 0x7a, 0xf9, 0xf9, 0x84, 0x47, 0x9b, 0xe2, 0xa5, 0x82, 0xe0, 0xc2,
-0x88, 0xd0, 0xb2, 0x58, 0x88, 0x7f, 0x45, 0x09, 0x67, 0x74, 0x61, 0xbf, 0xe6, 0x40, 0xe2,
-0x9d, 0xc2, 0x47, 0x05, 0x89, 0xed, 0xcb, 0xbb, 0xb7, 0x27, 0xe7, 0xdc, 0x7a, 0xfd, 0xbf,
-0xa8, 0xd0, 0xaa, 0x10, 0x39, 0x3c, 0x20, 0xf0, 0xd3, 0x6e, 0xb1, 0x72, 0xf8, 0xe6, 0x0f,
-0xef, 0x37, 0xe5, 0x09, 0x33, 0x5a, 0x83, 0x43, 0x80, 0x4f, 0x65, 0x2f, 0x7c, 0x8c, 0x6a,
-0xa0, 0x82, 0x0c, 0xd4, 0xd4, 0xfa, 0x81, 0x60, 0x3d, 0xdf, 0x06, 0xf1, 0x5f, 0x08, 0x0d,
-0x6d, 0x43, 0xf2, 0xe3, 0x11, 0x7d, 0x80, 0x32, 0xc5, 0xfb, 0xc5, 0xd9, 0x27, 0xec, 0xc6,
-0x4e, 0x65, 0x27, 0x76, 0x87, 0xa6, 0xee, 0xee, 0xd7, 0x8b, 0xd1, 0xa0, 0x5c, 0xb0, 0x42,
-0x13, 0x0e, 0x95, 0x4a, 0xf2, 0x06, 0xc6, 0x43, 0x33, 0xf4, 0xc7, 0xf8, 0xe7, 0x1f, 0xdd,
-0xe4, 0x46, 0x4a, 0x70, 0x39, 0x6c, 0xd0, 0xed, 0xca, 0xbe, 0x60, 0x3b, 0xd1, 0x7b, 0x57,
-0x48, 0xe5, 0x3a, 0x79, 0xc1, 0x69, 0x33, 0x53, 0x1b, 0x80, 0xb8, 0x91, 0x7d, 0xb4, 0xf6,
-0x17, 0x1a, 0x1d, 0x5a, 0x32, 0xd6, 0xcc, 0x71, 0x29, 0x3f, 0x28, 0xbb, 0xf3, 0x5e, 0x71,
-0xb8, 0x43, 0xaf, 0xf8, 0xb9, 0x64, 0xef, 0xc4, 0xa5, 0x6c, 0x08, 0x53, 0xc7, 0x00, 0x10,
-0x39, 0x4f, 0xdd, 0xe4, 0xb6, 0x19, 0x27, 0xfb, 0xb8, 0xf5, 0x32, 0x73, 0xe5, 0xcb, 0x32
-};
-
-/*
-====================
-COM_BlockSequenceCRCByte
-
-For proxy protecting
-====================
-*/
-byte COM_BlockSequenceCRCByte (byte *base, int length, int sequence)
-{
- int n;
- byte *p;
- int x;
- byte chkb[60 + 4];
- unsigned short crc;
-
-
- if (sequence < 0)
- Sys_Error("sequence < 0, this shouldn't happen\n");
-
- p = chktbl + (sequence % (sizeof(chktbl) - 4));
-
- if (length > 60)
- length = 60;
- memcpy (chkb, base, length);
-
- chkb[length] = p[0];
- chkb[length+1] = p[1];
- chkb[length+2] = p[2];
- chkb[length+3] = p[3];
-
- length += 4;
-
- crc = CRC_Block(chkb, length);
-
- for (x=0, n=0; n<length; n++)
- x += chkb[n];
-
- crc = (crc ^ x) & 0xff;
-
- return crc;
-}
-
-//========================================================
-
-float qfrand(void)
-{
- return (rand()&32767)* (1.0/32767);
-}
-
-float crand(void)
-{
- return (rand()&32767)* (2.0/32767) - 1;
-}
-
-void Key_Init (void);
-void SCR_EndLoadingPlaque (void);
-
-/*
-=============
-Com_Error_f
-
-Just throw a fatal error to
-test error shutdown procedures
-=============
-*/
-void Com_Error_f (void)
-{
- Com_Error (ERR_FATAL, "%s", Cmd_Argv(1));
-}
-
-
-/*
-=================
-Qcommon_Init
-=================
-*/
-void Qcommon_Init (int argc, char **argv)
-{
- char *s;
-
- if (setjmp (abortframe) )
- Sys_Error ("Error during initialization");
-
- z_chain.next = z_chain.prev = &z_chain;
-
- // prepare enough of the subsystems to handle
- // cvar and command buffer management
- COM_InitArgv (argc, argv);
-
- Swap_Init ();
- Cbuf_Init ();
-
- Cmd_Init ();
- Cvar_Init ();
-
- Key_Init ();
-
- // we need to add the early commands twice, because
- // a basedir or cddir needs to be set before execing
- // config files, but we want other parms to override
- // the settings of the config files
- Cbuf_AddEarlyCommands (false);
- Cbuf_Execute ();
-
- FS_InitFilesystem ();
-
- Cbuf_AddText ("exec default.cfg\n");
- Cbuf_AddText ("exec config.cfg\n");
-
- Cbuf_AddEarlyCommands (true);
- Cbuf_Execute ();
-
- //
- // init commands and vars
- //
- Cmd_AddCommand ("z_stats", Z_Stats_f);
- Cmd_AddCommand ("error", Com_Error_f);
-
- host_speeds = Cvar_Get ("host_speeds", "0", 0);
- log_stats = Cvar_Get ("log_stats", "0", 0);
- developer = Cvar_Get ("developer", "0", 0);
- timescale = Cvar_Get ("timescale", "1", 0);
- fixedtime = Cvar_Get ("fixedtime", "0", 0);
- logfile_active = Cvar_Get ("logfile", "0", 0);
- showtrace = Cvar_Get ("showtrace", "0", 0);
-#ifdef DEDICATED_ONLY
- dedicated = Cvar_Get ("dedicated", "1", CVAR_NOSET);
-#else
- dedicated = Cvar_Get ("dedicated", "0", CVAR_NOSET);
-#endif
-
- s = va("%4.2f 9front Nov 30 1997 9front", VERSION);
- Cvar_Get ("version", s, CVAR_SERVERINFO|CVAR_NOSET);
-
-
- if (dedicated->value)
- Cmd_AddCommand ("quit", Com_Quit);
-
- Sys_Init ();
-
- NET_Init ();
- Netchan_Init ();
-
- SV_Init ();
- CL_Init ();
-
- // add + commands from command line
- if (!Cbuf_AddLateCommands ())
- { // if the user didn't give any commands, run default action
- if (!dedicated->value)
- Cbuf_AddText ("d1\n");
- else
- Cbuf_AddText ("dedicated_start\n");
- Cbuf_Execute ();
- }
- else
- { // the user asked for something explicit
- // so drop the loading plaque
- SCR_EndLoadingPlaque ();
- }
-
- Com_Printf ("====== Quake2 Initialized ======\n\n");
-}
-
-/*
-=================
-Qcommon_Frame
-=================
-*/
-void Qcommon_Frame (int msec)
-{
- char *s;
- int time_before = 0, time_between = 0, time_after = 0;
-
- if (setjmp (abortframe) )
- return; // an ERR_DROP was thrown
-
- if ( log_stats->modified )
- {
- log_stats->modified = false;
- if ( log_stats->value )
- {
- if ( log_stats_file )
- {
- fclose( log_stats_file );
- log_stats_file = 0;
- }
- log_stats_file = fopen( "stats.log", "w" );
- if ( log_stats_file )
- fprintf( log_stats_file, "entities,dlights,parts,frame time\n" );
- }
- else
- {
- if ( log_stats_file )
- {
- fclose( log_stats_file );
- log_stats_file = 0;
- }
- }
- }
-
- if (fixedtime->value)
- msec = fixedtime->value;
- else if (timescale->value)
- {
- msec *= timescale->value;
- if (msec < 1)
- msec = 1;
- }
-
- if (showtrace->value)
- {
- extern int c_traces, c_brush_traces;
- extern int c_pointcontents;
-
- Com_Printf ("%4i traces %4i points\n", c_traces, c_pointcontents);
- c_traces = 0;
- c_brush_traces = 0;
- c_pointcontents = 0;
- }
-
- do
- {
- s = Sys_ConsoleInput ();
- if (s)
- Cbuf_AddText (va("%s\n",s));
- } while (s);
- Cbuf_Execute ();
-
- if (host_speeds->value)
- time_before = Sys_Milliseconds ();
-
- SV_Frame (msec);
-
- if (host_speeds->value)
- time_between = Sys_Milliseconds ();
-
- CL_Frame (msec);
-
- if (host_speeds->value)
- time_after = Sys_Milliseconds ();
-
-
- if (host_speeds->value)
- {
- int all, sv, gm, cl, rf;
-
- all = time_after - time_before;
- sv = time_between - time_before;
- cl = time_after - time_between;
- gm = time_after_game - time_before_game;
- rf = time_after_ref - time_before_ref;
- sv -= gm;
- cl -= rf;
- Com_Printf ("all:%3i sv:%3i gm:%3i cl:%3i rf:%3i\n",
- all, sv, gm, cl, rf);
- }
-}
--- a/qcommon/crc.c
+++ /dev/null
@@ -1,74 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-// this is a 16 bit, non-reflected CRC using the polynomial 0x1021
-// and the initial and final xor values shown below... in other words, the
-// CCITT standard CRC used by XMODEM
-
-#define CRC_INIT_VALUE 0xffff
-#define CRC_XOR_VALUE 0x0000
-
-static unsigned short crctable[256] =
-{
- 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
- 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
- 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
- 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
- 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
- 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
- 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
- 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
- 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
- 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
- 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
- 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
- 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
- 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
- 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
- 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
- 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
- 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
- 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
- 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
- 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
- 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
- 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
- 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
- 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
- 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
- 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
- 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
- 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
- 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
- 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
- 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
-};
-
-void CRC_Init(unsigned short *crcvalue)
-{
- *crcvalue = CRC_INIT_VALUE;
-}
-
-void CRC_ProcessByte(unsigned short *crcvalue, byte data)
-{
- *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
-}
-
-unsigned short CRC_Value(unsigned short crcvalue)
-{
- return crcvalue ^ CRC_XOR_VALUE;
-}
-
-unsigned short CRC_Block (byte *start, int count)
-{
- unsigned short crc;
-
- CRC_Init (&crc);
- while (count--)
- crc = (crc << 8) ^ crctable[(crc >> 8) ^ *start++];
-
- return crc;
-}
-
--- a/qcommon/crc.h
+++ /dev/null
@@ -1,4 +1,0 @@
-void CRC_Init(unsigned short *crcvalue);
-void CRC_ProcessByte(unsigned short *crcvalue, byte data);
-unsigned short CRC_Value(unsigned short crcvalue);
-unsigned short CRC_Block (byte *start, int count);
--- a/qcommon/cvar.c
+++ /dev/null
@@ -1,511 +1,0 @@
-// cvar.c -- dynamic variable tracking
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-cvar_t *cvar_vars;
-
-/*
-============
-Cvar_InfoValidate
-============
-*/
-static qboolean Cvar_InfoValidate (char *s)
-{
- if (strstr (s, "\\"))
- return false;
- if (strstr (s, "\""))
- return false;
- if (strstr (s, ";"))
- return false;
- return true;
-}
-
-/*
-============
-Cvar_FindVar
-============
-*/
-static cvar_t *Cvar_FindVar (char *var_name)
-{
- cvar_t *var;
-
- for (var=cvar_vars ; var ; var=var->next)
- if (!strcmp (var_name, var->name))
- return var;
-
- return NULL;
-}
-
-/*
-============
-Cvar_VariableValue
-============
-*/
-float Cvar_VariableValue (char *var_name)
-{
- cvar_t *var;
-
- var = Cvar_FindVar (var_name);
- if (!var)
- return 0;
- return atof (var->string);
-}
-
-
-/*
-============
-Cvar_VariableString
-============
-*/
-char *Cvar_VariableString (char *var_name)
-{
- cvar_t *var;
-
- var = Cvar_FindVar (var_name);
- if (!var)
- return "";
- return var->string;
-}
-
-
-/*
-============
-Cvar_CompleteVariable
-============
-*/
-char *Cvar_CompleteVariable (char *partial)
-{
- cvar_t *cvar;
- int len;
-
- len = strlen(partial);
-
- if (!len)
- return NULL;
-
- // check exact match
- for (cvar=cvar_vars ; cvar ; cvar=cvar->next)
- if (!strcmp (partial,cvar->name))
- return cvar->name;
-
- // check partial match
- for (cvar=cvar_vars ; cvar ; cvar=cvar->next)
- if (!strncmp (partial,cvar->name, len))
- return cvar->name;
-
- return NULL;
-}
-
-
-/*
-============
-Cvar_Get
-
-If the variable already exists, the value will not be set
-The flags will be or'ed in if the variable exists.
-============
-*/
-cvar_t *Cvar_Get (char *var_name, char *var_value, int flags)
-{
- cvar_t *var;
-
- if (flags & (CVAR_USERINFO | CVAR_SERVERINFO))
- {
- if (!Cvar_InfoValidate (var_name))
- {
- Com_Printf("invalid info cvar name\n");
- return NULL;
- }
- }
-
- var = Cvar_FindVar (var_name);
- if (var)
- {
- var->flags |= flags;
- return var;
- }
-
- if (!var_value)
- return NULL;
-
- if (flags & (CVAR_USERINFO | CVAR_SERVERINFO))
- {
- if (!Cvar_InfoValidate (var_value))
- {
- Com_Printf("invalid info cvar value\n");
- return NULL;
- }
- }
-
- var = Z_Malloc (sizeof(*var));
- var->name = CopyString (var_name);
- var->string = CopyString (var_value);
- var->modified = true;
- var->value = atof (var->string);
-
- // link the variable in
- var->next = cvar_vars;
- cvar_vars = var;
-
- var->flags = flags;
-
- return var;
-}
-
-/*
-============
-Cvar_Set2
-============
-*/
-cvar_t *Cvar_Set2 (char *var_name, char *value, qboolean force)
-{
- cvar_t *var;
-
- var = Cvar_FindVar (var_name);
- if (!var)
- { // create it
- return Cvar_Get (var_name, value, 0);
- }
-
- if (var->flags & (CVAR_USERINFO | CVAR_SERVERINFO))
- {
- if (!Cvar_InfoValidate (value))
- {
- Com_Printf("invalid info cvar value\n");
- return var;
- }
- }
-
- if (!force)
- {
- if (var->flags & CVAR_NOSET)
- {
- Com_Printf ("%s is write protected.\n", var_name);
- return var;
- }
-
- if (var->flags & CVAR_LATCH)
- {
- if (var->latched_string)
- {
- if (strcmp(value, var->latched_string) == 0)
- return var;
- Z_Free (var->latched_string);
- }
- else
- {
- if (strcmp(value, var->string) == 0)
- return var;
- }
-
- if (Com_ServerState())
- {
- Com_Printf ("%s will be changed for next game.\n", var_name);
- var->latched_string = CopyString(value);
- }
- else
- {
- var->string = CopyString(value);
- var->value = atof (var->string);
- if (!strcmp(var->name, "game"))
- {
- FS_SetGamedir (var->string);
- FS_ExecAutoexec ();
- }
- }
- return var;
- }
- }
- else
- {
- if (var->latched_string)
- {
- Z_Free (var->latched_string);
- var->latched_string = NULL;
- }
- }
-
- if (!strcmp(value, var->string))
- return var; // not changed
-
- var->modified = true;
-
- if (var->flags & CVAR_USERINFO)
- userinfo_modified = true; // transmit at next oportunity
-
- Z_Free (var->string); // free the old value string
-
- var->string = CopyString(value);
- var->value = atof (var->string);
-
- return var;
-}
-
-/*
-============
-Cvar_ForceSet
-============
-*/
-cvar_t *Cvar_ForceSet (char *var_name, char *value)
-{
- return Cvar_Set2 (var_name, value, true);
-}
-
-/*
-============
-Cvar_Set
-============
-*/
-cvar_t *Cvar_Set (char *var_name, char *value)
-{
- return Cvar_Set2 (var_name, value, false);
-}
-
-/*
-============
-Cvar_FullSet
-============
-*/
-cvar_t *Cvar_FullSet (char *var_name, char *value, int flags)
-{
- cvar_t *var;
-
- var = Cvar_FindVar (var_name);
- if (!var)
- { // create it
- return Cvar_Get (var_name, value, flags);
- }
-
- var->modified = true;
-
- if (var->flags & CVAR_USERINFO)
- userinfo_modified = true; // transmit at next oportunity
-
- Z_Free (var->string); // free the old value string
-
- var->string = CopyString(value);
- var->value = atof (var->string);
- var->flags = flags;
-
- return var;
-}
-
-/*
-============
-Cvar_SetValue
-============
-*/
-void Cvar_SetValue (char *var_name, float value)
-{
- char val[32];
-
- if (value == (int)value)
- Com_sprintf (val, sizeof(val), "%i",(int)value);
- else
- Com_sprintf (val, sizeof(val), "%f",value);
- Cvar_Set (var_name, val);
-}
-
-
-/*
-============
-Cvar_GetLatchedVars
-
-Any variables with latched values will now be updated
-============
-*/
-void Cvar_GetLatchedVars (void)
-{
- cvar_t *var;
-
- for (var = cvar_vars ; var ; var = var->next)
- {
- if (!var->latched_string)
- continue;
- Z_Free (var->string);
- var->string = var->latched_string;
- var->latched_string = NULL;
- var->value = atof(var->string);
- if (!strcmp(var->name, "game"))
- {
- FS_SetGamedir (var->string);
- FS_ExecAutoexec ();
- }
- }
-}
-
-/*
-============
-Cvar_Command
-
-Handles variable inspection and changing from the console
-============
-*/
-qboolean Cvar_Command (void)
-{
- cvar_t *v;
-
-// check variables
- v = Cvar_FindVar (Cmd_Argv(0));
- if (!v)
- return false;
-
-// perform a variable print or set
- if (Cmd_Argc() == 1)
- {
- Com_Printf ("\"%s\" is \"%s\"\n", v->name, v->string);
- return true;
- }
-
- Cvar_Set (v->name, Cmd_Argv(1));
- return true;
-}
-
-
-/*
-============
-Cvar_Set_f
-
-Allows setting and defining of arbitrary cvars from console
-============
-*/
-void Cvar_Set_f (void)
-{
- int c;
- int flags;
-
- c = Cmd_Argc();
- if (c != 3 && c != 4)
- {
- Com_Printf ("usage: set <variable> <value> [u / s]\n");
- return;
- }
-
- if (c == 4)
- {
- if (!strcmp(Cmd_Argv(3), "u"))
- flags = CVAR_USERINFO;
- else if (!strcmp(Cmd_Argv(3), "s"))
- flags = CVAR_SERVERINFO;
- else
- {
- Com_Printf ("flags can only be 'u' or 's'\n");
- return;
- }
- Cvar_FullSet (Cmd_Argv(1), Cmd_Argv(2), flags);
- }
- else
- Cvar_Set (Cmd_Argv(1), Cmd_Argv(2));
-}
-
-
-/*
-============
-Cvar_WriteVariables
-
-Appends lines containing "set variable value" for all variables
-with the archive flag set to true.
-============
-*/
-void Cvar_WriteVariables (char *path)
-{
- cvar_t *var;
- char buffer[1024];
- FILE *f;
-
- f = fopen (path, "a");
- for (var = cvar_vars ; var ; var = var->next)
- {
- if (var->flags & CVAR_ARCHIVE)
- {
- Com_sprintf (buffer, sizeof(buffer), "set %s \"%s\"\n", var->name, var->string);
- fprintf (f, "%s", buffer);
- }
- }
- fclose (f);
-}
-
-/*
-============
-Cvar_List_f
-
-============
-*/
-void Cvar_List_f (void)
-{
- cvar_t *var;
- int i;
-
- i = 0;
- for (var = cvar_vars ; var ; var = var->next, i++)
- {
- if (var->flags & CVAR_ARCHIVE)
- Com_Printf ("*");
- else
- Com_Printf (" ");
- if (var->flags & CVAR_USERINFO)
- Com_Printf ("U");
- else
- Com_Printf (" ");
- if (var->flags & CVAR_SERVERINFO)
- Com_Printf ("S");
- else
- Com_Printf (" ");
- if (var->flags & CVAR_NOSET)
- Com_Printf ("-");
- else if (var->flags & CVAR_LATCH)
- Com_Printf ("L");
- else
- Com_Printf (" ");
- Com_Printf (" %s \"%s\"\n", var->name, var->string);
- }
- Com_Printf ("%i cvars\n", i);
-}
-
-
-qboolean userinfo_modified;
-
-
-char *Cvar_BitInfo (int bit)
-{
- static char info[MAX_INFO_STRING];
- cvar_t *var;
-
- info[0] = 0;
-
- for (var = cvar_vars ; var ; var = var->next)
- {
- if (var->flags & bit)
- Info_SetValueForKey (info, var->name, var->string);
- }
- return info;
-}
-
-// returns an info string containing all the CVAR_USERINFO cvars
-char *Cvar_Userinfo (void)
-{
- return Cvar_BitInfo (CVAR_USERINFO);
-}
-
-// returns an info string containing all the CVAR_SERVERINFO cvars
-char *Cvar_Serverinfo (void)
-{
- return Cvar_BitInfo (CVAR_SERVERINFO);
-}
-
-/*
-============
-Cvar_Init
-
-Reads in all archived cvars
-============
-*/
-void Cvar_Init (void)
-{
- Cmd_AddCommand ("set", Cvar_Set_f);
- Cmd_AddCommand ("cvarlist", Cvar_List_f);
-
-}
--- a/qcommon/files.c
+++ /dev/null
@@ -1,859 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-// define this to dissalow any data but the demo pak file
-//#define NO_ADDONS
-
-// if a packfile directory differs from this, it is assumed to be hacked
-// Full version
-#define PAK0_CHECKSUM 0x40e614e0
-// Demo
-//#define PAK0_CHECKSUM 0xb2c6d7ea
-// OEM
-//#define PAK0_CHECKSUM 0x78e135c
-
-/*
-=============================================================================
-
-QUAKE FILESYSTEM
-
-=============================================================================
-*/
-
-
-//
-// in memory
-//
-
-typedef struct
-{
- char name[MAX_QPATH];
- int filepos, filelen;
-} packfile_t;
-
-typedef struct pack_s
-{
- char filename[MAX_OSPATH];
- FILE *handle;
- int numfiles;
- packfile_t *files;
-} pack_t;
-
-char fs_gamedir[MAX_OSPATH];
-cvar_t *fs_basedir;
-cvar_t *fs_cddir;
-cvar_t *fs_gamedirvar;
-
-typedef struct filelink_s
-{
- struct filelink_s *next;
- char *from;
- int fromlength;
- char *to;
-} filelink_t;
-
-filelink_t *fs_links;
-
-typedef struct searchpath_s
-{
- char filename[MAX_OSPATH];
- pack_t *pack; // only one of filename / pack will be used
- struct searchpath_s *next;
-} searchpath_t;
-
-searchpath_t *fs_searchpaths;
-searchpath_t *fs_base_searchpaths; // without gamedirs
-
-
-/*
-
-All of Quake's data access is through a hierchal file system, but the contents of the file system can be transparently merged from several sources.
-
-The "base directory" is the path to the directory holding the quake.exe and all game directories. The sys_* files pass this to host_init in quakeparms_t->basedir. This can be overridden with the "-basedir" command line parm to allow code debugging in a different directory. The base directory is
-only used during filesystem initialization.
-
-The "game directory" is the first tree on the search path and directory that all generated files (savegames, screenshots, demos, config files) will be saved to. This can be overridden with the "-game" command line parameter. The game directory can never be changed while quake is executing. This is a precacution against having a malicious server instruct clients to write files over areas they shouldn't.
-
-*/
-
-
-/*
-================
-FS_filelength
-================
-*/
-int FS_filelength (FILE *f)
-{
- int pos;
- int end;
-
- pos = ftell (f);
- fseek (f, 0, SEEK_END);
- end = ftell (f);
- fseek (f, pos, SEEK_SET);
-
- return end;
-}
-
-
-/*
-============
-FS_CreatePath
-
-Creates any directories needed to store the given filename
-============
-*/
-void FS_CreatePath (char *path)
-{
- char *ofs;
-
- for (ofs = path+1 ; *ofs ; ofs++)
- {
- if (*ofs == '/')
- { // create the directory
- *ofs = 0;
- Sys_Mkdir (path);
- *ofs = '/';
- }
- }
-}
-
-
-/*
-==============
-FS_FCloseFile
-
-For some reason, other dll's can't just cal fclose()
-on files returned by FS_FOpenFile...
-==============
-*/
-void FS_FCloseFile (FILE *f)
-{
- fclose (f);
-}
-
-
-// RAFAEL
-/*
- Developer_searchpath
-*/
-int Developer_searchpath (int /*who*/)
-{
-
- // PMM - warning removal
-// char *start;
- searchpath_t *search;
-
- for (search = fs_searchpaths ; search ; search = search->next)
- {
- if (strstr (search->filename, "xatrix"))
- return 1;
-
- if (strstr (search->filename, "rogue"))
- return 2;
-/*
- start = strchr (search->filename, ch);
-
- if (start == NULL)
- continue;
-
- if (strcmp (start ,"xatrix") == 0)
- return (1);
-*/
- }
- return (0);
-
-}
-
-
-/*
-===========
-FS_FOpenFile
-
-Finds the file in the search path.
-returns filesize and an open FILE *
-Used for streaming data out of either a pak file or
-a seperate file.
-===========
-*/
-int file_from_pak = 0;
-#ifndef NO_ADDONS
-int FS_FOpenFile (char *filename, FILE **file)
-{
- searchpath_t *search;
- char netpath[MAX_OSPATH];
- pack_t *pak;
- int i;
- filelink_t *link;
-
- file_from_pak = 0;
-
- // check for links first
- for (link = fs_links ; link ; link=link->next)
- {
- if (!strncmp (filename, link->from, link->fromlength))
- {
- Com_sprintf (netpath, sizeof(netpath), "%s%s",link->to, filename+link->fromlength);
- *file = fopen (netpath, "rb");
- if (*file)
- {
- Com_DPrintf ("link file: %s\n",netpath);
- return FS_filelength (*file);
- }
- return -1;
- }
- }
-
-//
-// search through the path, one element at a time
-//
- for (search = fs_searchpaths ; search ; search = search->next)
- {
- // is the element a pak file?
- if (search->pack)
- {
- // look through all the pak file elements
- pak = search->pack;
- for (i=0 ; i<pak->numfiles ; i++)
- if (!cistrcmp (pak->files[i].name, filename))
- { // found it!
- file_from_pak = 1;
- Com_DPrintf ("PackFile: %s : %s\n",pak->filename, filename);
- // open a new file on the pakfile
- *file = fopen (pak->filename, "rb");
- if (!*file)
- Com_Error (ERR_FATAL, "Couldn't reopen %s", pak->filename);
- fseek (*file, pak->files[i].filepos, SEEK_SET);
- return pak->files[i].filelen;
- }
- }
- else
- {
- // check a file in the directory tree
-
- Com_sprintf (netpath, sizeof(netpath), "%s/%s",search->filename, filename);
-
- *file = fopen (netpath, "rb");
- if (!*file)
- continue;
-
- Com_DPrintf ("FindFile: %s\n",netpath);
-
- return FS_filelength (*file);
- }
-
- }
-
- Com_DPrintf ("FindFile: can't find %s\n", filename);
-
- *file = NULL;
- return -1;
-}
-
-#else
-
-// this is just for demos to prevent add on hacking
-
-int FS_FOpenFile (char *filename, FILE **file)
-{
- searchpath_t *search;
- char netpath[MAX_OSPATH];
- pack_t *pak;
- int i;
-
- file_from_pak = 0;
-
- // get config from directory, everything else from pak
- if (!strcmp(filename, "config.cfg") || !strncmp(filename, "players/", 8))
- {
- Com_sprintf (netpath, sizeof(netpath), "%s/%s",FS_Gamedir(), filename);
-
- *file = fopen (netpath, "rb");
- if (!*file)
- return -1;
-
- Com_DPrintf ("FindFile: %s\n",netpath);
-
- return FS_filelength (*file);
- }
-
- for (search = fs_searchpaths ; search ; search = search->next)
- if (search->pack)
- break;
- if (!search)
- {
- *file = NULL;
- return -1;
- }
-
- pak = search->pack;
- for (i=0 ; i<pak->numfiles ; i++)
- if (!cistrcmp (pak->files[i].name, filename))
- { // found it!
- file_from_pak = 1;
- Com_DPrintf ("PackFile: %s : %s\n",pak->filename, filename);
- // open a new file on the pakfile
- *file = fopen (pak->filename, "rb");
- if (!*file)
- Com_Error (ERR_FATAL, "Couldn't reopen %s", pak->filename);
- fseek (*file, pak->files[i].filepos, SEEK_SET);
- return pak->files[i].filelen;
- }
-
- Com_DPrintf ("FindFile: can't find %s\n", filename);
-
- *file = NULL;
- return -1;
-}
-
-#endif
-
-
-/*
-=================
-FS_ReadFile
-
-Properly handles partial reads
-=================
-*/
-void CDAudio_Stop(void);
-#define MAX_READ 0x10000 // read in blocks of 64k
-void FS_Read (void *buffer, int len, FILE *f)
-{
- int block, remaining;
- int read;
- byte *buf;
- int tries;
-
- buf = (byte *)buffer;
-
- // read in chunks for progress bar
- remaining = len;
- tries = 0;
- while (remaining)
- {
- block = remaining;
- if (block > MAX_READ)
- block = MAX_READ;
- read = fread (buf, 1, block, f);
- if (read == 0)
- {
- // we might have been trying to read from a CD
- if (!tries)
- {
- tries = 1;
- CDAudio_Stop();
- }
- else
- Com_Error (ERR_FATAL, "FS_Read: 0 bytes read");
- }
-
- if (read == -1)
- Com_Error (ERR_FATAL, "FS_Read: -1 bytes read");
-
- // do some progress bar thing here...
-
- remaining -= read;
- buf += read;
- }
-}
-
-/*
-============
-FS_LoadFile
-
-Filename are reletive to the quake search path
-a null buffer will just return the file length without loading
-============
-*/
-int FS_LoadFile (char *path, void **buffer)
-{
- FILE *h;
- byte *buf;
- int len;
-
-// look for it in the filesystem or pack files
- len = FS_FOpenFile (path, &h);
- if (!h)
- {
- if (buffer)
- *buffer = NULL;
- return -1;
- }
-
- if (!buffer)
- {
- fclose (h);
- return len;
- }
-
- buf = Z_Malloc(len);
- *buffer = buf;
-
- FS_Read (buf, len, h);
-
- fclose (h);
-
- return len;
-}
-
-
-/*
-=============
-FS_FreeFile
-=============
-*/
-void FS_FreeFile (void *buffer)
-{
- Z_Free (buffer);
-}
-
-/*
-=================
-FS_LoadPackFile
-
-Takes an explicit (not game tree related) path to a pak file.
-
-Loads the header and directory, adding the files at the beginning
-of the list so they override previous pack files.
-=================
-*/
-pack_t *FS_LoadPackFile (char *packfile)
-{
- dpackheader_t header;
- int i;
- packfile_t *newfiles;
- int numpackfiles;
- pack_t *pack;
- FILE *packhandle;
- dpackfile_t info[MAX_FILES_IN_PACK];
- unsigned checksum;
-
- packhandle = fopen(packfile, "rb");
- if (!packhandle)
- return NULL;
-
- fread (&header, 1, sizeof(header), packhandle);
- if (LittleLong(header.ident) != IDPAKHEADER)
- Com_Error (ERR_FATAL, "%s is not a packfile", packfile);
- header.dirofs = LittleLong (header.dirofs);
- header.dirlen = LittleLong (header.dirlen);
-
- numpackfiles = header.dirlen / sizeof(dpackfile_t);
-
- if (numpackfiles > MAX_FILES_IN_PACK)
- Com_Error (ERR_FATAL, "%s has %i files", packfile, numpackfiles);
-
- newfiles = Z_Malloc (numpackfiles * sizeof(packfile_t));
-
- fseek (packhandle, header.dirofs, SEEK_SET);
- fread (info, 1, header.dirlen, packhandle);
-
-// crc the directory to check for modifications
- checksum = Com_BlockChecksum ((void *)info, header.dirlen);
-
-#ifdef NO_ADDONS
- if (checksum != PAK0_CHECKSUM)
- return NULL;
-#else
- USED(checksum);
-#endif
-// parse the directory
- for (i=0 ; i<numpackfiles ; i++)
- {
- strcpy (newfiles[i].name, info[i].name);
- newfiles[i].filepos = LittleLong(info[i].filepos);
- newfiles[i].filelen = LittleLong(info[i].filelen);
- }
-
- pack = Z_Malloc (sizeof (pack_t));
- strcpy (pack->filename, packfile);
- pack->handle = packhandle;
- pack->numfiles = numpackfiles;
- pack->files = newfiles;
-
- Com_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
- return pack;
-}
-
-
-/*
-================
-FS_AddGameDirectory
-
-Sets fs_gamedir, adds the directory to the head of the path,
-then loads and adds pak1.pak pak2.pak ...
-================
-*/
-void FS_AddGameDirectory (char *dir)
-{
- int i;
- searchpath_t *search;
- pack_t *pak;
- char pakfile[MAX_OSPATH];
-
- strcpy (fs_gamedir, dir);
-
- //
- // add the directory to the search path
- //
- search = Z_Malloc (sizeof(searchpath_t));
- strcpy (search->filename, dir);
- search->next = fs_searchpaths;
- fs_searchpaths = search;
-
- //
- // add any pak files in the format pak0.pak pak1.pak, ...
- //
- for (i=0; i<10; i++)
- {
- Com_sprintf (pakfile, sizeof(pakfile), "%s/pak%i.pak", dir, i);
- pak = FS_LoadPackFile (pakfile);
- if (!pak)
- continue;
- search = Z_Malloc (sizeof(searchpath_t));
- search->pack = pak;
- search->next = fs_searchpaths;
- fs_searchpaths = search;
- }
-
-
-}
-
-/*
-============
-FS_Gamedir
-
-Called to find where to write a file (demos, savegames, etc)
-============
-*/
-char *FS_Gamedir (void)
-{
- return fs_gamedir;
-}
-
-/*
-=============
-FS_ExecAutoexec
-=============
-*/
-void FS_ExecAutoexec (void)
-{
- char *dir;
- char name [MAX_QPATH];
-
- dir = Cvar_VariableString("gamedir");
- if (*dir)
- Com_sprintf(name, sizeof(name), "%s/%s/autoexec.cfg", fs_basedir->string, dir);
- else
- Com_sprintf(name, sizeof(name), "%s/%s/autoexec.cfg", fs_basedir->string, BASEDIRNAME);
- if (Sys_FindFirst(name, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM))
- Cbuf_AddText ("exec autoexec.cfg\n");
- Sys_FindClose();
-}
-
-
-/*
-================
-FS_SetGamedir
-
-Sets the gamedir and path to a different directory.
-================
-*/
-void FS_SetGamedir (char *dir)
-{
- searchpath_t *next;
-
- if (strstr(dir, "..") || strstr(dir, "/")
- || strstr(dir, "\\") || strstr(dir, ":") )
- {
- Com_Printf ("Gamedir should be a single filename, not a path\n");
- return;
- }
-
- //
- // free up any current game dir info
- //
- while (fs_searchpaths != fs_base_searchpaths)
- {
- if (fs_searchpaths->pack)
- {
- fclose (fs_searchpaths->pack->handle);
- Z_Free (fs_searchpaths->pack->files);
- Z_Free (fs_searchpaths->pack);
- }
- next = fs_searchpaths->next;
- Z_Free (fs_searchpaths);
- fs_searchpaths = next;
- }
-
- //
- // flush all data, so it will be forced to reload
- //
- if (dedicated && !dedicated->value)
- Cbuf_AddText ("vid_restart\nsnd_restart\n");
-
- Com_sprintf (fs_gamedir, sizeof(fs_gamedir), "%s/%s", fs_basedir->string, dir);
-
- if (!strcmp(dir,BASEDIRNAME) || (*dir == 0))
- {
- Cvar_FullSet ("gamedir", "", CVAR_SERVERINFO|CVAR_NOSET);
- Cvar_FullSet ("game", "", CVAR_LATCH|CVAR_SERVERINFO);
- }
- else
- {
- Cvar_FullSet ("gamedir", dir, CVAR_SERVERINFO|CVAR_NOSET);
- if (fs_cddir->string[0])
- FS_AddGameDirectory (va("%s/%s", fs_cddir->string, dir) );
- FS_AddGameDirectory (va("%s/%s", fs_basedir->string, dir) );
- }
-}
-
-
-/*
-================
-FS_Link_f
-
-Creates a filelink_t
-================
-*/
-void FS_Link_f (void)
-{
- filelink_t *l, **prev;
-
- if (Cmd_Argc() != 3)
- {
- Com_Printf ("USAGE: link <from> <to>\n");
- return;
- }
-
- // see if the link already exists
- prev = &fs_links;
- for (l=fs_links ; l ; l=l->next)
- {
- if (!strcmp (l->from, Cmd_Argv(1)))
- {
- Z_Free (l->to);
- if (!strlen(Cmd_Argv(2)))
- { // delete it
- *prev = l->next;
- Z_Free (l->from);
- Z_Free (l);
- return;
- }
- l->to = CopyString (Cmd_Argv(2));
- return;
- }
- prev = &l->next;
- }
-
- // create a new link
- l = Z_Malloc(sizeof(*l));
- l->next = fs_links;
- fs_links = l;
- l->from = CopyString(Cmd_Argv(1));
- l->fromlength = strlen(l->from);
- l->to = CopyString(Cmd_Argv(2));
-}
-
-/*
-** FS_ListFiles
-*/
-char **FS_ListFiles( char *findname, int *numfiles, unsigned musthave, unsigned canthave )
-{
- char *s;
- int nfiles = 0;
- char **list;
-
- s = Sys_FindFirst( findname, musthave, canthave );
- while ( s )
- {
- if ( s[strlen(s)-1] != '.' )
- nfiles++;
- s = Sys_FindNext( musthave, canthave );
- }
- Sys_FindClose ();
-
- if ( !nfiles )
- return NULL;
-
- nfiles++; // add space for a guard
- *numfiles = nfiles;
-
- list = malloc( sizeof( char * ) * nfiles );
- memset( list, 0, sizeof( char * ) * nfiles );
-
- s = Sys_FindFirst( findname, musthave, canthave );
- nfiles = 0;
- while ( s )
- {
- if ( s[strlen(s)-1] != '.' )
- {
- list[nfiles] = strdup( s );
- nfiles++;
- }
- s = Sys_FindNext( musthave, canthave );
- }
- Sys_FindClose ();
-
- return list;
-}
-
-/*
-** FS_Dir_f
-*/
-void FS_Dir_f( void )
-{
- char *path = NULL;
- char findname[1024];
- char wildcard[1024] = "*.*";
- char **dirnames;
- int ndirs;
-
- if ( Cmd_Argc() != 1 )
- {
- strcpy( wildcard, Cmd_Argv( 1 ) );
- }
-
- while ( ( path = FS_NextPath( path ) ) != NULL )
- {
- char *tmp = findname;
-
- Com_sprintf( findname, sizeof(findname), "%s/%s", path, wildcard );
-
- while ( *tmp != 0 )
- {
- if ( *tmp == '\\' )
- *tmp = '/';
- tmp++;
- }
- Com_Printf( "Directory of %s\n", findname );
- Com_Printf( "----\n" );
-
- if ( ( dirnames = FS_ListFiles( findname, &ndirs, 0, 0 ) ) != 0 )
- {
- int i;
-
- for ( i = 0; i < ndirs-1; i++ )
- {
- if ( strrchr( dirnames[i], '/' ) )
- Com_Printf( "%s\n", strrchr( dirnames[i], '/' ) + 1 );
- else
- Com_Printf( "%s\n", dirnames[i] );
-
- free( dirnames[i] );
- }
- free( dirnames );
- }
- Com_Printf( "\n" );
- };
-}
-
-/*
-============
-FS_Path_f
-
-============
-*/
-void FS_Path_f (void)
-{
- searchpath_t *s;
- filelink_t *l;
-
- Com_Printf ("Current search path:\n");
- for (s=fs_searchpaths ; s ; s=s->next)
- {
- if (s == fs_base_searchpaths)
- Com_Printf ("----------\n");
- if (s->pack)
- Com_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
- else
- Com_Printf ("%s\n", s->filename);
- }
-
- Com_Printf ("\nLinks:\n");
- for (l=fs_links ; l ; l=l->next)
- Com_Printf ("%s : %s\n", l->from, l->to);
-}
-
-/*
-================
-FS_NextPath
-
-Allows enumerating all of the directories in the search path
-================
-*/
-char *FS_NextPath (char *prevpath)
-{
- searchpath_t *s;
- char *prev;
-
- if (!prevpath)
- return fs_gamedir;
-
- prev = fs_gamedir;
- for (s=fs_searchpaths ; s ; s=s->next)
- {
- if (s->pack)
- continue;
- if (prevpath == prev)
- return s->filename;
- prev = s->filename;
- }
-
- return NULL;
-}
-
-
-/*
-================
-FS_InitFilesystem
-================
-*/
-void FS_InitFilesystem (void)
-{
- static char homedir[1024];
- char *home;
-
- Cmd_AddCommand ("path", FS_Path_f);
- Cmd_AddCommand ("link", FS_Link_f);
- Cmd_AddCommand ("dir", FS_Dir_f );
-
- //
- // basedir <path>
- // allows the game to run from outside the data tree
- //
- if(home = getenv("home")){
- snprint(homedir, sizeof homedir, "%s/lib/quake2", home);
- free(home);
- }else
- snprint(homedir, sizeof homedir, "/sys/lib/quake2");
- fs_basedir = Cvar_Get ("basedir", homedir, CVAR_NOSET);
-
- //
- // cddir <path>
- // Logically concatenates the cddir after the basedir for
- // allows the game to run from outside the data tree
- //
- fs_cddir = Cvar_Get ("cddir", "", CVAR_NOSET);
- if (fs_cddir->string[0])
- FS_AddGameDirectory (va("%s/"BASEDIRNAME, fs_cddir->string) );
-
- //
- // start up with baseq2 by default
- //
- FS_AddGameDirectory (va("%s/"BASEDIRNAME, fs_basedir->string) );
-
- // any set gamedirs will be freed up to here
- fs_base_searchpaths = fs_searchpaths;
-
- // check for game override
- fs_gamedirvar = Cvar_Get ("game", "", CVAR_LATCH|CVAR_SERVERINFO);
- if (fs_gamedirvar->string[0])
- FS_SetGamedir (fs_gamedirvar->string);
-}
-
-
-
--- a/qcommon/md4.c
+++ /dev/null
@@ -1,275 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-/* POINTER defines a generic pointer type */
-typedef unsigned char *POINTER;
-
-/* UINT2 defines a two byte word */
-typedef unsigned short int UINT2;
-
-/* UINT4 defines a four byte word */
-typedef unsigned long int UINT4;
-
-
-/* MD4.H - header file for MD4C.C */
-
-/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991.
-
-All rights reserved.
-
-License to copy and use this software is granted provided that it is identified as the �RSA Data Security, Inc. MD4 Message-Digest Algorithm� in all material mentioning or referencing this software or this function.
-License is also granted to make and use derivative works provided that such works are identified as �derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm� in all material mentioning or referencing the derived work.
-RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided �as is� without express or implied warranty of any kind.
-
-These notices must be retained in any copies of any part of this documentation and/or software. */
-
-/* MD4 context. */
-typedef struct {
- UINT4 state[4]; /* state (ABCD) */
- UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
- unsigned char buffer[64]; /* input buffer */
-} MD4_CTX;
-
-void MD4Init (MD4_CTX *);
-void MD4Update (MD4_CTX *, unsigned char *, unsigned int);
-void MD4Final (unsigned char [16], MD4_CTX *);
-
-
-
-/* MD4C.C - RSA Data Security, Inc., MD4 message-digest algorithm */
-/* Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
-
-License to copy and use this software is granted provided that it is identified as the
-RSA Data Security, Inc. MD4 Message-Digest Algorithm
- in all material mentioning or referencing this software or this function.
-License is also granted to make and use derivative works provided that such works are identified as
-derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm
-in all material mentioning or referencing the derived work.
-RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided
-as is without express or implied warranty of any kind.
-
-These notices must be retained in any copies of any part of this documentation and/or software. */
-
-/* Constants for MD4Transform routine. */
-#define S11 3
-#define S12 7
-#define S13 11
-#define S14 19
-#define S21 3
-#define S22 5
-#define S23 9
-#define S24 13
-#define S31 3
-#define S32 9
-#define S33 11
-#define S34 15
-
-static void MD4Transform (UINT4 [4], unsigned char [64]);
-static void Encode (unsigned char *, UINT4 *, unsigned int);
-static void Decode (UINT4 *, unsigned char *, unsigned int);
-
-static unsigned char PADDING[64] = {
-0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/* F, G and H are basic MD4 functions. */
-#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
-#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-
-/* ROTATE_LEFT rotates x left n bits. */
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
-
-/* FF, GG and HH are transformations for rounds 1, 2 and 3 */
-/* Rotation is separate from addition to prevent recomputation */
-#define FF(a, b, c, d, x, s) {(a) += F ((b), (c), (d)) + (x); (a) = ROTATE_LEFT ((a), (s));}
-
-#define GG(a, b, c, d, x, s) {(a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; (a) = ROTATE_LEFT ((a), (s));}
-
-#define HH(a, b, c, d, x, s) {(a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; (a) = ROTATE_LEFT ((a), (s));}
-
-
-/* MD4 initialization. Begins an MD4 operation, writing a new context. */
-void MD4Init (MD4_CTX *context)
-{
- context->count[0] = context->count[1] = 0;
-
-/* Load magic initialization constants.*/
-context->state[0] = 0x67452301;
-context->state[1] = 0xefcdab89;
-context->state[2] = 0x98badcfe;
-context->state[3] = 0x10325476;
-}
-
-/* MD4 block update operation. Continues an MD4 message-digest operation, processing another message block, and updating the context. */
-void MD4Update (MD4_CTX *context, unsigned char *input, unsigned int inputLen)
-{
- unsigned int i, index, partLen;
-
- /* Compute number of bytes mod 64 */
- index = (unsigned int)((context->count[0] >> 3) & 0x3F);
-
- /* Update number of bits */
- if ((context->count[0] += ((UINT4)inputLen << 3))< ((UINT4)inputLen << 3))
- context->count[1]++;
-
- context->count[1] += ((UINT4)inputLen >> 29);
-
- partLen = 64 - index;
-
- /* Transform as many times as possible.*/
- if (inputLen >= partLen)
- {
- memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen);
- MD4Transform (context->state, context->buffer);
-
- for (i = partLen; i + 63 < inputLen; i += 64)
- MD4Transform (context->state, &input[i]);
-
- index = 0;
- }
- else
- i = 0;
-
- /* Buffer remaining input */
- memcpy ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);
-}
-
-
-/* MD4 finalization. Ends an MD4 message-digest operation, writing the the message digest and zeroizing the context. */
-void MD4Final (unsigned char digest[16], MD4_CTX *context)
-{
- unsigned char bits[8];
- unsigned int index, padLen;
-
- /* Save number of bits */
- Encode (bits, context->count, 8);
-
- /* Pad out to 56 mod 64.*/
- index = (unsigned int)((context->count[0] >> 3) & 0x3f);
- padLen = (index < 56) ? (56 - index) : (120 - index);
- MD4Update (context, PADDING, padLen);
-
- /* Append length (before padding) */
- MD4Update (context, bits, 8);
-
- /* Store state in digest */
- Encode (digest, context->state, 16);
-
- /* Zeroize sensitive information.*/
- memset ((POINTER)context, 0, sizeof (*context));
-}
-
-
-/* MD4 basic transformation. Transforms state based on block. */
-static void MD4Transform (UINT4 state[4], unsigned char block[64])
-{
- UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
-
- Decode (x, block, 64);
-
-/* Round 1 */
-FF (a, b, c, d, x[ 0], S11); /* 1 */
-FF (d, a, b, c, x[ 1], S12); /* 2 */
-FF (c, d, a, b, x[ 2], S13); /* 3 */
-FF (b, c, d, a, x[ 3], S14); /* 4 */
-FF (a, b, c, d, x[ 4], S11); /* 5 */
-FF (d, a, b, c, x[ 5], S12); /* 6 */
-FF (c, d, a, b, x[ 6], S13); /* 7 */
-FF (b, c, d, a, x[ 7], S14); /* 8 */
-FF (a, b, c, d, x[ 8], S11); /* 9 */
-FF (d, a, b, c, x[ 9], S12); /* 10 */
-FF (c, d, a, b, x[10], S13); /* 11 */
-FF (b, c, d, a, x[11], S14); /* 12 */
-FF (a, b, c, d, x[12], S11); /* 13 */
-FF (d, a, b, c, x[13], S12); /* 14 */
-FF (c, d, a, b, x[14], S13); /* 15 */
-FF (b, c, d, a, x[15], S14); /* 16 */
-
-/* Round 2 */
-GG (a, b, c, d, x[ 0], S21); /* 17 */
-GG (d, a, b, c, x[ 4], S22); /* 18 */
-GG (c, d, a, b, x[ 8], S23); /* 19 */
-GG (b, c, d, a, x[12], S24); /* 20 */
-GG (a, b, c, d, x[ 1], S21); /* 21 */
-GG (d, a, b, c, x[ 5], S22); /* 22 */
-GG (c, d, a, b, x[ 9], S23); /* 23 */
-GG (b, c, d, a, x[13], S24); /* 24 */
-GG (a, b, c, d, x[ 2], S21); /* 25 */
-GG (d, a, b, c, x[ 6], S22); /* 26 */
-GG (c, d, a, b, x[10], S23); /* 27 */
-GG (b, c, d, a, x[14], S24); /* 28 */
-GG (a, b, c, d, x[ 3], S21); /* 29 */
-GG (d, a, b, c, x[ 7], S22); /* 30 */
-GG (c, d, a, b, x[11], S23); /* 31 */
-GG (b, c, d, a, x[15], S24); /* 32 */
-
-/* Round 3 */
-HH (a, b, c, d, x[ 0], S31); /* 33 */
-HH (d, a, b, c, x[ 8], S32); /* 34 */
-HH (c, d, a, b, x[ 4], S33); /* 35 */
-HH (b, c, d, a, x[12], S34); /* 36 */
-HH (a, b, c, d, x[ 2], S31); /* 37 */
-HH (d, a, b, c, x[10], S32); /* 38 */
-HH (c, d, a, b, x[ 6], S33); /* 39 */
-HH (b, c, d, a, x[14], S34); /* 40 */
-HH (a, b, c, d, x[ 1], S31); /* 41 */
-HH (d, a, b, c, x[ 9], S32); /* 42 */
-HH (c, d, a, b, x[ 5], S33); /* 43 */
-HH (b, c, d, a, x[13], S34); /* 44 */
-HH (a, b, c, d, x[ 3], S31); /* 45 */
-HH (d, a, b, c, x[11], S32); /* 46 */
-HH (c, d, a, b, x[ 7], S33); /* 47 */
-HH (b, c, d, a, x[15], S34); /* 48 */
-
-state[0] += a;
-state[1] += b;
-state[2] += c;
-state[3] += d;
-
- /* Zeroize sensitive information.*/
- memset ((POINTER)x, 0, sizeof (x));
-}
-
-
-/* Encodes input (UINT4) into output (unsigned char). Assumes len is a multiple of 4. */
-static void Encode (unsigned char *output, UINT4 *input, unsigned int len)
-{
- unsigned int i, j;
-
- for (i = 0, j = 0; j < len; i++, j += 4) {
- output[j] = (unsigned char)(input[i] & 0xff);
- output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
- output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
- output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
- }
-}
-
-
-/* Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4. */
-static void Decode (UINT4 *output, unsigned char *input, unsigned int len)
-{
-unsigned int i, j;
-
-for (i = 0, j = 0; j < len; i++, j += 4)
- output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
-}
-
-//===================================================================
-
-unsigned Com_BlockChecksum (void *buffer, int length)
-{
- int digest[4];
- unsigned val;
- MD4_CTX ctx;
-
- MD4Init (&ctx);
- MD4Update (&ctx, (unsigned char *)buffer, length);
- MD4Final ( (unsigned char *)digest, &ctx);
-
- val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3];
-
- return val;
-}
--- a/qcommon/net_chan.c
+++ /dev/null
@@ -1,369 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-/*
-
-packet header
--------------
-31 sequence
-1 does this message contain a reliable payload
-31 acknowledge sequence
-1 acknowledge receipt of even/odd message
-16 qport
-
-The remote connection never knows if it missed a reliable message, the
-local side detects that it has been dropped by seeing a sequence acknowledge
-higher thatn the last reliable sequence, but without the correct evon/odd
-bit for the reliable set.
-
-If the sender notices that a reliable message has been dropped, it will be
-retransmitted. It will not be retransmitted again until a message after
-the retransmit has been acknowledged and the reliable still failed to get there.
-
-if the sequence number is -1, the packet should be handled without a netcon
-
-The reliable message can be added to at any time by doing
-MSG_Write* (&netchan->message, <data>).
-
-If the message buffer is overflowed, either by a single message, or by
-multiple frames worth piling up while the last reliable transmit goes
-unacknowledged, the netchan signals a fatal error.
-
-Reliable messages are always placed first in a packet, then the unreliable
-message is included if there is sufficient room.
-
-To the receiver, there is no distinction between the reliable and unreliable
-parts of the message, they are just processed out as a single larger message.
-
-Illogical packet sequence numbers cause the packet to be dropped, but do
-not kill the connection. This, combined with the tight window of valid
-reliable acknowledgement numbers provides protection against malicious
-address spoofing.
-
-
-The qport field is a workaround for bad address translating routers that
-sometimes remap the client's source port on a packet during gameplay.
-
-If the base part of the net address matches and the qport matches, then the
-channel matches even if the IP port differs. The IP port should be updated
-to the new value before sending out any replies.
-
-
-If there is no information that needs to be transfered on a given frame,
-such as during the connection stage while waiting for the client to load,
-then a packet only needs to be delivered if there is something in the
-unacknowledged reliable
-*/
-
-cvar_t *showpackets;
-cvar_t *showdrop;
-cvar_t *qport;
-
-netadr_t net_from;
-sizebuf_t net_message;
-byte net_message_buffer[MAX_MSGLEN];
-
-/*
-===============
-Netchan_Init
-
-===============
-*/
-void Netchan_Init (void)
-{
- int port;
-
- // pick a port value that should be nice and random
- port = Sys_Milliseconds() & 0xffff;
-
- showpackets = Cvar_Get ("showpackets", "0", 0);
- showdrop = Cvar_Get ("showdrop", "0", 0);
- qport = Cvar_Get ("qport", va("%i", port), CVAR_NOSET);
-}
-
-/*
-===============
-Netchan_OutOfBand
-
-Sends an out-of-band datagram
-================
-*/
-void Netchan_OutOfBand (int net_socket, netadr_t adr, int length, byte *data)
-{
- sizebuf_t send;
- byte send_buf[MAX_MSGLEN];
-
-// write the packet header
- SZ_Init (&send, send_buf, sizeof(send_buf));
-
- MSG_WriteLong (&send, -1); // -1 sequence means out of band
- SZ_Write (&send, data, length);
-
-// send the datagram
- NET_SendPacket (net_socket, send.cursize, send.data, adr);
-}
-
-/*
-===============
-Netchan_OutOfBandPrint
-
-Sends a text message in an out-of-band datagram
-================
-*/
-void Netchan_OutOfBandPrint (int net_socket, netadr_t adr, char *format, ...)
-{
- va_list argptr;
- static char string[MAX_MSGLEN - 4];
-
- va_start (argptr, format);
- vsprintf (string, format,argptr);
- va_end (argptr);
-
- Netchan_OutOfBand (net_socket, adr, strlen(string), (byte *)string);
-}
-
-
-/*
-==============
-Netchan_Setup
-
-called to open a channel to a remote system
-==============
-*/
-void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t adr, int qport)
-{
- memset (chan, 0, sizeof(*chan));
-
- chan->sock = sock;
- chan->remote_address = adr;
- chan->qport = qport;
- chan->last_received = curtime;
- chan->incoming_sequence = 0;
- chan->outgoing_sequence = 1;
-
- SZ_Init (&chan->message, chan->message_buf, sizeof(chan->message_buf));
- chan->message.allowoverflow = true;
-}
-
-
-/*
-===============
-Netchan_CanReliable
-
-Returns true if the last reliable message has acked
-================
-*/
-qboolean Netchan_CanReliable (netchan_t *chan)
-{
- if (chan->reliable_length)
- return false; // waiting for ack
- return true;
-}
-
-
-qboolean Netchan_NeedReliable (netchan_t *chan)
-{
- qboolean send_reliable;
-
-// if the remote side dropped the last reliable message, resend it
- send_reliable = false;
-
- if (chan->incoming_acknowledged > chan->last_reliable_sequence
- && chan->incoming_reliable_acknowledged != chan->reliable_sequence)
- send_reliable = true;
-
-// if the reliable transmit buffer is empty, copy the current message out
- if (!chan->reliable_length && chan->message.cursize)
- {
- send_reliable = true;
- }
-
- return send_reliable;
-}
-
-/*
-===============
-Netchan_Transmit
-
-tries to send an unreliable message to a connection, and handles the
-transmition / retransmition of the reliable messages.
-
-A 0 length will still generate a packet and deal with the reliable messages.
-================
-*/
-void Netchan_Transmit (netchan_t *chan, int length, byte *data)
-{
- sizebuf_t send;
- byte send_buf[MAX_MSGLEN];
- qboolean send_reliable;
- unsigned w1, w2;
-
-// check for message overflow
- if (chan->message.overflowed)
- {
- chan->fatal_error = true;
- Com_Printf ("%s:Outgoing message overflow\n"
- , NET_AdrToString (chan->remote_address));
- return;
- }
-
- send_reliable = Netchan_NeedReliable (chan);
-
- if (!chan->reliable_length && chan->message.cursize)
- {
- memcpy (chan->reliable_buf, chan->message_buf, chan->message.cursize);
- chan->reliable_length = chan->message.cursize;
- chan->message.cursize = 0;
- chan->reliable_sequence ^= 1;
- }
-
-
-// write the packet header
- SZ_Init (&send, send_buf, sizeof(send_buf));
-
- w1 = ( chan->outgoing_sequence & ~(1<<31) ) | (send_reliable<<31);
- w2 = ( chan->incoming_sequence & ~(1<<31) ) | (chan->incoming_reliable_sequence<<31);
-
- chan->outgoing_sequence++;
- chan->last_sent = curtime;
-
- MSG_WriteLong (&send, w1);
- MSG_WriteLong (&send, w2);
-
- // send the qport if we are a client
- if (chan->sock == NS_CLIENT)
- MSG_WriteShort (&send, qport->value);
-
-// copy the reliable message to the packet first
- if (send_reliable)
- {
- SZ_Write (&send, chan->reliable_buf, chan->reliable_length);
- chan->last_reliable_sequence = chan->outgoing_sequence;
- }
-
-// add the unreliable part if space is available
- if (send.maxsize - send.cursize >= length)
- SZ_Write (&send, data, length);
- else
- Com_Printf ("Netchan_Transmit: dumped unreliable\n");
-
-// send the datagram
- NET_SendPacket (chan->sock, send.cursize, send.data, chan->remote_address);
-
- if (showpackets->value)
- {
- if (send_reliable)
- Com_Printf ("send %4i : s=%i reliable=%i ack=%i rack=%i\n"
- , send.cursize
- , chan->outgoing_sequence - 1
- , chan->reliable_sequence
- , chan->incoming_sequence
- , chan->incoming_reliable_sequence);
- else
- Com_Printf ("send %4i : s=%i ack=%i rack=%i\n"
- , send.cursize
- , chan->outgoing_sequence - 1
- , chan->incoming_sequence
- , chan->incoming_reliable_sequence);
- }
-}
-
-/*
-=================
-Netchan_Process
-
-called when the current net_message is from remote_address
-modifies net_message so that it points to the packet payload
-=================
-*/
-qboolean Netchan_Process (netchan_t *chan, sizebuf_t *msg)
-{
- unsigned sequence, sequence_ack;
- unsigned reliable_ack, reliable_message;
-
-// get sequence numbers
- MSG_BeginReading (msg);
- sequence = MSG_ReadLong (msg);
- sequence_ack = MSG_ReadLong (msg);
-
- // read the qport if we are a server
- if (chan->sock == NS_SERVER)
- MSG_ReadShort (msg); /* toss read */
-
- reliable_message = sequence >> 31;
- reliable_ack = sequence_ack >> 31;
-
- sequence &= ~(1<<31);
- sequence_ack &= ~(1<<31);
-
- if (showpackets->value)
- {
- if (reliable_message)
- Com_Printf ("recv %4i : s=%i reliable=%i ack=%i rack=%i\n"
- , msg->cursize
- , sequence
- , chan->incoming_reliable_sequence ^ 1
- , sequence_ack
- , reliable_ack);
- else
- Com_Printf ("recv %4i : s=%i ack=%i rack=%i\n"
- , msg->cursize
- , sequence
- , sequence_ack
- , reliable_ack);
- }
-
-//
-// discard stale or duplicated packets
-//
- if (sequence <= chan->incoming_sequence)
- {
- if (showdrop->value)
- Com_Printf ("%s:Out of order packet %i at %i\n"
- , NET_AdrToString (chan->remote_address)
- , sequence
- , chan->incoming_sequence);
- return false;
- }
-
-//
-// dropped packets don't keep the message from being used
-//
- chan->dropped = sequence - (chan->incoming_sequence+1);
- if (chan->dropped > 0)
- {
- if (showdrop->value)
- Com_Printf ("%s:Dropped %i packets at %i\n"
- , NET_AdrToString (chan->remote_address)
- , chan->dropped
- , sequence);
- }
-
-//
-// if the current outgoing reliable message has been acknowledged
-// clear the buffer to make way for the next
-//
- if (reliable_ack == chan->reliable_sequence)
- chan->reliable_length = 0; // it has been received
-
-//
-// if this message contains a reliable message, bump incoming_reliable_sequence
-//
- chan->incoming_sequence = sequence;
- chan->incoming_acknowledged = sequence_ack;
- chan->incoming_reliable_acknowledged = reliable_ack;
- if (reliable_message)
- {
- chan->incoming_reliable_sequence ^= 1;
- }
-
-//
-// the message can now be read from the current message pointer
-//
- chan->last_received = curtime;
-
- return true;
-}
-
--- a/qcommon/pmove.c
+++ /dev/null
@@ -1,1337 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-
-#define STEPSIZE 18
-
-// all of the locals will be zeroed before each
-// pmove, just to make damn sure we don't have
-// any differences when running on client or server
-
-typedef struct
-{
- vec3_t origin; // full float precision
- vec3_t velocity; // full float precision
-
- vec3_t forward, right, up;
- float frametime;
-
-
- csurface_t *groundsurface;
- cplane_t groundplane;
- int groundcontents;
-
- vec3_t previous_origin;
- qboolean ladder;
-} pml_t;
-
-pmove_t *pm;
-pml_t pml;
-
-
-// movement parameters
-float pm_stopspeed = 100;
-float pm_maxspeed = 300;
-float pm_duckspeed = 100;
-float pm_accelerate = 10;
-float pm_airaccelerate = 0;
-float pm_wateraccelerate = 10;
-float pm_friction = 6;
-float pm_waterfriction = 1;
-float pm_waterspeed = 400;
-
-/*
-
- walking up a step should kill some velocity
-
-*/
-
-
-/*
-==================
-PM_ClipVelocity
-
-Slide off of the impacting object
-returns the blocked flags (1 = floor, 2 = step / wall)
-==================
-*/
-#define STOP_EPSILON 0.1
-
-void PM_ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
-{
- float backoff;
- float change;
- int i;
-
- backoff = DotProduct (in, normal) * overbounce;
-
- for (i=0 ; i<3 ; i++)
- {
- change = normal[i]*backoff;
- out[i] = in[i] - change;
- if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
- out[i] = 0;
- }
-}
-
-
-
-
-/*
-==================
-PM_StepSlideMove
-
-Each intersection will try to step over the obstruction instead of
-sliding along it.
-
-Returns a new origin, velocity, and contact entity
-Does not modify any world state?
-==================
-*/
-#define MIN_STEP_NORMAL 0.7 // can't step up onto very steep slopes
-#define MAX_CLIP_PLANES 5
-void PM_StepSlideMove_ (void)
-{
- int bumpcount, numbumps;
- vec3_t dir;
- float d;
- int numplanes;
- vec3_t planes[MAX_CLIP_PLANES];
- vec3_t primal_velocity;
- int i, j;
- trace_t trace;
- vec3_t end;
- float time_left;
-
- numbumps = 4;
-
- VectorCopy (pml.velocity, primal_velocity);
- numplanes = 0;
-
- time_left = pml.frametime;
-
- for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
- {
- for (i=0 ; i<3 ; i++)
- end[i] = pml.origin[i] + time_left * pml.velocity[i];
-
- trace = pm->trace (pml.origin, pm->mins, pm->maxs, end);
-
- if (trace.allsolid)
- { // entity is trapped in another solid
- pml.velocity[2] = 0; // don't build up falling damage
- return;
- }
-
- if (trace.fraction > 0)
- { // actually covered some distance
- VectorCopy (trace.endpos, pml.origin);
- numplanes = 0;
- }
-
- if (trace.fraction == 1)
- break; // moved the entire distance
-
- // save entity for contact
- if (pm->numtouch < MAXTOUCH && trace.ent)
- {
- pm->touchents[pm->numtouch] = trace.ent;
- pm->numtouch++;
- }
-
- time_left -= time_left * trace.fraction;
-
- // slide along this plane
- if (numplanes >= MAX_CLIP_PLANES)
- { // this shouldn't really happen
- VectorCopy (vec3_origin, pml.velocity);
- break;
- }
-
- VectorCopy (trace.plane.normal, planes[numplanes]);
- numplanes++;
-
-/* commented out in release
- float rub;
-
- //
- // modify velocity so it parallels all of the clip planes
- //
- if (numplanes == 1)
- { // go along this plane
- VectorCopy (pml.velocity, dir);
- VectorNormalize (dir);
- rub = 1.0 + 0.5 * DotProduct (dir, planes[0]);
-
- // slide along the plane
- PM_ClipVelocity (pml.velocity, planes[0], pml.velocity, 1.01);
- // rub some extra speed off on xy axis
- // not on Z, or you can scrub down walls
- pml.velocity[0] *= rub;
- pml.velocity[1] *= rub;
- pml.velocity[2] *= rub;
- }
- else if (numplanes == 2)
- { // go along the crease
- VectorCopy (pml.velocity, dir);
- VectorNormalize (dir);
- rub = 1.0 + 0.5 * DotProduct (dir, planes[0]);
-
- // slide along the plane
- CrossProduct (planes[0], planes[1], dir);
- d = DotProduct (dir, pml.velocity);
- VectorScale (dir, d, pml.velocity);
-
- // rub some extra speed off
- VectorScale (pml.velocity, rub, pml.velocity);
- }
- else
- {
-// Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
- VectorCopy (vec3_origin, pml.velocity);
- break;
- }
-
-*/
-//
-// modify original_velocity so it parallels all of the clip planes
-//
- for (i=0 ; i<numplanes ; i++)
- {
- PM_ClipVelocity (pml.velocity, planes[i], pml.velocity, 1.01);
- for (j=0 ; j<numplanes ; j++)
- if (j != i)
- {
- if (DotProduct (pml.velocity, planes[j]) < 0)
- break; // not ok
- }
- if (j == numplanes)
- break;
- }
-
- if (i != numplanes)
- { // go along this plane
- }
- else
- { // go along the crease
- if (numplanes != 2)
- {
-// Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
- VectorCopy (vec3_origin, pml.velocity);
- break;
- }
- CrossProduct (planes[0], planes[1], dir);
- d = DotProduct (dir, pml.velocity);
- VectorScale (dir, d, pml.velocity);
- }
- //
- // if velocity is against the original velocity, stop dead
- // to avoid tiny occilations in sloping corners
- //
- if (DotProduct (pml.velocity, primal_velocity) <= 0)
- {
- VectorCopy (vec3_origin, pml.velocity);
- break;
- }
- }
-
- if (pm->s.pm_time)
- {
- VectorCopy (primal_velocity, pml.velocity);
- }
-}
-
-/*
-==================
-PM_StepSlideMove
-
-==================
-*/
-void PM_StepSlideMove (void)
-{
- vec3_t start_o, start_v;
- vec3_t down_o, down_v;
- trace_t trace;
- float down_dist, up_dist;
-// vec3_t delta;
- vec3_t up, down;
-
- VectorCopy (pml.origin, start_o);
- VectorCopy (pml.velocity, start_v);
-
- PM_StepSlideMove_ ();
-
- VectorCopy (pml.origin, down_o);
- VectorCopy (pml.velocity, down_v);
-
- VectorCopy (start_o, up);
- up[2] += STEPSIZE;
-
- trace = pm->trace (up, pm->mins, pm->maxs, up);
- if (trace.allsolid)
- return; // can't step up
-
- // try sliding above
- VectorCopy (up, pml.origin);
- VectorCopy (start_v, pml.velocity);
-
- PM_StepSlideMove_ ();
-
- // push down the final amount
- VectorCopy (pml.origin, down);
- down[2] -= STEPSIZE;
- trace = pm->trace (pml.origin, pm->mins, pm->maxs, down);
- if (!trace.allsolid)
- {
- VectorCopy (trace.endpos, pml.origin);
- }
-
-/*
- VectorSubtract (pml.origin, up, delta);
- up_dist = DotProduct (delta, start_v);
-
- VectorSubtract (down_o, start_o, delta);
- down_dist = DotProduct (delta, start_v);
-*/
- VectorCopy(pml.origin, up);
-
- // decide which one went farther
- down_dist = (down_o[0] - start_o[0])*(down_o[0] - start_o[0])
- + (down_o[1] - start_o[1])*(down_o[1] - start_o[1]);
- up_dist = (up[0] - start_o[0])*(up[0] - start_o[0])
- + (up[1] - start_o[1])*(up[1] - start_o[1]);
-
- if (down_dist > up_dist || trace.plane.normal[2] < MIN_STEP_NORMAL)
- {
- VectorCopy (down_o, pml.origin);
- VectorCopy (down_v, pml.velocity);
- return;
- }
- //!! Special case
- // if we were walking along a plane, then we need to copy the Z over
- pml.velocity[2] = down_v[2];
-}
-
-
-/*
-==================
-PM_Friction
-
-Handles both ground friction and water friction
-==================
-*/
-void PM_Friction (void)
-{
- float *vel;
- float speed, newspeed, control;
- float friction;
- float drop;
-
- vel = pml.velocity;
-
- speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1] + vel[2]*vel[2]);
- if (speed < 1)
- {
- vel[0] = 0;
- vel[1] = 0;
- return;
- }
-
- drop = 0;
-
-// apply ground friction
- if ((pm->groundentity && pml.groundsurface && !(pml.groundsurface->flags & SURF_SLICK) ) || (pml.ladder) )
- {
- friction = pm_friction;
- control = speed < pm_stopspeed ? pm_stopspeed : speed;
- drop += control*friction*pml.frametime;
- }
-
-// apply water friction
- if (pm->waterlevel && !pml.ladder)
- drop += speed*pm_waterfriction*pm->waterlevel*pml.frametime;
-
-// scale the velocity
- newspeed = speed - drop;
- if (newspeed < 0)
- {
- newspeed = 0;
- }
- newspeed /= speed;
-
- vel[0] = vel[0] * newspeed;
- vel[1] = vel[1] * newspeed;
- vel[2] = vel[2] * newspeed;
-}
-
-
-/*
-==============
-PM_Accelerate
-
-Handles user intended acceleration
-==============
-*/
-void PM_Accelerate (vec3_t wishdir, float wishspeed, float accel)
-{
- int i;
- float addspeed, accelspeed, currentspeed;
-
- currentspeed = DotProduct (pml.velocity, wishdir);
- addspeed = wishspeed - currentspeed;
- if (addspeed <= 0)
- return;
- accelspeed = accel*pml.frametime*wishspeed;
- if (accelspeed > addspeed)
- accelspeed = addspeed;
-
- for (i=0 ; i<3 ; i++)
- pml.velocity[i] += accelspeed*wishdir[i];
-}
-
-void PM_AirAccelerate (vec3_t wishdir, float wishspeed, float accel)
-{
- int i;
- float addspeed, accelspeed, currentspeed, wishspd = wishspeed;
-
- if (wishspd > 30)
- wishspd = 30;
- currentspeed = DotProduct (pml.velocity, wishdir);
- addspeed = wishspd - currentspeed;
- if (addspeed <= 0)
- return;
- accelspeed = accel * wishspeed * pml.frametime;
- if (accelspeed > addspeed)
- accelspeed = addspeed;
-
- for (i=0 ; i<3 ; i++)
- pml.velocity[i] += accelspeed*wishdir[i];
-}
-
-/*
-=============
-PM_AddCurrents
-=============
-*/
-void PM_AddCurrents (vec3_t wishvel)
-{
- vec3_t v;
- float s;
-
- //
- // account for ladders
- //
-
- if (pml.ladder && fabs(pml.velocity[2]) <= 200)
- {
- if ((pm->viewangles[PITCH] <= -15) && (pm->cmd.forwardmove > 0))
- wishvel[2] = 200;
- else if ((pm->viewangles[PITCH] >= 15) && (pm->cmd.forwardmove > 0))
- wishvel[2] = -200;
- else if (pm->cmd.upmove > 0)
- wishvel[2] = 200;
- else if (pm->cmd.upmove < 0)
- wishvel[2] = -200;
- else
- wishvel[2] = 0;
-
- // limit horizontal speed when on a ladder
- if (wishvel[0] < -25)
- wishvel[0] = -25;
- else if (wishvel[0] > 25)
- wishvel[0] = 25;
-
- if (wishvel[1] < -25)
- wishvel[1] = -25;
- else if (wishvel[1] > 25)
- wishvel[1] = 25;
- }
-
-
- //
- // add water currents
- //
-
- if (pm->watertype & MASK_CURRENT)
- {
- VectorClear (v);
-
- if (pm->watertype & CONTENTS_CURRENT_0)
- v[0] += 1;
- if (pm->watertype & CONTENTS_CURRENT_90)
- v[1] += 1;
- if (pm->watertype & CONTENTS_CURRENT_180)
- v[0] -= 1;
- if (pm->watertype & CONTENTS_CURRENT_270)
- v[1] -= 1;
- if (pm->watertype & CONTENTS_CURRENT_UP)
- v[2] += 1;
- if (pm->watertype & CONTENTS_CURRENT_DOWN)
- v[2] -= 1;
-
- s = pm_waterspeed;
- if ((pm->waterlevel == 1) && (pm->groundentity))
- s /= 2;
-
- VectorMA (wishvel, s, v, wishvel);
- }
-
- //
- // add conveyor belt velocities
- //
-
- if (pm->groundentity)
- {
- VectorClear (v);
-
- if (pml.groundcontents & CONTENTS_CURRENT_0)
- v[0] += 1;
- if (pml.groundcontents & CONTENTS_CURRENT_90)
- v[1] += 1;
- if (pml.groundcontents & CONTENTS_CURRENT_180)
- v[0] -= 1;
- if (pml.groundcontents & CONTENTS_CURRENT_270)
- v[1] -= 1;
- if (pml.groundcontents & CONTENTS_CURRENT_UP)
- v[2] += 1;
- if (pml.groundcontents & CONTENTS_CURRENT_DOWN)
- v[2] -= 1;
-
- VectorMA (wishvel, 100 /* pm->groundentity->speed */, v, wishvel);
- }
-}
-
-
-/*
-===================
-PM_WaterMove
-
-===================
-*/
-void PM_WaterMove (void)
-{
- int i;
- vec3_t wishvel;
- float wishspeed;
- vec3_t wishdir;
-
-//
-// user intentions
-//
- for (i=0 ; i<3 ; i++)
- wishvel[i] = pml.forward[i]*pm->cmd.forwardmove + pml.right[i]*pm->cmd.sidemove;
-
- if (!pm->cmd.forwardmove && !pm->cmd.sidemove && !pm->cmd.upmove)
- wishvel[2] -= 60; // drift towards bottom
- else
- wishvel[2] += pm->cmd.upmove;
-
- PM_AddCurrents (wishvel);
-
- VectorCopy (wishvel, wishdir);
- wishspeed = VectorNormalize(wishdir);
-
- if (wishspeed > pm_maxspeed)
- {
- VectorScale (wishvel, pm_maxspeed/wishspeed, wishvel);
- wishspeed = pm_maxspeed;
- }
- wishspeed *= 0.5;
-
- PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate);
-
- PM_StepSlideMove ();
-}
-
-
-/*
-===================
-PM_AirMove
-
-===================
-*/
-void PM_AirMove (void)
-{
- int i;
- vec3_t wishvel;
- float fmove, smove;
- vec3_t wishdir;
- float wishspeed;
- float maxspeed;
-
- fmove = pm->cmd.forwardmove;
- smove = pm->cmd.sidemove;
-
-//!!!!! pitch should be 1/3 so this isn't needed??!
-/*
- pml.forward[2] = 0;
- pml.right[2] = 0;
- VectorNormalize (pml.forward);
- VectorNormalize (pml.right);
-*/
-
- for (i=0 ; i<2 ; i++)
- wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
- wishvel[2] = 0;
-
- PM_AddCurrents (wishvel);
-
- VectorCopy (wishvel, wishdir);
- wishspeed = VectorNormalize(wishdir);
-
-//
-// clamp to server defined max speed
-//
- maxspeed = (pm->s.pm_flags & PMF_DUCKED) ? pm_duckspeed : pm_maxspeed;
-
- if (wishspeed > maxspeed)
- {
- VectorScale (wishvel, maxspeed/wishspeed, wishvel);
- wishspeed = maxspeed;
- }
-
- if ( pml.ladder )
- {
- PM_Accelerate (wishdir, wishspeed, pm_accelerate);
- if (!wishvel[2])
- {
- if (pml.velocity[2] > 0)
- {
- pml.velocity[2] -= pm->s.gravity * pml.frametime;
- if (pml.velocity[2] < 0)
- pml.velocity[2] = 0;
- }
- else
- {
- pml.velocity[2] += pm->s.gravity * pml.frametime;
- if (pml.velocity[2] > 0)
- pml.velocity[2] = 0;
- }
- }
- PM_StepSlideMove ();
- }
- else if ( pm->groundentity )
- { // walking on ground
- pml.velocity[2] = 0; //!!! this is before the accel
- PM_Accelerate (wishdir, wishspeed, pm_accelerate);
-
-// PGM -- fix for negative trigger_gravity fields
-// pml.velocity[2] = 0;
- if(pm->s.gravity > 0)
- pml.velocity[2] = 0;
- else
- pml.velocity[2] -= pm->s.gravity * pml.frametime;
-// PGM
-
- if (!pml.velocity[0] && !pml.velocity[1])
- return;
- PM_StepSlideMove ();
- }
- else
- { // not on ground, so little effect on velocity
- if (pm_airaccelerate)
- PM_AirAccelerate (wishdir, wishspeed, pm_accelerate);
- else
- PM_Accelerate (wishdir, wishspeed, 1);
- // add gravity
- pml.velocity[2] -= pm->s.gravity * pml.frametime;
- PM_StepSlideMove ();
- }
-}
-
-
-
-/*
-=============
-PM_CatagorizePosition
-=============
-*/
-void PM_CatagorizePosition (void)
-{
- vec3_t point;
- int cont;
- trace_t trace;
- int sample1;
- int sample2;
-
-// if the player hull point one unit down is solid, the player
-// is on ground
-
-// see if standing on something solid
- point[0] = pml.origin[0];
- point[1] = pml.origin[1];
- point[2] = pml.origin[2] - 0.25;
- if (pml.velocity[2] > 180) //!!ZOID changed from 100 to 180 (ramp accel)
- {
- pm->s.pm_flags &= ~PMF_ON_GROUND;
- pm->groundentity = NULL;
- }
- else
- {
- trace = pm->trace (pml.origin, pm->mins, pm->maxs, point);
- pml.groundplane = trace.plane;
- pml.groundsurface = trace.surface;
- pml.groundcontents = trace.contents;
-
- if (!trace.ent || (trace.plane.normal[2] < 0.7 && !trace.startsolid) )
- {
- pm->groundentity = NULL;
- pm->s.pm_flags &= ~PMF_ON_GROUND;
- }
- else
- {
- pm->groundentity = trace.ent;
-
- // hitting solid ground will end a waterjump
- if (pm->s.pm_flags & PMF_TIME_WATERJUMP)
- {
- pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
- pm->s.pm_time = 0;
- }
-
- if (! (pm->s.pm_flags & PMF_ON_GROUND) )
- { // just hit the ground
- pm->s.pm_flags |= PMF_ON_GROUND;
- // don't do landing time if we were just going down a slope
- if (pml.velocity[2] < -200)
- {
- pm->s.pm_flags |= PMF_TIME_LAND;
- // don't allow another jump for a little while
- if (pml.velocity[2] < -400)
- pm->s.pm_time = 25;
- else
- pm->s.pm_time = 18;
- }
- }
- }
-
-/*
- if (trace.fraction < 1.0 && trace.ent && pml.velocity[2] < 0)
- pml.velocity[2] = 0;
-*/
-
- if (pm->numtouch < MAXTOUCH && trace.ent)
- {
- pm->touchents[pm->numtouch] = trace.ent;
- pm->numtouch++;
- }
- }
-
-//
-// get waterlevel, accounting for ducking
-//
- pm->waterlevel = 0;
- pm->watertype = 0;
-
- sample2 = pm->viewheight - pm->mins[2];
- sample1 = sample2 / 2;
-
- point[2] = pml.origin[2] + pm->mins[2] + 1;
- cont = pm->pointcontents (point);
-
- if (cont & MASK_WATER)
- {
- pm->watertype = cont;
- pm->waterlevel = 1;
- point[2] = pml.origin[2] + pm->mins[2] + sample1;
- cont = pm->pointcontents (point);
- if (cont & MASK_WATER)
- {
- pm->waterlevel = 2;
- point[2] = pml.origin[2] + pm->mins[2] + sample2;
- cont = pm->pointcontents (point);
- if (cont & MASK_WATER)
- pm->waterlevel = 3;
- }
- }
-
-}
-
-
-/*
-=============
-PM_CheckJump
-=============
-*/
-void PM_CheckJump (void)
-{
- if (pm->s.pm_flags & PMF_TIME_LAND)
- { // hasn't been long enough since landing to jump again
- return;
- }
-
- if (pm->cmd.upmove < 10)
- { // not holding jump
- pm->s.pm_flags &= ~PMF_JUMP_HELD;
- return;
- }
-
- // must wait for jump to be released
- if (pm->s.pm_flags & PMF_JUMP_HELD)
- return;
-
- if (pm->s.pm_type == PM_DEAD)
- return;
-
- if (pm->waterlevel >= 2)
- { // swimming, not jumping
- pm->groundentity = NULL;
-
- if (pml.velocity[2] <= -300)
- return;
-
- if (pm->watertype == CONTENTS_WATER)
- pml.velocity[2] = 100;
- else if (pm->watertype == CONTENTS_SLIME)
- pml.velocity[2] = 80;
- else
- pml.velocity[2] = 50;
- return;
- }
-
- if (pm->groundentity == NULL)
- return; // in air, so no effect
-
- pm->s.pm_flags |= PMF_JUMP_HELD;
-
- pm->groundentity = NULL;
- pml.velocity[2] += 270;
- if (pml.velocity[2] < 270)
- pml.velocity[2] = 270;
-}
-
-
-/*
-=============
-PM_CheckSpecialMovement
-=============
-*/
-void PM_CheckSpecialMovement (void)
-{
- vec3_t spot;
- int cont;
- vec3_t flatforward;
- trace_t trace;
-
- if (pm->s.pm_time)
- return;
-
- pml.ladder = false;
-
- // check for ladder
- flatforward[0] = pml.forward[0];
- flatforward[1] = pml.forward[1];
- flatforward[2] = 0;
- VectorNormalize (flatforward);
-
- VectorMA (pml.origin, 1, flatforward, spot);
- trace = pm->trace (pml.origin, pm->mins, pm->maxs, spot);
- if ((trace.fraction < 1) && (trace.contents & CONTENTS_LADDER))
- pml.ladder = true;
-
- // check for water jump
- if (pm->waterlevel != 2)
- return;
-
- VectorMA (pml.origin, 30, flatforward, spot);
- spot[2] += 4;
- cont = pm->pointcontents (spot);
- if (!(cont & CONTENTS_SOLID))
- return;
-
- spot[2] += 16;
- cont = pm->pointcontents (spot);
- if (cont)
- return;
- // jump out of water
- VectorScale (flatforward, 50, pml.velocity);
- pml.velocity[2] = 350;
-
- pm->s.pm_flags |= PMF_TIME_WATERJUMP;
- pm->s.pm_time = 255;
-}
-
-
-/*
-===============
-PM_FlyMove
-===============
-*/
-void PM_FlyMove (qboolean doclip)
-{
- float speed, drop, friction, control, newspeed;
- float currentspeed, addspeed, accelspeed;
- int i;
- vec3_t wishvel;
- float fmove, smove;
- vec3_t wishdir;
- float wishspeed;
- vec3_t end;
- trace_t trace;
-
- pm->viewheight = 22;
-
- // friction
-
- speed = VectorLength (pml.velocity);
- if (speed < 1)
- {
- VectorCopy (vec3_origin, pml.velocity);
- }
- else
- {
- drop = 0;
-
- friction = pm_friction*1.5; // extra friction
- control = speed < pm_stopspeed ? pm_stopspeed : speed;
- drop += control*friction*pml.frametime;
-
- // scale the velocity
- newspeed = speed - drop;
- if (newspeed < 0)
- newspeed = 0;
- newspeed /= speed;
-
- VectorScale (pml.velocity, newspeed, pml.velocity);
- }
-
- // accelerate
- fmove = pm->cmd.forwardmove;
- smove = pm->cmd.sidemove;
-
- VectorNormalize (pml.forward);
- VectorNormalize (pml.right);
-
- for (i=0 ; i<3 ; i++)
- wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
- wishvel[2] += pm->cmd.upmove;
-
- VectorCopy (wishvel, wishdir);
- wishspeed = VectorNormalize(wishdir);
-
- //
- // clamp to server defined max speed
- //
- if (wishspeed > pm_maxspeed)
- {
- VectorScale (wishvel, pm_maxspeed/wishspeed, wishvel);
- wishspeed = pm_maxspeed;
- }
-
-
- currentspeed = DotProduct(pml.velocity, wishdir);
- addspeed = wishspeed - currentspeed;
- if (addspeed <= 0)
- return;
- accelspeed = pm_accelerate*pml.frametime*wishspeed;
- if (accelspeed > addspeed)
- accelspeed = addspeed;
-
- for (i=0 ; i<3 ; i++)
- pml.velocity[i] += accelspeed*wishdir[i];
-
- if (doclip) {
- for (i=0 ; i<3 ; i++)
- end[i] = pml.origin[i] + pml.frametime * pml.velocity[i];
-
- trace = pm->trace (pml.origin, pm->mins, pm->maxs, end);
-
- VectorCopy (trace.endpos, pml.origin);
- } else {
- // move
- VectorMA (pml.origin, pml.frametime, pml.velocity, pml.origin);
- }
-}
-
-
-/*
-==============
-PM_CheckDuck
-
-Sets mins, maxs, and pm->viewheight
-==============
-*/
-void PM_CheckDuck (void)
-{
- trace_t trace;
-
- pm->mins[0] = -16;
- pm->mins[1] = -16;
-
- pm->maxs[0] = 16;
- pm->maxs[1] = 16;
-
- if (pm->s.pm_type == PM_GIB)
- {
- pm->mins[2] = 0;
- pm->maxs[2] = 16;
- pm->viewheight = 8;
- return;
- }
-
- pm->mins[2] = -24;
-
- if (pm->s.pm_type == PM_DEAD)
- {
- pm->s.pm_flags |= PMF_DUCKED;
- }
- else if (pm->cmd.upmove < 0 && (pm->s.pm_flags & PMF_ON_GROUND) )
- { // duck
- pm->s.pm_flags |= PMF_DUCKED;
- }
- else
- { // stand up if possible
- if (pm->s.pm_flags & PMF_DUCKED)
- {
- // try to stand up
- pm->maxs[2] = 32;
- trace = pm->trace (pml.origin, pm->mins, pm->maxs, pml.origin);
- if (!trace.allsolid)
- pm->s.pm_flags &= ~PMF_DUCKED;
- }
- }
-
- if (pm->s.pm_flags & PMF_DUCKED)
- {
- pm->maxs[2] = 4;
- pm->viewheight = -2;
- }
- else
- {
- pm->maxs[2] = 32;
- pm->viewheight = 22;
- }
-}
-
-
-/*
-==============
-PM_DeadMove
-==============
-*/
-void PM_DeadMove (void)
-{
- float forward;
-
- if (!pm->groundentity)
- return;
-
- // extra friction
-
- forward = VectorLength (pml.velocity);
- forward -= 20;
- if (forward <= 0)
- {
- VectorClear (pml.velocity);
- }
- else
- {
- VectorNormalize (pml.velocity);
- VectorScale (pml.velocity, forward, pml.velocity);
- }
-}
-
-
-qboolean PM_GoodPosition (void)
-{
- trace_t trace;
- vec3_t origin, end;
- int i;
-
- if (pm->s.pm_type == PM_SPECTATOR)
- return true;
-
- for (i=0 ; i<3 ; i++)
- origin[i] = end[i] = pm->s.origin[i]*0.125;
- trace = pm->trace (origin, pm->mins, pm->maxs, end);
-
- return !trace.allsolid;
-}
-
-/*
-================
-PM_SnapPosition
-
-On exit, the origin will have a value that is pre-quantized to the 0.125
-precision of the network channel and in a valid position.
-================
-*/
-void PM_SnapPosition (void)
-{
- int sign[3];
- int i, j, bits;
- short base[3];
- // try all single bits first
- static int jitterbits[8] = {0,4,1,2,3,5,6,7};
-
- // snap velocity to eigths
- for (i=0 ; i<3 ; i++)
- pm->s.velocity[i] = (int)(pml.velocity[i]*8);
-
- for (i=0 ; i<3 ; i++)
- {
- if (pml.origin[i] >= 0)
- sign[i] = 1;
- else
- sign[i] = -1;
- pm->s.origin[i] = (int)(pml.origin[i]*8);
- if (pm->s.origin[i]*0.125 == pml.origin[i])
- sign[i] = 0;
- }
- VectorCopy (pm->s.origin, base);
-
- // try all combinations
- for (j=0 ; j<8 ; j++)
- {
- bits = jitterbits[j];
- VectorCopy (base, pm->s.origin);
- for (i=0 ; i<3 ; i++)
- if (bits & (1<<i) )
- pm->s.origin[i] += sign[i];
-
- if (PM_GoodPosition ())
- return;
- }
-
- // go back to the last position
- VectorCopy (pml.previous_origin, pm->s.origin);
-// Com_DPrintf ("using previous_origin\n");
-}
-
-/*
-================
-PM_InitialSnapPosition
-
-================
-*/
-/* NO LONGER USED
-void PM_InitialSnapPosition (void)
-{
- int x, y, z;
- short base[3];
-
- VectorCopy (pm->s.origin, base);
-
- for (z=1 ; z>=-1 ; z--)
- {
- pm->s.origin[2] = base[2] + z;
- for (y=1 ; y>=-1 ; y--)
- {
- pm->s.origin[1] = base[1] + y;
- for (x=1 ; x>=-1 ; x--)
- {
- pm->s.origin[0] = base[0] + x;
- if (PM_GoodPosition ())
- {
- pml.origin[0] = pm->s.origin[0]*0.125;
- pml.origin[1] = pm->s.origin[1]*0.125;
- pml.origin[2] = pm->s.origin[2]*0.125;
- VectorCopy (pm->s.origin, pml.previous_origin);
- return;
- }
- }
- }
- }
-
- Com_DPrintf ("Bad InitialSnapPosition\n");
-}
-*/
-/*
-================
-PM_InitialSnapPosition
-
-================
-*/
-void PM_InitialSnapPosition(void)
-{
- int x, y, z;
- short base[3];
- static int offset[3] = { 0, -1, 1 };
-
- VectorCopy (pm->s.origin, base);
-
- for ( z = 0; z < 3; z++ ) {
- pm->s.origin[2] = base[2] + offset[ z ];
- for ( y = 0; y < 3; y++ ) {
- pm->s.origin[1] = base[1] + offset[ y ];
- for ( x = 0; x < 3; x++ ) {
- pm->s.origin[0] = base[0] + offset[ x ];
- if (PM_GoodPosition ()) {
- pml.origin[0] = pm->s.origin[0]*0.125;
- pml.origin[1] = pm->s.origin[1]*0.125;
- pml.origin[2] = pm->s.origin[2]*0.125;
- VectorCopy (pm->s.origin, pml.previous_origin);
- return;
- }
- }
- }
- }
-
- Com_DPrintf ("Bad InitialSnapPosition\n");
-}
-
-/*
-================
-PM_ClampAngles
-
-================
-*/
-void PM_ClampAngles (void)
-{
- short temp;
- int i;
-
- if (pm->s.pm_flags & PMF_TIME_TELEPORT)
- {
- pm->viewangles[YAW] = SHORT2ANGLE(pm->cmd.angles[YAW] + pm->s.delta_angles[YAW]);
- pm->viewangles[PITCH] = 0;
- pm->viewangles[ROLL] = 0;
- }
- else
- {
- // circularly clamp the angles with deltas
- for (i=0 ; i<3 ; i++)
- {
- temp = pm->cmd.angles[i] + pm->s.delta_angles[i];
- pm->viewangles[i] = SHORT2ANGLE(temp);
- }
-
- // don't let the player look up or down more than 90 degrees
- if (pm->viewangles[PITCH] > 89 && pm->viewangles[PITCH] < 180)
- pm->viewangles[PITCH] = 89;
- else if (pm->viewangles[PITCH] < 271 && pm->viewangles[PITCH] >= 180)
- pm->viewangles[PITCH] = 271;
- }
- AngleVectors (pm->viewangles, pml.forward, pml.right, pml.up);
-}
-
-/*
-================
-Pmove
-
-Can be called by either the server or the client
-================
-*/
-void Pmove (pmove_t *pmove)
-{
- pm = pmove;
-
- // clear results
- pm->numtouch = 0;
- VectorClear (pm->viewangles);
- pm->viewheight = 0;
- pm->groundentity = 0;
- pm->watertype = 0;
- pm->waterlevel = 0;
-
- // clear all pmove local vars
- memset (&pml, 0, sizeof(pml));
-
- // convert origin and velocity to float values
- pml.origin[0] = pm->s.origin[0]*0.125;
- pml.origin[1] = pm->s.origin[1]*0.125;
- pml.origin[2] = pm->s.origin[2]*0.125;
-
- pml.velocity[0] = pm->s.velocity[0]*0.125;
- pml.velocity[1] = pm->s.velocity[1]*0.125;
- pml.velocity[2] = pm->s.velocity[2]*0.125;
-
- // save old org in case we get stuck
- VectorCopy (pm->s.origin, pml.previous_origin);
-
- pml.frametime = pm->cmd.msec * 0.001;
-
- PM_ClampAngles ();
-
- if (pm->s.pm_type == PM_SPECTATOR)
- {
- PM_FlyMove (false);
- PM_SnapPosition ();
- return;
- }
-
- if (pm->s.pm_type >= PM_DEAD)
- {
- pm->cmd.forwardmove = 0;
- pm->cmd.sidemove = 0;
- pm->cmd.upmove = 0;
- }
-
- if (pm->s.pm_type == PM_FREEZE)
- return; // no movement at all
-
- // set mins, maxs, and viewheight
- PM_CheckDuck ();
-
- if (pm->snapinitial)
- PM_InitialSnapPosition ();
-
- // set groundentity, watertype, and waterlevel
- PM_CatagorizePosition ();
-
- if (pm->s.pm_type == PM_DEAD)
- PM_DeadMove ();
-
- PM_CheckSpecialMovement ();
-
- // drop timing counter
- if (pm->s.pm_time)
- {
- int msec;
-
- msec = pm->cmd.msec >> 3;
- if (!msec)
- msec = 1;
- if ( msec >= pm->s.pm_time)
- {
- pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
- pm->s.pm_time = 0;
- }
- else
- pm->s.pm_time -= msec;
- }
-
- if (pm->s.pm_flags & PMF_TIME_TELEPORT)
- { // teleport pause stays exactly in place
- }
- else if (pm->s.pm_flags & PMF_TIME_WATERJUMP)
- { // waterjump has no control, but falls
- pml.velocity[2] -= pm->s.gravity * pml.frametime;
- if (pml.velocity[2] < 0)
- { // cancel as soon as we are falling down again
- pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
- pm->s.pm_time = 0;
- }
-
- PM_StepSlideMove ();
- }
- else
- {
- PM_CheckJump ();
-
- PM_Friction ();
-
- if (pm->waterlevel >= 2)
- PM_WaterMove ();
- else {
- vec3_t angles;
-
- VectorCopy(pm->viewangles, angles);
- if (angles[PITCH] > 180)
- angles[PITCH] = angles[PITCH] - 360;
- angles[PITCH] /= 3;
-
- AngleVectors (angles, pml.forward, pml.right, pml.up);
-
- PM_AirMove ();
- }
- }
-
- // set groundentity, watertype, and waterlevel for final spot
- PM_CatagorizePosition ();
-
- PM_SnapPosition ();
-}
-
--- a/qcommon/qcommon.h
+++ /dev/null
@@ -1,754 +1,0 @@
-#define VERSION 3.19
-
-#define BASEDIRNAME "baseq2"
-
-//============================================================================
-
-typedef struct sizebuf_s
-{
- qboolean allowoverflow; // if false, do a Com_Error
- qboolean overflowed; // set to true if the buffer size failed
- byte *data;
- int maxsize;
- int cursize;
- int readcount;
-} sizebuf_t;
-
-void SZ_Init (sizebuf_t *buf, byte *data, int length);
-void SZ_Clear (sizebuf_t *buf);
-void *SZ_GetSpace (sizebuf_t *buf, int length);
-void SZ_Write (sizebuf_t *buf, void *data, int length);
-void SZ_Print (sizebuf_t *buf, char *data); // strcats onto the sizebuf
-
-//============================================================================
-
-struct usercmd_s;
-struct entity_state_s;
-
-void MSG_WriteChar (sizebuf_t *sb, int c);
-void MSG_WriteByte (sizebuf_t *sb, int c);
-void MSG_WriteShort (sizebuf_t *sb, int c);
-void MSG_WriteLong (sizebuf_t *sb, int c);
-void MSG_WriteFloat (sizebuf_t *sb, float f);
-void MSG_WriteString (sizebuf_t *sb, char *s);
-void MSG_WriteCoord (sizebuf_t *sb, float f);
-void MSG_WritePos (sizebuf_t *sb, vec3_t pos);
-void MSG_WriteAngle (sizebuf_t *sb, float f);
-void MSG_WriteAngle16 (sizebuf_t *sb, float f);
-void MSG_WriteDeltaUsercmd (sizebuf_t *sb, struct usercmd_s *from, struct usercmd_s *cmd);
-void MSG_WriteDeltaEntity (struct entity_state_s *from, struct entity_state_s *to, sizebuf_t *msg, qboolean force, qboolean newentity);
-void MSG_WriteDir (sizebuf_t *sb, vec3_t vector);
-
-
-void MSG_BeginReading (sizebuf_t *sb);
-
-int MSG_ReadChar (sizebuf_t *sb);
-int MSG_ReadByte (sizebuf_t *sb);
-int MSG_ReadShort (sizebuf_t *sb);
-int MSG_ReadLong (sizebuf_t *sb);
-float MSG_ReadFloat (sizebuf_t *sb);
-char *MSG_ReadString (sizebuf_t *sb);
-char *MSG_ReadStringLine (sizebuf_t *sb);
-
-float MSG_ReadCoord (sizebuf_t *sb);
-void MSG_ReadPos (sizebuf_t *sb, vec3_t pos);
-float MSG_ReadAngle (sizebuf_t *sb);
-float MSG_ReadAngle16 (sizebuf_t *sb);
-void MSG_ReadDeltaUsercmd (sizebuf_t *sb, struct usercmd_s *from, struct usercmd_s *cmd);
-
-void MSG_ReadDir (sizebuf_t *sb, vec3_t vector);
-
-void MSG_ReadData (sizebuf_t *sb, void *buffer, int size);
-
-//============================================================================
-
-extern qboolean bigendien;
-
-extern short BigShort (short l);
-extern short LittleShort (short l);
-extern int BigLong (int l);
-extern int LittleLong (int l);
-extern float BigFloat (float l);
-extern float LittleFloat (float l);
-
-//============================================================================
-
-
-int COM_Argc (void);
-char *COM_Argv (int arg); // range and null checked
-void COM_ClearArgv (int arg);
-int COM_CheckParm (char *parm);
-void COM_AddParm (char *parm);
-
-void COM_Init (void);
-void COM_InitArgv (int argc, char **argv);
-
-char *CopyString (char *in);
-
-//============================================================================
-
-void Info_Print (char *s);
-
-
-/* crc.h */
-
-void CRC_Init(unsigned short *crcvalue);
-void CRC_ProcessByte(unsigned short *crcvalue, byte data);
-unsigned short CRC_Value(unsigned short crcvalue);
-unsigned short CRC_Block (byte *start, int count);
-
-
-
-/*
-==============================================================
-
-PROTOCOL
-
-==============================================================
-*/
-
-// protocol.h -- communications protocols
-
-#define PROTOCOL_VERSION 34
-
-//=========================================
-
-#define PORT_MASTER 27900
-#define PORT_CLIENT 27901
-#define PORT_SERVER 27910
-
-//=========================================
-
-#define UPDATE_BACKUP 16 // copies of entity_state_t to keep buffered
- // must be power of two
-#define UPDATE_MASK (UPDATE_BACKUP-1)
-
-
-
-//==================
-// the svc_strings[] array in cl_parse.c should mirror this
-//==================
-
-//
-// server to client: protocol bytes that can be directly added to messages
-//
-enum svc_ops_e
-{
- svc_bad,
-
- // these ops are known to the game dll
- svc_muzzleflash,
- svc_muzzleflash2,
- svc_temp_entity,
- svc_layout,
- svc_inventory,
-
- // the rest are private to the client and server
- svc_nop,
- svc_disconnect,
- svc_reconnect,
- svc_sound, // <see code>
- svc_print, // [byte] id [string] null terminated string
- svc_stufftext, // [string] stuffed into client's console buffer, should be \n terminated
- svc_serverdata, // [long] protocol ...
- svc_configstring, // [short] [string]
- svc_spawnbaseline,
- svc_centerprint, // [string] to put in center of the screen
- svc_download, // [short] size [size bytes]
- svc_playerinfo, // variable
- svc_packetentities, // [...]
- svc_deltapacketentities, // [...]
- svc_frame
-};
-
-//==============================================
-
-//
-// client to server
-//
-enum clc_ops_e
-{
- clc_bad,
- clc_nop,
- clc_move, // [[usercmd_t]
- clc_userinfo, // [[userinfo string]
- clc_stringcmd // [string] message
-};
-
-//==============================================
-
-// plyer_state_t communication
-
-#define PS_M_TYPE (1<<0)
-#define PS_M_ORIGIN (1<<1)
-#define PS_M_VELOCITY (1<<2)
-#define PS_M_TIME (1<<3)
-#define PS_M_FLAGS (1<<4)
-#define PS_M_GRAVITY (1<<5)
-#define PS_M_DELTA_ANGLES (1<<6)
-
-#define PS_VIEWOFFSET (1<<7)
-#define PS_VIEWANGLES (1<<8)
-#define PS_KICKANGLES (1<<9)
-#define PS_BLEND (1<<10)
-#define PS_FOV (1<<11)
-#define PS_WEAPONINDEX (1<<12)
-#define PS_WEAPONFRAME (1<<13)
-#define PS_RDFLAGS (1<<14)
-
-//==============================================
-
-// user_cmd_t communication
-
-// ms and light always sent, the others are optional
-#define CM_ANGLE1 (1<<0)
-#define CM_ANGLE2 (1<<1)
-#define CM_ANGLE3 (1<<2)
-#define CM_FORWARD (1<<3)
-#define CM_SIDE (1<<4)
-#define CM_UP (1<<5)
-#define CM_BUTTONS (1<<6)
-#define CM_IMPULSE (1<<7)
-
-//==============================================
-
-// a sound without an ent or pos will be a local only sound
-#define SND_VOLUME (1<<0) // a byte
-#define SND_ATTENUATION (1<<1) // a byte
-#define SND_POS (1<<2) // three coordinates
-#define SND_ENT (1<<3) // a short 0-2: channel, 3-12: entity
-#define SND_OFFSET (1<<4) // a byte, msec offset from frame start
-
-#define DEFAULT_SOUND_PACKET_VOLUME 1.0
-#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0
-
-//==============================================
-
-// entity_state_t communication
-
-// try to pack the common update flags into the first byte
-#define U_ORIGIN1 (1<<0)
-#define U_ORIGIN2 (1<<1)
-#define U_ANGLE2 (1<<2)
-#define U_ANGLE3 (1<<3)
-#define U_FRAME8 (1<<4) // frame is a byte
-#define U_EVENT (1<<5)
-#define U_REMOVE (1<<6) // REMOVE this entity, don't add it
-#define U_MOREBITS1 (1<<7) // read one additional byte
-
-// second byte
-#define U_NUMBER16 (1<<8) // NUMBER8 is implicit if not set
-#define U_ORIGIN3 (1<<9)
-#define U_ANGLE1 (1<<10)
-#define U_MODEL (1<<11)
-#define U_RENDERFX8 (1<<12) // fullbright, etc
-#define U_EFFECTS8 (1<<14) // autorotate, trails, etc
-#define U_MOREBITS2 (1<<15) // read one additional byte
-
-// third byte
-#define U_SKIN8 (1<<16)
-#define U_FRAME16 (1<<17) // frame is a short
-#define U_RENDERFX16 (1<<18) // 8 + 16 = 32
-#define U_EFFECTS16 (1<<19) // 8 + 16 = 32
-#define U_MODEL2 (1<<20) // weapons, flags, etc
-#define U_MODEL3 (1<<21)
-#define U_MODEL4 (1<<22)
-#define U_MOREBITS3 (1<<23) // read one additional byte
-
-// fourth byte
-#define U_OLDORIGIN (1<<24) // FIXME: get rid of this
-#define U_SKIN16 (1<<25)
-#define U_SOUND (1<<26)
-#define U_SOLID (1<<27)
-
-
-/*
-==============================================================
-
-CMD
-
-Command text buffering and command execution
-
-==============================================================
-*/
-
-/*
-
-Any number of commands can be added in a frame, from several different sources.
-Most commands come from either keybindings or console line input, but remote
-servers can also send across commands and entire text files can be execed.
-
-The + command line options are also added to the command buffer.
-
-The game starts with a Cbuf_AddText ("exec quake.rc\n"); Cbuf_Execute ();
-
-*/
-
-void Cbuf_Init (void);
-// allocates an initial text buffer that will grow as needed
-
-void Cbuf_AddText (char *text);
-// as new commands are generated from the console or keybindings,
-// the text is added to the end of the command buffer.
-
-void Cbuf_InsertText (char *text);
-// when a command wants to issue other commands immediately, the text is
-// inserted at the beginning of the buffer, before any remaining unexecuted
-// commands.
-
-void Cbuf_ExecuteText (int exec_when, char *text);
-// this can be used in place of either Cbuf_AddText or Cbuf_InsertText
-
-void Cbuf_AddEarlyCommands (qboolean clear);
-// adds all the +set commands from the command line
-
-qboolean Cbuf_AddLateCommands (void);
-// adds all the remaining + commands from the command line
-// Returns true if any late commands were added, which
-// will keep the demoloop from immediately starting
-
-void Cbuf_Execute (void);
-// Pulls off \n terminated lines of text from the command buffer and sends
-// them through Cmd_ExecuteString. Stops when the buffer is empty.
-// Normally called once per frame, but may be explicitly invoked.
-// Do not call inside a command function!
-
-void Cbuf_CopyToDefer (void);
-void Cbuf_InsertFromDefer (void);
-// These two functions are used to defer any pending commands while a map
-// is being loaded
-
-//===========================================================================
-
-/*
-
-Command execution takes a null terminated string, breaks it into tokens,
-then searches for a command or variable that matches the first token.
-
-*/
-
-typedef void (*xcommand_t) (void);
-
-void Cmd_Init (void);
-
-void Cmd_AddCommand (char *cmd_name, xcommand_t function);
-// called by the init functions of other parts of the program to
-// register commands and functions to call for them.
-// The cmd_name is referenced later, so it should not be in temp memory
-// if function is NULL, the command will be forwarded to the server
-// as a clc_stringcmd instead of executed locally
-void Cmd_RemoveCommand (char *cmd_name);
-
-qboolean Cmd_Exists (char *cmd_name);
-// used by the cvar code to check for cvar / command name overlap
-
-char *Cmd_CompleteCommand (char *partial);
-// attempts to match a partial command for automatic command line completion
-// returns NULL if nothing fits
-
-int Cmd_Argc (void);
-char *Cmd_Argv (int arg);
-char *Cmd_Args (void);
-// The functions that execute commands get their parameters with these
-// functions. Cmd_Argv () will return an empty string, not a NULL
-// if arg > argc, so string operations are always safe.
-
-void Cmd_TokenizeString (char *text, qboolean macroExpand);
-// Takes a null terminated string. Does not need to be /n terminated.
-// breaks the string up into arg tokens.
-
-void Cmd_ExecuteString (char *text);
-// Parses a single line of text into arguments and tries to execute it
-// as if it was typed at the console
-
-void Cmd_ForwardToServer (void);
-// adds the current command line as a clc_stringcmd to the client message.
-// things like godmode, noclip, etc, are commands directed to the server,
-// so when they are typed in at the console, they will need to be forwarded.
-
-
-/*
-==============================================================
-
-CVAR
-
-==============================================================
-*/
-
-/*
-
-cvar_t variables are used to hold scalar or string variables that can be changed or displayed at the console or prog code as well as accessed directly
-in C code.
-
-The user can access cvars from the console in three ways:
-r_draworder prints the current value
-r_draworder 0 sets the current value to 0
-set r_draworder 0 as above, but creates the cvar if not present
-Cvars are restricted from having the same names as commands to keep this
-interface from being ambiguous.
-*/
-
-extern cvar_t *cvar_vars;
-
-cvar_t *Cvar_Get (char *var_name, char *value, int flags);
-// creates the variable if it doesn't exist, or returns the existing one
-// if it exists, the value will not be changed, but flags will be ORed in
-// that allows variables to be unarchived without needing bitflags
-
-cvar_t *Cvar_Set (char *var_name, char *value);
-// will create the variable if it doesn't exist
-
-cvar_t *Cvar_ForceSet (char *var_name, char *value);
-// will set the variable even if NOSET or LATCH
-
-cvar_t *Cvar_FullSet (char *var_name, char *value, int flags);
-
-void Cvar_SetValue (char *var_name, float value);
-// expands value to a string and calls Cvar_Set
-
-float Cvar_VariableValue (char *var_name);
-// returns 0 if not defined or non numeric
-
-char *Cvar_VariableString (char *var_name);
-// returns an empty string if not defined
-
-char *Cvar_CompleteVariable (char *partial);
-// attempts to match a partial variable name for command line completion
-// returns NULL if nothing fits
-
-void Cvar_GetLatchedVars (void);
-// any CVAR_LATCHED variables that have been set will now take effect
-
-qboolean Cvar_Command (void);
-// called by Cmd_ExecuteString when Cmd_Argv(0) doesn't match a known
-// command. Returns true if the command was a variable reference that
-// was handled. (print or change)
-
-void Cvar_WriteVariables (char *path);
-// appends lines containing "set variable value" for all variables
-// with the archive flag set to true.
-
-void Cvar_Init (void);
-
-char *Cvar_Userinfo (void);
-// returns an info string containing all the CVAR_USERINFO cvars
-
-char *Cvar_Serverinfo (void);
-// returns an info string containing all the CVAR_SERVERINFO cvars
-
-extern qboolean userinfo_modified;
-// this is set each time a CVAR_USERINFO variable is changed
-// so that the client knows to send it to the server
-
-/*
-==============================================================
-
-NET
-
-==============================================================
-*/
-
-// net.h -- quake's interface to the networking layer
-
-#define PORT_ANY -1
-
-#define MAX_MSGLEN 1400 // max length of a message
-#define PACKET_HEADER 10 // two ints and a short
-
-typedef enum {NA_LOOPBACK, NA_BROADCAST, NA_IP, NA_IPX, NA_BROADCAST_IPX} netadrtype_t;
-
-typedef enum {NS_CLIENT, NS_SERVER} netsrc_t;
-
-typedef struct
-{
- netadrtype_t type;
-
- byte ip[4];
- byte ipx[10];
-
- unsigned short port;
-} netadr_t;
-
-void NET_Init (void);
-void NET_Shutdown (void);
-
-void NET_Config (qboolean multiplayer);
-
-qboolean NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message);
-void NET_SendPacket (netsrc_t sock, int length, void *data, netadr_t to);
-
-qboolean NET_CompareAdr (netadr_t a, netadr_t b);
-qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b);
-qboolean NET_IsLocalAddress (netadr_t adr);
-char *NET_AdrToString (netadr_t a);
-qboolean NET_StringToAdr (char *s, netadr_t *a);
-void NET_Sleep(int msec);
-
-//============================================================================
-
-#define OLD_AVG 0.99 // total = oldtotal*OLD_AVG + new*(1-OLD_AVG)
-
-#define MAX_LATENT 32
-
-typedef struct
-{
- qboolean fatal_error;
-
- netsrc_t sock;
-
- int dropped; // between last packet and previous
-
- int last_received; // for timeouts
- int last_sent; // for retransmits
-
- netadr_t remote_address;
- int qport; // qport value to write when transmitting
-
-// sequencing variables
- int incoming_sequence;
- int incoming_acknowledged;
- int incoming_reliable_acknowledged; // single bit
-
- int incoming_reliable_sequence; // single bit, maintained local
-
- int outgoing_sequence;
- int reliable_sequence; // single bit
- int last_reliable_sequence; // sequence number of last send
-
-// reliable staging and holding areas
- sizebuf_t message; // writing buffer to send to server
- byte message_buf[MAX_MSGLEN-16]; // leave space for header
-
-// message is copied to this buffer when it is first transfered
- int reliable_length;
- byte reliable_buf[MAX_MSGLEN-16]; // unacked reliable message
-} netchan_t;
-
-extern netadr_t net_from;
-extern sizebuf_t net_message;
-extern byte net_message_buffer[MAX_MSGLEN];
-
-
-void Netchan_Init (void);
-void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t adr, int qport);
-
-qboolean Netchan_NeedReliable (netchan_t *chan);
-void Netchan_Transmit (netchan_t *chan, int length, byte *data);
-void Netchan_OutOfBand (int net_socket, netadr_t adr, int length, byte *data);
-void Netchan_OutOfBandPrint (int net_socket, netadr_t adr, char *format, ...);
-qboolean Netchan_Process (netchan_t *chan, sizebuf_t *msg);
-
-qboolean Netchan_CanReliable (netchan_t *chan);
-
-
-/*
-==============================================================
-
-CMODEL
-
-==============================================================
-*/
-
-
-cmodel_t *CM_LoadMap (char *name, qboolean clientload, unsigned *checksum);
-cmodel_t *CM_InlineModel (char *name); // *1, *2, etc
-
-int CM_NumClusters (void);
-int CM_NumInlineModels (void);
-char *CM_EntityString (void);
-
-// creates a clipping hull for an arbitrary box
-int CM_HeadnodeForBox (vec3_t mins, vec3_t maxs);
-
-
-// returns an ORed contents mask
-int CM_PointContents (vec3_t p, int headnode);
-int CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t angles);
-
-trace_t CM_BoxTrace (vec3_t start, vec3_t end,
- vec3_t mins, vec3_t maxs,
- int headnode, int brushmask);
-trace_t CM_TransformedBoxTrace (vec3_t start, vec3_t end,
- vec3_t mins, vec3_t maxs,
- int headnode, int brushmask,
- vec3_t origin, vec3_t angles);
-
-byte *CM_ClusterPVS (int cluster);
-byte *CM_ClusterPHS (int cluster);
-
-int CM_PointLeafnum (vec3_t p);
-
-// call with topnode set to the headnode, returns with topnode
-// set to the first node that splits the box
-int CM_BoxLeafnums (vec3_t mins, vec3_t maxs, int *list,
- int listsize, int *topnode);
-
-int CM_LeafContents (int leafnum);
-int CM_LeafCluster (int leafnum);
-int CM_LeafArea (int leafnum);
-
-void CM_SetAreaPortalState (int portalnum, qboolean open);
-qboolean CM_AreasConnected (int area1, int area2);
-
-int CM_WriteAreaBits (byte *buffer, int area);
-qboolean CM_HeadnodeVisible (int headnode, byte *visbits);
-
-void CM_WritePortalState (FILE *f);
-void CM_ReadPortalState (FILE *f);
-
-/*
-==============================================================
-
-PLAYER MOVEMENT CODE
-
-Common between server and client so prediction matches
-
-==============================================================
-*/
-
-extern float pm_airaccelerate;
-
-void Pmove (pmove_t *pmove);
-
-/*
-==============================================================
-
-FILESYSTEM
-
-==============================================================
-*/
-
-void FS_InitFilesystem (void);
-void FS_SetGamedir (char *dir);
-char *FS_Gamedir (void);
-char *FS_NextPath (char *prevpath);
-void FS_ExecAutoexec (void);
-
-int FS_FOpenFile (char *filename, FILE **file);
-void FS_FCloseFile (FILE *f);
-// note: this can't be called from another DLL, due to MS libc issues
-
-int FS_LoadFile (char *path, void **buffer);
-// a null buffer will just return the file length without loading
-// a -1 length is not present
-
-void FS_Read (void *buffer, int len, FILE *f);
-// properly handles partial reads
-
-void FS_FreeFile (void *buffer);
-
-void FS_CreatePath (char *path);
-
-
-/*
-==============================================================
-
-MISC
-
-==============================================================
-*/
-
-#define ERR_FATAL 0 // exit the entire game with a popup window
-#define ERR_DROP 1 // print to console and disconnect from game
-#define ERR_QUIT 2 // not an error, just a normal exit
-#define ERR_DISCONNECT 2 // don't kill server
-
-#define EXEC_NOW 0 // don't return until completed
-#define EXEC_INSERT 1 // insert at current position, but don't run yet
-#define EXEC_APPEND 2 // add to end of the command buffer
-
-#define PRINT_ALL 0
-#define PRINT_DEVELOPER 1 // only print when "developer 1"
-
-void Com_BeginRedirect (int target, char *buffer, int buffersize, void (*flush));
-void Com_EndRedirect (void);
-void Com_Printf (char *fmt, ...);
-void Com_DPrintf (char *fmt, ...);
-void Com_Error (int code, char *fmt, ...);
-void Com_Quit (void);
-
-int Com_ServerState (void); // this should have just been a cvar...
-void Com_SetServerState (int state);
-
-unsigned Com_BlockChecksum (void *buffer, int length);
-byte COM_BlockSequenceCRCByte (byte *base, int length, int sequence);
-
-float qfrand(void); // 0 ti 1
-float crand(void); // -1 to 1
-
-extern cvar_t *developer;
-extern cvar_t *dedicated;
-extern cvar_t *host_speeds;
-extern cvar_t *log_stats;
-
-extern FILE *log_stats_file;
-
-// host_speeds times
-extern int time_before_game;
-extern int time_after_game;
-extern int time_before_ref;
-extern int time_after_ref;
-
-void Z_Free (void *ptr);
-void *Z_Malloc (int size); // returns 0 filled memory
-void *Z_TagMalloc (int size, int tag);
-void Z_FreeTags (int tag);
-
-void Qcommon_Init (int argc, char **argv);
-void Qcommon_Frame (int msec);
-
-#define NUMVERTEXNORMALS 162
-extern vec3_t bytedirs[NUMVERTEXNORMALS];
-
-// this is in the client code, but can be used for debugging from server
-void SCR_DebugGraph (float value, int color);
-
-
-/*
-==============================================================
-
-NON-PORTABLE SYSTEM SERVICES
-
-==============================================================
-*/
-
-enum{
- THin = 1,
- THsnd = 2,
- THnet = 3
-};
-
-extern uint sys_frame_time;
-
-void Sys_Init (void);
-
-void Sys_AppActivate (void);
-
-void Sys_UnloadGame (void);
-
-char *Sys_ConsoleInput (void);
-void Sys_ConsoleOutput (char *string);
-void Sys_SendKeyEvents (void);
-void Sys_Error (char *error, ...);
-void Sys_Quit (void);
-char *Sys_GetClipboardData( void );
-void Sys_CopyProtect (void);
-
-/*
-==============================================================
-
-CLIENT / SERVER SYSTEMS
-
-==============================================================
-*/
-
-void CL_Init (void);
-void CL_Drop (void);
-void CL_Shutdown (void);
-void CL_Frame (int msec);
-void Con_Print (char *text);
-void SCR_BeginLoadingPlaque (void);
-
-void SV_Init (void);
-void SV_Shutdown (char *finalmsg, qboolean reconnect);
-void SV_Frame (int msec);
--- a/qcommon/qfiles.h
+++ /dev/null
@@ -1,460 +1,0 @@
-//
-// qfiles.h: quake file formats
-// This file must be identical in the quake and utils directories
-//
-
-/*
-========================================================================
-
-The .pak files are just a linear collapse of a directory tree
-
-========================================================================
-*/
-
-#define IDPAKHEADER (('K'<<24)+('C'<<16)+('A'<<8)+'P')
-
-#pragma pack on
-
-typedef struct
-{
- char name[56];
- int filepos, filelen;
-} dpackfile_t;
-
-typedef struct
-{
- int ident; // == IDPAKHEADER
- int dirofs;
- int dirlen;
-} dpackheader_t;
-
-#define MAX_FILES_IN_PACK 4096
-
-
-/*
-========================================================================
-
-PCX files are used for as many images as possible
-
-========================================================================
-*/
-
-typedef struct
-{
- char manufacturer;
- char version;
- char encoding;
- char bits_per_pixel;
- unsigned short xmin,ymin,xmax,ymax;
- unsigned short hres,vres;
- unsigned char palette[48];
- char reserved;
- char color_planes;
- unsigned short bytes_per_line;
- unsigned short palette_type;
- char filler[58];
- unsigned char data; // unbounded
-} pcx_t;
-
-
-/*
-========================================================================
-
-.MD2 triangle model file format
-
-========================================================================
-*/
-
-#define IDALIASHEADER (('2'<<24)+('P'<<16)+('D'<<8)+'I')
-#define ALIAS_VERSION 8
-
-#define MAX_TRIANGLES 4096
-#define MAX_VERTS 2048
-#define MAX_FRAMES 512
-#define MAX_MD2SKINS 32
-#define MAX_SKINNAME 64
-
-typedef struct
-{
- short s;
- short t;
-} dstvert_t;
-
-typedef struct
-{
- short index_xyz[3];
- short index_st[3];
-} dtriangle_t;
-
-typedef struct
-{
- byte v[3]; // scaled byte to fit in frame mins/maxs
- byte lightnormalindex;
-} dtrivertx_t;
-
-#define DTRIVERTX_V0 0
-#define DTRIVERTX_V1 1
-#define DTRIVERTX_V2 2
-#define DTRIVERTX_LNI 3
-#define DTRIVERTX_SIZE 4
-
-typedef struct
-{
- float scale[3]; // multiply byte verts by this
- float translate[3]; // then add this
- char name[16]; // frame name from grabbing
- dtrivertx_t verts[1]; // variable sized
-} daliasframe_t;
-
-
-// the glcmd format:
-// a positive integer starts a tristrip command, followed by that many
-// vertex structures.
-// a negative integer starts a trifan command, followed by -x vertexes
-// a zero indicates the end of the command list.
-// a vertex consists of a floating point s, a floating point t,
-// and an integer vertex index.
-
-
-typedef struct
-{
- int ident;
- int version;
-
- int skinwidth;
- int skinheight;
- int framesize; // byte size of each frame
-
- int num_skins;
- int num_xyz;
- int num_st; // greater than num_xyz for seams
- int num_tris;
- int num_glcmds; // dwords in strip/fan command list
- int num_frames;
-
- int ofs_skins; // each skin is a MAX_SKINNAME string
- int ofs_st; // byte offset from start for stverts
- int ofs_tris; // offset for dtriangles
- int ofs_frames; // offset for first frame
- int ofs_glcmds;
- int ofs_end; // end of file
-
-} dmdl_t;
-
-/*
-========================================================================
-
-.SP2 sprite file format
-
-========================================================================
-*/
-
-#define IDSPRITEHEADER (('2'<<24)+('S'<<16)+('D'<<8)+'I')
- // little-endian "IDS2"
-#define SPRITE_VERSION 2
-
-typedef struct
-{
- int width, height;
- int origin_x, origin_y; // raster coordinates inside pic
- char name[MAX_SKINNAME]; // name of pcx file
-} dsprframe_t;
-
-typedef struct {
- int ident;
- int version;
- int numframes;
- dsprframe_t frames[1]; // variable sized
-} dsprite_t;
-
-/*
-==============================================================================
-
- .WAL texture file format
-
-==============================================================================
-*/
-
-
-#define MIPLEVELS 4
-typedef struct miptex_s
-{
- char name[32];
- unsigned width, height;
- unsigned offsets[MIPLEVELS]; // four mip maps stored
- char animname[32]; // next frame in animation chain
- int flags;
- int contents;
- int value;
-} miptex_t;
-
-
-
-/*
-==============================================================================
-
- .BSP file format
-
-==============================================================================
-*/
-
-#define IDBSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I')
- // little-endian "IBSP"
-
-#define BSPVERSION 38
-
-
-// upper design bounds
-// leaffaces, leafbrushes, planes, and verts are still bounded by
-// 16 bit short limits
-#define MAX_MAP_MODELS 1024
-#define MAX_MAP_BRUSHES 8192
-#define MAX_MAP_ENTITIES 2048
-#define MAX_MAP_ENTSTRING 0x40000
-#define MAX_MAP_TEXINFO 8192
-
-#define MAX_MAP_AREAS 256
-#define MAX_MAP_AREAPORTALS 1024
-#define MAX_MAP_PLANES 65536
-#define MAX_MAP_NODES 65536
-#define MAX_MAP_BRUSHSIDES 65536
-#define MAX_MAP_LEAFS 65536
-#define MAX_MAP_VERTS 65536
-#define MAX_MAP_FACES 65536
-#define MAX_MAP_LEAFFACES 65536
-#define MAX_MAP_LEAFBRUSHES 65536
-#define MAX_MAP_PORTALS 65536
-#define MAX_MAP_EDGES 128000
-#define MAX_MAP_SURFEDGES 256000
-#define MAX_MAP_LIGHTING 0x200000
-#define MAX_MAP_VISIBILITY 0x100000
-
-// key / value pair sizes
-
-#define MAX_KEY 32
-#define MAX_VALUE 1024
-
-//=============================================================================
-
-typedef struct
-{
- int fileofs, filelen;
-} lump_t;
-
-#define LUMP_ENTITIES 0
-#define LUMP_PLANES 1
-#define LUMP_VERTEXES 2
-#define LUMP_VISIBILITY 3
-#define LUMP_NODES 4
-#define LUMP_TEXINFO 5
-#define LUMP_FACES 6
-#define LUMP_LIGHTING 7
-#define LUMP_LEAFS 8
-#define LUMP_LEAFFACES 9
-#define LUMP_LEAFBRUSHES 10
-#define LUMP_EDGES 11
-#define LUMP_SURFEDGES 12
-#define LUMP_MODELS 13
-#define LUMP_BRUSHES 14
-#define LUMP_BRUSHSIDES 15
-#define LUMP_POP 16
-#define LUMP_AREAS 17
-#define LUMP_AREAPORTALS 18
-#define HEADER_LUMPS 19
-
-typedef struct
-{
- int ident;
- int version;
- lump_t lumps[HEADER_LUMPS];
-} dheader_t;
-
-typedef struct
-{
- float mins[3], maxs[3];
- float origin[3]; // for sounds or lights
- int headnode;
- int firstface, numfaces; // submodels just draw faces
- // without walking the bsp tree
-} dmodel_t;
-
-typedef struct
-{
- float point[3];
-} dvertex_t;
-
-// 0-2 are axial planes
-#define PLANE_X 0
-#define PLANE_Y 1
-#define PLANE_Z 2
-
-// 3-5 are non-axial planes snapped to the nearest
-#define PLANE_ANYX 3
-#define PLANE_ANYY 4
-#define PLANE_ANYZ 5
-
-// planes (x&~1) and (x&~1)+1 are always opposites
-
-typedef struct
-{
- float normal[3];
- float dist;
- int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
-} dplane_t;
-
-// contents flags are seperate bits
-// a given brush can contribute multiple content bits
-// multiple brushes can be in a single leaf
-
-// these definitions also need to be in q_shared.h!
-
-/* ^-- macro redefinitions
-// lower bits are stronger, and will eat weaker brushes completely
-#define CONTENTS_SOLID 1 // an eye is never valid in a solid
-#define CONTENTS_WINDOW 2 // translucent, but not watery
-#define CONTENTS_AUX 4
-#define CONTENTS_LAVA 8
-#define CONTENTS_SLIME 16
-#define CONTENTS_WATER 32
-#define CONTENTS_MIST 64
-#define LAST_VISIBLE_CONTENTS 64
-
-// remaining contents are non-visible, and don't eat brushes
-
-#define CONTENTS_AREAPORTAL 0x8000
-
-#define CONTENTS_PLAYERCLIP 0x10000
-#define CONTENTS_MONSTERCLIP 0x20000
-
-// currents can be added to any other contents, and may be mixed
-#define CONTENTS_CURRENT_0 0x40000
-#define CONTENTS_CURRENT_90 0x80000
-#define CONTENTS_CURRENT_180 0x100000
-#define CONTENTS_CURRENT_270 0x200000
-#define CONTENTS_CURRENT_UP 0x400000
-#define CONTENTS_CURRENT_DOWN 0x800000
-
-#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity
-
-#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game
-#define CONTENTS_DEADMONSTER 0x4000000
-#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs
-#define CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans
-#define CONTENTS_LADDER 0x20000000
-
-
-
-#define SURF_LIGHT 0x1 // value will hold the light strength
-
-#define SURF_SLICK 0x2 // effects game physics
-
-#define SURF_SKY 0x4 // don't draw, but add to skybox
-#define SURF_WARP 0x8 // turbulent water warp
-#define SURF_TRANS33 0x10
-#define SURF_TRANS66 0x20
-#define SURF_FLOWING 0x40 // scroll towards angle
-#define SURF_NODRAW 0x80 // don't bother referencing the texture
-*/
-
-typedef struct
-{
- int planenum;
- int children[2]; // negative numbers are -(leafs+1), not nodes
- short mins[3]; // for frustom culling
- short maxs[3];
- unsigned short firstface;
- unsigned short numfaces; // counting both sides
-} dnode_t;
-
-typedef struct texinfo_s
-{
- float vecs[2][4]; // [s/t][xyz offset]
- int flags; // miptex flags + overrides
- int value; // light emission, etc
- char texture[32]; // texture name (textures/*.wal)
- int nexttexinfo; // for animations, -1 = end of chain
-} texinfo_t;
-
-// note that edge 0 is never used, because negative edge nums are used for
-// counterclockwise use of the edge in a face
-typedef struct
-{
- unsigned short v[2]; // vertex numbers
-} dedge_t;
-
-#define MAXLIGHTMAPS 4
-typedef struct
-{
- unsigned short planenum;
- short side;
-
- int firstedge; // we must support > 64k edges
- short numedges;
- short texinfo;
-
-// lighting info
- byte styles[MAXLIGHTMAPS];
- int lightofs; // start of [numstyles*surfsize] samples
-} dface_t;
-
-typedef struct
-{
- int contents; // OR of all brushes (not needed?)
-
- short cluster;
- short area;
-
- short mins[3]; // for frustum culling
- short maxs[3];
-
- unsigned short firstleafface;
- unsigned short numleaffaces;
-
- unsigned short firstleafbrush;
- unsigned short numleafbrushes;
-} dleaf_t;
-
-typedef struct
-{
- unsigned short planenum; // facing out of the leaf
- short texinfo;
-} dbrushside_t;
-
-typedef struct
-{
- int firstside;
- int numsides;
- int contents;
-} dbrush_t;
-
-#define ANGLE_UP -1
-#define ANGLE_DOWN -2
-
-
-// the visibility lump consists of a header with a count, then
-// byte offsets for the PVS and PHS of each cluster, then the raw
-// compressed bit vectors
-#define DVIS_PVS 0
-#define DVIS_PHS 1
-typedef struct
-{
- int numclusters;
- int bitofs[8][2]; // bitofs[numclusters][2]
-} dvis_t;
-
-// each area has a list of portals that lead into other areas
-// when portals are closed, other areas may not be visible or
-// hearable even if the vis info says that it should be
-typedef struct
-{
- int portalnum;
- int otherarea;
-} dareaportal_t;
-
-typedef struct
-{
- int numareaportals;
- int firstareaportal;
-} darea_t;
-
-#pragma pack off
--- /dev/null
+++ b/qmenu.c
@@ -1,0 +1,652 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "dat.h"
+#include "fns.h"
+
+void Action_DoEnter( menuaction_t *a );
+void Action_Draw( menuaction_t *a );
+void Menu_DrawStatusBar( char *string );
+void Menulist_DoEnter( menulist_t *l );
+void MenuList_Draw( menulist_t *l );
+void Separator_Draw( menuseparator_t *s );
+void Slider_DoSlide( menuslider_t *s, int dir );
+void Slider_Draw( menuslider_t *s );
+void SpinControl_DoEnter( menulist_t *s );
+void SpinControl_Draw( menulist_t *s );
+void SpinControl_DoSlide( menulist_t *s, int dir );
+
+#define RCOLUMN_OFFSET 16
+#define LCOLUMN_OFFSET -16
+
+extern refexport_t re;
+
+#define Draw_Char re.DrawChar
+#define Draw_Fill re.DrawFill
+
+void Action_DoEnter( menuaction_t *a )
+{
+ if ( a->generic.callback )
+ a->generic.callback( a );
+}
+
+void Action_Draw( menuaction_t *a )
+{
+ if ( a->generic.flags & QMF_LEFT_JUSTIFY )
+ {
+ if ( a->generic.flags & QMF_GRAYED )
+ Menu_DrawStringDark( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
+ else
+ Menu_DrawString( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
+ }
+ else
+ {
+ if ( a->generic.flags & QMF_GRAYED )
+ Menu_DrawStringR2LDark( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
+ else
+ Menu_DrawStringR2L( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
+ }
+ if ( a->generic.ownerdraw )
+ a->generic.ownerdraw( a );
+}
+
+qboolean Field_DoEnter( menufield_t *f )
+{
+ if ( f->generic.callback )
+ {
+ f->generic.callback( f );
+ return true;
+ }
+ return false;
+}
+
+void Field_Draw( menufield_t *f )
+{
+ int i;
+ char tempbuffer[128]="";
+
+ if ( f->generic.name )
+ Menu_DrawStringR2LDark( f->generic.x + f->generic.parent->x + LCOLUMN_OFFSET, f->generic.y + f->generic.parent->y, f->generic.name );
+
+ strncpy( tempbuffer, f->buffer + f->visible_offset, f->visible_length );
+
+ Draw_Char( f->generic.x + f->generic.parent->x + 16, f->generic.y + f->generic.parent->y - 4, 18 );
+ Draw_Char( f->generic.x + f->generic.parent->x + 16, f->generic.y + f->generic.parent->y + 4, 24 );
+
+ Draw_Char( f->generic.x + f->generic.parent->x + 24 + f->visible_length * 8, f->generic.y + f->generic.parent->y - 4, 20 );
+ Draw_Char( f->generic.x + f->generic.parent->x + 24 + f->visible_length * 8, f->generic.y + f->generic.parent->y + 4, 26 );
+
+ for ( i = 0; i < f->visible_length; i++ )
+ {
+ Draw_Char( f->generic.x + f->generic.parent->x + 24 + i * 8, f->generic.y + f->generic.parent->y - 4, 19 );
+ Draw_Char( f->generic.x + f->generic.parent->x + 24 + i * 8, f->generic.y + f->generic.parent->y + 4, 25 );
+ }
+
+ Menu_DrawString( f->generic.x + f->generic.parent->x + 24, f->generic.y + f->generic.parent->y, tempbuffer );
+
+ if ( Menu_ItemAtCursor( f->generic.parent ) == f )
+ {
+ int offset;
+
+ if ( f->visible_offset )
+ offset = f->visible_length;
+ else
+ offset = f->cursor;
+
+ if ( ( ( int ) ( Sys_Milliseconds() / 250 ) ) & 1 )
+ {
+ Draw_Char( f->generic.x + f->generic.parent->x + ( offset + 2 ) * 8 + 8,
+ f->generic.y + f->generic.parent->y,
+ 11 );
+ }
+ else
+ {
+ Draw_Char( f->generic.x + f->generic.parent->x + ( offset + 2 ) * 8 + 8,
+ f->generic.y + f->generic.parent->y,
+ ' ' );
+ }
+ }
+}
+
+qboolean Field_Key( menufield_t *f, int key )
+{
+ extern int keydown[];
+
+ switch ( key )
+ {
+ case K_KP_SLASH:
+ key = '/';
+ break;
+ case K_KP_MINUS:
+ key = '-';
+ break;
+ case K_KP_PLUS:
+ key = '+';
+ break;
+ case K_KP_HOME:
+ key = '7';
+ break;
+ case K_KP_UPARROW:
+ key = '8';
+ break;
+ case K_KP_PGUP:
+ key = '9';
+ break;
+ case K_KP_LEFTARROW:
+ key = '4';
+ break;
+ case K_KP_5:
+ key = '5';
+ break;
+ case K_KP_RIGHTARROW:
+ key = '6';
+ break;
+ case K_KP_END:
+ key = '1';
+ break;
+ case K_KP_DOWNARROW:
+ key = '2';
+ break;
+ case K_KP_PGDN:
+ key = '3';
+ break;
+ case K_KP_INS:
+ key = '0';
+ break;
+ case K_KP_DEL:
+ key = '.';
+ break;
+ }
+
+ if ( key > 127 )
+ {
+ switch ( key )
+ {
+ case K_DEL:
+ default:
+ return false;
+ }
+ }
+
+ /*
+ ** support pasting from the clipboard
+ */
+ if ( ( toupper( key ) == 'V' && keydown[K_CTRL] ) ||
+ ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keydown[K_SHIFT] ) )
+ {
+ char *cbd;
+
+ if ( ( cbd = Sys_GetClipboardData() ) != 0 )
+ {
+ strtok( cbd, "\n\r\b" );
+
+ strncpy( f->buffer, cbd, f->length - 1 );
+ f->cursor = strlen( f->buffer );
+ f->visible_offset = f->cursor - f->visible_length;
+ if ( f->visible_offset < 0 )
+ f->visible_offset = 0;
+
+ free( cbd );
+ }
+ return true;
+ }
+
+ switch ( key )
+ {
+ case K_KP_LEFTARROW:
+ case K_LEFTARROW:
+ case K_BACKSPACE:
+ if ( f->cursor > 0 )
+ {
+ memmove( &f->buffer[f->cursor-1], &f->buffer[f->cursor], strlen( &f->buffer[f->cursor] ) + 1 );
+ f->cursor--;
+
+ if ( f->visible_offset )
+ {
+ f->visible_offset--;
+ }
+ }
+ break;
+
+ case K_KP_DEL:
+ case K_DEL:
+ memmove( &f->buffer[f->cursor], &f->buffer[f->cursor+1], strlen( &f->buffer[f->cursor+1] ) + 1 );
+ break;
+
+ case K_KP_ENTER:
+ case K_ENTER:
+ case K_ESCAPE:
+ case K_TAB:
+ return false;
+
+ case K_SPACE:
+ default:
+ if ( !isdigit( key ) && ( f->generic.flags & QMF_NUMBERSONLY ) )
+ return false;
+
+ if ( f->cursor < f->length )
+ {
+ f->buffer[f->cursor++] = key;
+ f->buffer[f->cursor] = 0;
+
+ if ( f->cursor > f->visible_length )
+ {
+ f->visible_offset++;
+ }
+ }
+ }
+
+ return true;
+}
+
+void Menu_AddItem( menuframework_t *menu, void *item )
+{
+ if ( menu->nitems == 0 )
+ menu->nslots = 0;
+
+ if ( menu->nitems < MAXMENUITEMS )
+ {
+ menu->items[menu->nitems] = item;
+ ( ( menucommon_t * ) menu->items[menu->nitems] )->parent = menu;
+ menu->nitems++;
+ }
+
+ menu->nslots = Menu_TallySlots( menu );
+}
+
+/*
+** Menu_AdjustCursor
+**
+** This function takes the given menu, the direction, and attempts
+** to adjust the menu's cursor so that it's at the next available
+** slot.
+*/
+void Menu_AdjustCursor( menuframework_t *m, int dir )
+{
+ menucommon_t *citem;
+
+ /*
+ ** see if it's in a valid spot
+ */
+ if ( m->cursor >= 0 && m->cursor < m->nitems )
+ {
+ if ( ( citem = Menu_ItemAtCursor( m ) ) != 0 )
+ {
+ if ( citem->type != MTYPE_SEPARATOR )
+ return;
+ }
+ }
+
+ /*
+ ** it's not in a valid spot, so crawl in the direction indicated until we
+ ** find a valid spot
+ */
+ if ( dir == 1 )
+ {
+ while ( 1 )
+ {
+ citem = Menu_ItemAtCursor( m );
+ if ( citem )
+ if ( citem->type != MTYPE_SEPARATOR )
+ break;
+ m->cursor += dir;
+ if ( m->cursor >= m->nitems )
+ m->cursor = 0;
+ }
+ }
+ else
+ {
+ while ( 1 )
+ {
+ citem = Menu_ItemAtCursor( m );
+ if ( citem )
+ if ( citem->type != MTYPE_SEPARATOR )
+ break;
+ m->cursor += dir;
+ if ( m->cursor < 0 )
+ m->cursor = m->nitems - 1;
+ }
+ }
+}
+
+void Menu_Center( menuframework_t *menu )
+{
+ int height;
+
+ height = ( ( menucommon_t * ) menu->items[menu->nitems-1])->y;
+ height += 10;
+
+ menu->y = ( vid.height - height ) / 2;
+}
+
+void Menu_Draw( menuframework_t *menu )
+{
+ int i;
+ menucommon_t *item;
+
+ /*
+ ** draw contents
+ */
+ for ( i = 0; i < menu->nitems; i++ )
+ {
+ switch ( ( ( menucommon_t * ) menu->items[i] )->type )
+ {
+ case MTYPE_FIELD:
+ Field_Draw( ( menufield_t * ) menu->items[i] );
+ break;
+ case MTYPE_SLIDER:
+ Slider_Draw( ( menuslider_t * ) menu->items[i] );
+ break;
+ case MTYPE_LIST:
+ MenuList_Draw( ( menulist_t * ) menu->items[i] );
+ break;
+ case MTYPE_SPINCONTROL:
+ SpinControl_Draw( ( menulist_t * ) menu->items[i] );
+ break;
+ case MTYPE_ACTION:
+ Action_Draw( ( menuaction_t * ) menu->items[i] );
+ break;
+ case MTYPE_SEPARATOR:
+ Separator_Draw( ( menuseparator_t * ) menu->items[i] );
+ break;
+ }
+ }
+
+ item = Menu_ItemAtCursor( menu );
+
+ if ( item && item->cursordraw )
+ {
+ item->cursordraw( item );
+ }
+ else if ( menu->cursordraw )
+ {
+ menu->cursordraw( menu );
+ }
+ else if ( item && item->type != MTYPE_FIELD )
+ {
+ if ( item->flags & QMF_LEFT_JUSTIFY )
+ {
+ Draw_Char( menu->x + item->x - 24 + item->cursor_offset, menu->y + item->y, 12 + ( ( int ) ( Sys_Milliseconds()/250 ) & 1 ) );
+ }
+ else
+ {
+ Draw_Char( menu->x + item->cursor_offset, menu->y + item->y, 12 + ( ( int ) ( Sys_Milliseconds()/250 ) & 1 ) );
+ }
+ }
+
+ if ( item )
+ {
+ if ( item->statusbarfunc )
+ item->statusbarfunc( ( void * ) item );
+ else if ( item->statusbar )
+ Menu_DrawStatusBar( item->statusbar );
+ else
+ Menu_DrawStatusBar( menu->statusbar );
+
+ }
+ else
+ {
+ Menu_DrawStatusBar( menu->statusbar );
+ }
+}
+
+void Menu_DrawStatusBar( char *string )
+{
+ if ( string )
+ {
+ int l = strlen( string );
+ //int maxrow = vid.height / 8;
+ int maxcol = vid.width / 8;
+ int col = maxcol / 2 - l / 2;
+
+ Draw_Fill( 0, vid.height-8, vid.width, 8, 4 );
+ Menu_DrawString( col*8, vid.height - 8, string );
+ }
+ else
+ {
+ Draw_Fill( 0, vid.height-8, vid.width, 8, 0 );
+ }
+}
+
+void Menu_DrawString( int x, int y, char *string )
+{
+ unsigned i;
+
+ for ( i = 0; i < strlen( string ); i++ )
+ {
+ Draw_Char( ( x + i*8 ), y, string[i] );
+ }
+}
+
+void Menu_DrawStringDark( int x, int y, char *string )
+{
+ unsigned i;
+
+ for ( i = 0; i < strlen( string ); i++ )
+ {
+ Draw_Char( ( x + i*8 ), y, string[i] + 128 );
+ }
+}
+
+void Menu_DrawStringR2L( int x, int y, char *string )
+{
+ unsigned i;
+
+ for ( i = 0; i < strlen( string ); i++ )
+ {
+ Draw_Char( ( x - i*8 ), y, string[strlen(string)-i-1] );
+ }
+}
+
+void Menu_DrawStringR2LDark( int x, int y, char *string )
+{
+ unsigned i;
+
+ for ( i = 0; i < strlen( string ); i++ )
+ {
+ Draw_Char( ( x - i*8 ), y, string[strlen(string)-i-1]+128 );
+ }
+}
+
+void *Menu_ItemAtCursor( menuframework_t *m )
+{
+ if ( m->cursor < 0 || m->cursor >= m->nitems )
+ return 0;
+
+ return m->items[m->cursor];
+}
+
+qboolean Menu_SelectItem( menuframework_t *s )
+{
+ menucommon_t *item = ( menucommon_t * ) Menu_ItemAtCursor( s );
+
+ if ( item )
+ {
+ switch ( item->type )
+ {
+ case MTYPE_FIELD:
+ return Field_DoEnter( ( menufield_t * ) item ) ;
+ case MTYPE_ACTION:
+ Action_DoEnter( ( menuaction_t * ) item );
+ return true;
+ case MTYPE_LIST:
+// Menulist_DoEnter( ( menulist_t * ) item );
+ return false;
+ case MTYPE_SPINCONTROL:
+// SpinControl_DoEnter( ( menulist_t * ) item );
+ return false;
+ }
+ }
+ return false;
+}
+
+void Menu_SetStatusBar( menuframework_t *m, char *string )
+{
+ m->statusbar = string;
+}
+
+void Menu_SlideItem( menuframework_t *s, int dir )
+{
+ menucommon_t *item = ( menucommon_t * ) Menu_ItemAtCursor( s );
+
+ if ( item )
+ {
+ switch ( item->type )
+ {
+ case MTYPE_SLIDER:
+ Slider_DoSlide( ( menuslider_t * ) item, dir );
+ break;
+ case MTYPE_SPINCONTROL:
+ SpinControl_DoSlide( ( menulist_t * ) item, dir );
+ break;
+ }
+ }
+}
+
+int Menu_TallySlots( menuframework_t *menu )
+{
+ int i;
+ int total = 0;
+
+ for ( i = 0; i < menu->nitems; i++ )
+ {
+ if ( ( ( menucommon_t * ) menu->items[i] )->type == MTYPE_LIST )
+ {
+ int nitems = 0;
+ char **n = ( ( menulist_t * ) menu->items[i] )->itemnames;
+
+ while (*n)
+ nitems++, n++;
+
+ total += nitems;
+ }
+ else
+ {
+ total++;
+ }
+ }
+
+ return total;
+}
+
+void Menulist_DoEnter( menulist_t *l )
+{
+ int start;
+
+ start = l->generic.y / 10 + 1;
+
+ l->curvalue = l->generic.parent->cursor - start;
+
+ if ( l->generic.callback )
+ l->generic.callback( l );
+}
+
+void MenuList_Draw( menulist_t *l )
+{
+ char **n;
+ int y = 0;
+
+ Menu_DrawStringR2LDark( l->generic.x + l->generic.parent->x + LCOLUMN_OFFSET, l->generic.y + l->generic.parent->y, l->generic.name );
+
+ n = l->itemnames;
+
+ Draw_Fill( l->generic.x - 112 + l->generic.parent->x, l->generic.parent->y + l->generic.y + l->curvalue*10 + 10, 128, 10, 16 );
+ while ( *n )
+ {
+ Menu_DrawStringR2LDark( l->generic.x + l->generic.parent->x + LCOLUMN_OFFSET, l->generic.y + l->generic.parent->y + y + 10, *n );
+
+ n++;
+ y += 10;
+ }
+}
+
+void Separator_Draw( menuseparator_t *s )
+{
+ if ( s->generic.name )
+ Menu_DrawStringR2LDark( s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y, s->generic.name );
+}
+
+void Slider_DoSlide( menuslider_t *s, int dir )
+{
+ s->curvalue += dir;
+
+ if ( s->curvalue > s->maxvalue )
+ s->curvalue = s->maxvalue;
+ else if ( s->curvalue < s->minvalue )
+ s->curvalue = s->minvalue;
+
+ if ( s->generic.callback )
+ s->generic.callback( s );
+}
+
+#define SLIDER_RANGE 10
+
+void Slider_Draw( menuslider_t *s )
+{
+ int i;
+
+ Menu_DrawStringR2LDark( s->generic.x + s->generic.parent->x + LCOLUMN_OFFSET,
+ s->generic.y + s->generic.parent->y,
+ s->generic.name );
+
+ s->range = ( s->curvalue - s->minvalue ) / ( float ) ( s->maxvalue - s->minvalue );
+
+ if ( s->range < 0)
+ s->range = 0;
+ if ( s->range > 1)
+ s->range = 1;
+ Draw_Char( s->generic.x + s->generic.parent->x + RCOLUMN_OFFSET, s->generic.y + s->generic.parent->y, 128);
+ for ( i = 0; i < SLIDER_RANGE; i++ )
+ Draw_Char( RCOLUMN_OFFSET + s->generic.x + i*8 + s->generic.parent->x + 8, s->generic.y + s->generic.parent->y, 129);
+ Draw_Char( RCOLUMN_OFFSET + s->generic.x + i*8 + s->generic.parent->x + 8, s->generic.y + s->generic.parent->y, 130);
+ Draw_Char( ( int ) ( 8 + RCOLUMN_OFFSET + s->generic.parent->x + s->generic.x + (SLIDER_RANGE-1)*8 * s->range ), s->generic.y + s->generic.parent->y, 131);
+}
+
+void SpinControl_DoEnter( menulist_t *s )
+{
+ s->curvalue++;
+ if ( s->itemnames[s->curvalue] == 0 )
+ s->curvalue = 0;
+
+ if ( s->generic.callback )
+ s->generic.callback( s );
+}
+
+void SpinControl_DoSlide( menulist_t *s, int dir )
+{
+ s->curvalue += dir;
+
+ if ( s->curvalue < 0 )
+ s->curvalue = 0;
+ else if ( s->itemnames[s->curvalue] == 0 )
+ s->curvalue--;
+
+ if ( s->generic.callback )
+ s->generic.callback( s );
+}
+
+void SpinControl_Draw( menulist_t *s )
+{
+ char buffer[100];
+
+ if ( s->generic.name )
+ {
+ Menu_DrawStringR2LDark( s->generic.x + s->generic.parent->x + LCOLUMN_OFFSET,
+ s->generic.y + s->generic.parent->y,
+ s->generic.name );
+ }
+ if ( !strchr( s->itemnames[s->curvalue], '\n' ) )
+ {
+ Menu_DrawString( RCOLUMN_OFFSET + s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y, s->itemnames[s->curvalue] );
+ }
+ else
+ {
+ strcpy( buffer, s->itemnames[s->curvalue] );
+ *strchr( buffer, '\n' ) = 0;
+ Menu_DrawString( RCOLUMN_OFFSET + s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y, buffer );
+ strcpy( buffer, strchr( s->itemnames[s->curvalue], '\n' ) + 1 );
+ Menu_DrawString( RCOLUMN_OFFSET + s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y + 10, buffer );
+ }
+}
+
--- /dev/null
+++ b/r_aclip.c
@@ -1,0 +1,304 @@
+// r_aclip.c: clip routines for drawing Alias models directly to the screen
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+static finalvert_t fv[2][8];
+
+void R_AliasProjectAndClipTestFinalVert (finalvert_t *fv);
+void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1,
+ finalvert_t *out);
+void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1,
+ finalvert_t *out);
+void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1,
+ finalvert_t *out);
+void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1,
+ finalvert_t *out);
+
+
+/*
+================
+R_Alias_clip_z
+
+pfv0 is the unclipped vertex, pfv1 is the z-clipped vertex
+================
+*/
+void R_Alias_clip_z (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
+{
+ float scale;
+
+ scale = (ALIAS_Z_CLIP_PLANE - pfv0->xyz[2]) /
+ (pfv1->xyz[2] - pfv0->xyz[2]);
+
+ out->xyz[0] = pfv0->xyz[0] + (pfv1->xyz[0] - pfv0->xyz[0]) * scale;
+ out->xyz[1] = pfv0->xyz[1] + (pfv1->xyz[1] - pfv0->xyz[1]) * scale;
+ out->xyz[2] = ALIAS_Z_CLIP_PLANE;
+
+ out->s = pfv0->s + (pfv1->s - pfv0->s) * scale;
+ out->t = pfv0->t + (pfv1->t - pfv0->t) * scale;
+ out->l = pfv0->l + (pfv1->l - pfv0->l) * scale;
+
+ R_AliasProjectAndClipTestFinalVert (out);
+}
+
+
+void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
+{
+ float scale;
+
+ if (pfv0->v >= pfv1->v )
+ {
+ scale = (float)(r_refdef.aliasvrect.x - pfv0->u) /
+ (pfv1->u - pfv0->u);
+ out->u = pfv0->u + ( pfv1->u - pfv0->u ) * scale + 0.5;
+ out->v = pfv0->v + ( pfv1->v - pfv0->v ) * scale + 0.5;
+ out->s = pfv0->s + ( pfv1->s - pfv0->s ) * scale + 0.5;
+ out->t = pfv0->t + ( pfv1->t - pfv0->t ) * scale + 0.5;
+ out->l = pfv0->l + ( pfv1->l - pfv0->l ) * scale + 0.5;
+ out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
+ }
+ else
+ {
+ scale = (float)(r_refdef.aliasvrect.x - pfv1->u) /
+ (pfv0->u - pfv1->u);
+ out->u = pfv1->u + ( pfv0->u - pfv1->u ) * scale + 0.5;
+ out->v = pfv1->v + ( pfv0->v - pfv1->v ) * scale + 0.5;
+ out->s = pfv1->s + ( pfv0->s - pfv1->s ) * scale + 0.5;
+ out->t = pfv1->t + ( pfv0->t - pfv1->t ) * scale + 0.5;
+ out->l = pfv1->l + ( pfv0->l - pfv1->l ) * scale + 0.5;
+ out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
+ }
+}
+
+
+void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
+{
+ float scale;
+
+ if ( pfv0->v >= pfv1->v )
+ {
+ scale = (float)(r_refdef.aliasvrectright - pfv0->u ) /
+ (pfv1->u - pfv0->u );
+ out->u = pfv0->u + ( pfv1->u - pfv0->u ) * scale + 0.5;
+ out->v = pfv0->v + ( pfv1->v - pfv0->v ) * scale + 0.5;
+ out->s = pfv0->s + ( pfv1->s - pfv0->s ) * scale + 0.5;
+ out->t = pfv0->t + ( pfv1->t - pfv0->t ) * scale + 0.5;
+ out->l = pfv0->l + ( pfv1->l - pfv0->l ) * scale + 0.5;
+ out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
+ }
+ else
+ {
+ scale = (float)(r_refdef.aliasvrectright - pfv1->u ) /
+ (pfv0->u - pfv1->u );
+ out->u = pfv1->u + ( pfv0->u - pfv1->u ) * scale + 0.5;
+ out->v = pfv1->v + ( pfv0->v - pfv1->v ) * scale + 0.5;
+ out->s = pfv1->s + ( pfv0->s - pfv1->s ) * scale + 0.5;
+ out->t = pfv1->t + ( pfv0->t - pfv1->t ) * scale + 0.5;
+ out->l = pfv1->l + ( pfv0->l - pfv1->l ) * scale + 0.5;
+ out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
+ }
+}
+
+
+void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
+{
+ float scale;
+
+ if (pfv0->v >= pfv1->v)
+ {
+ scale = (float)(r_refdef.aliasvrect.y - pfv0->v) /
+ (pfv1->v - pfv0->v);
+ out->u = pfv0->u + ( pfv1->u - pfv0->u ) * scale + 0.5;
+ out->v = pfv0->v + ( pfv1->v - pfv0->v ) * scale + 0.5;
+ out->s = pfv0->s + ( pfv1->s - pfv0->s ) * scale + 0.5;
+ out->t = pfv0->t + ( pfv1->t - pfv0->t ) * scale + 0.5;
+ out->l = pfv0->l + ( pfv1->l - pfv0->l ) * scale + 0.5;
+ out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
+ }
+ else
+ {
+ scale = (float)(r_refdef.aliasvrect.y - pfv1->v) /
+ (pfv0->v - pfv1->v);
+ out->u = pfv1->u + ( pfv0->u - pfv1->u ) * scale + 0.5;
+ out->v = pfv1->v + ( pfv0->v - pfv1->v ) * scale + 0.5;
+ out->s = pfv1->s + ( pfv0->s - pfv1->s ) * scale + 0.5;
+ out->t = pfv1->t + ( pfv0->t - pfv1->t ) * scale + 0.5;
+ out->l = pfv1->l + ( pfv0->l - pfv1->l ) * scale + 0.5;
+ out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
+ }
+}
+
+
+void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1,
+ finalvert_t *out)
+{
+ float scale;
+
+ if (pfv0->v >= pfv1->v)
+ {
+ scale = (float)(r_refdef.aliasvrectbottom - pfv0->v) /
+ (pfv1->v - pfv0->v);
+
+ out->u = pfv0->u + ( pfv1->u - pfv0->u ) * scale + 0.5;
+ out->v = pfv0->v + ( pfv1->v - pfv0->v ) * scale + 0.5;
+ out->s = pfv0->s + ( pfv1->s - pfv0->s ) * scale + 0.5;
+ out->t = pfv0->t + ( pfv1->t - pfv0->t ) * scale + 0.5;
+ out->l = pfv0->l + ( pfv1->l - pfv0->l ) * scale + 0.5;
+ out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
+ }
+ else
+ {
+ scale = (float)(r_refdef.aliasvrectbottom - pfv1->v) /
+ (pfv0->v - pfv1->v);
+
+ out->u = pfv1->u + ( pfv0->u - pfv1->u ) * scale + 0.5;
+ out->v = pfv1->v + ( pfv0->v - pfv1->v ) * scale + 0.5;
+ out->s = pfv1->s + ( pfv0->s - pfv1->s ) * scale + 0.5;
+ out->t = pfv1->t + ( pfv0->t - pfv1->t ) * scale + 0.5;
+ out->l = pfv1->l + ( pfv0->l - pfv1->l ) * scale + 0.5;
+ out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
+ }
+}
+
+
+int R_AliasClip (finalvert_t *in, finalvert_t *out, int flag, int count,
+ void(*clip)(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) )
+{
+ int i,j,k;
+ int flags, oldflags;
+
+ j = count-1;
+ k = 0;
+ for (i=0 ; i<count ; j = i, i++)
+ {
+ oldflags = in[j].flags & flag;
+ flags = in[i].flags & flag;
+
+ if (flags && oldflags)
+ continue;
+ if (oldflags ^ flags)
+ {
+ clip (&in[j], &in[i], &out[k]);
+ out[k].flags = 0;
+ if (out[k].u < r_refdef.aliasvrect.x)
+ out[k].flags |= ALIAS_LEFT_CLIP;
+ if (out[k].v < r_refdef.aliasvrect.y)
+ out[k].flags |= ALIAS_TOP_CLIP;
+ if (out[k].u > r_refdef.aliasvrectright)
+ out[k].flags |= ALIAS_RIGHT_CLIP;
+ if (out[k].v > r_refdef.aliasvrectbottom)
+ out[k].flags |= ALIAS_BOTTOM_CLIP;
+ k++;
+ }
+ if (!flags)
+ {
+ out[k] = in[i];
+ k++;
+ }
+ }
+
+ return k;
+}
+
+
+/*
+================
+R_AliasClipTriangle
+================
+*/
+void R_AliasClipTriangle (finalvert_t *index0, finalvert_t *index1, finalvert_t *index2)
+{
+ int i, k, pingpong;
+ unsigned clipflags;
+
+// copy vertexes and fix seam texture coordinates
+ fv[0][0] = *index0;
+ fv[0][1] = *index1;
+ fv[0][2] = *index2;
+
+// clip
+ clipflags = fv[0][0].flags | fv[0][1].flags | fv[0][2].flags;
+
+ if (clipflags & ALIAS_Z_CLIP)
+ {
+ k = R_AliasClip (fv[0], fv[1], ALIAS_Z_CLIP, 3, R_Alias_clip_z);
+ if (k == 0)
+ return;
+
+ pingpong = 1;
+ clipflags = fv[1][0].flags | fv[1][1].flags | fv[1][2].flags;
+ }
+ else
+ {
+ pingpong = 0;
+ k = 3;
+ }
+
+ if (clipflags & ALIAS_LEFT_CLIP)
+ {
+ k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
+ ALIAS_LEFT_CLIP, k, R_Alias_clip_left);
+ if (k == 0)
+ return;
+
+ pingpong ^= 1;
+ }
+
+ if (clipflags & ALIAS_RIGHT_CLIP)
+ {
+ k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
+ ALIAS_RIGHT_CLIP, k, R_Alias_clip_right);
+ if (k == 0)
+ return;
+
+ pingpong ^= 1;
+ }
+
+ if (clipflags & ALIAS_BOTTOM_CLIP)
+ {
+ k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
+ ALIAS_BOTTOM_CLIP, k, R_Alias_clip_bottom);
+ if (k == 0)
+ return;
+
+ pingpong ^= 1;
+ }
+
+ if (clipflags & ALIAS_TOP_CLIP)
+ {
+ k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
+ ALIAS_TOP_CLIP, k, R_Alias_clip_top);
+ if (k == 0)
+ return;
+
+ pingpong ^= 1;
+ }
+
+ for (i=0 ; i<k ; i++)
+ {
+ if (fv[pingpong][i].u < r_refdef.aliasvrect.x)
+ fv[pingpong][i].u = r_refdef.aliasvrect.x;
+ else if (fv[pingpong][i].u > r_refdef.aliasvrectright)
+ fv[pingpong][i].u = r_refdef.aliasvrectright;
+
+ if (fv[pingpong][i].v < r_refdef.aliasvrect.y)
+ fv[pingpong][i].v = r_refdef.aliasvrect.y;
+ else if (fv[pingpong][i].v > r_refdef.aliasvrectbottom)
+ fv[pingpong][i].v = r_refdef.aliasvrectbottom;
+
+ fv[pingpong][i].flags = 0;
+ }
+
+// draw triangles
+ for (i=1 ; i<k-1 ; i++)
+ {
+ aliastriangleparms.a = &fv[pingpong][0];
+ aliastriangleparms.b = &fv[pingpong][i];
+ aliastriangleparms.c = &fv[pingpong][i+1];
+ R_DrawTriangle();
+ }
+}
+
--- /dev/null
+++ b/r_alias.c
@@ -1,0 +1,861 @@
+// r_alias.c: routines for setting up to draw alias models
+
+/*
+** use a real variable to control lerping
+*/
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+#define LIGHT_MIN 5 // lowest light value we'll allow, to avoid the
+ // need for inner-loop light clamping
+
+//PGM
+extern byte iractive;
+//PGM
+
+int r_amodels_drawn;
+
+affinetridesc_t r_affinetridesc;
+
+vec3_t r_plightvec;
+vec3_t r_lerped[1024];
+vec3_t r_lerp_frontv, r_lerp_backv, r_lerp_move;
+
+int r_ambientlight;
+int r_aliasblendcolor;
+float r_shadelight;
+
+
+daliasframe_t *r_thisframe, *r_lastframe;
+dmdl_t *s_pmdl;
+
+float aliastransform[3][4];
+float aliasworldtransform[3][4];
+float aliasoldworldtransform[3][4];
+
+static float s_ziscale;
+static vec3_t s_alias_forward, s_alias_right, s_alias_up;
+
+
+float r_avertexnormals[NUMVERTEXNORMALS][3] = {
+#include "anorms.h"
+};
+
+
+void R_AliasSetUpLerpData( dmdl_t *pmdl, float backlerp );
+void R_AliasSetUpTransform (void);
+void R_AliasTransformVector (vec3_t in, vec3_t out, float m[3][4] );
+void R_AliasProjectAndClipTestFinalVert (finalvert_t *fv);
+
+void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv );
+
+void R_AliasLerpFrames( dmdl_t *paliashdr, float backlerp );
+
+/*
+================
+R_AliasCheckBBox
+================
+*/
+typedef struct {
+ int index0;
+ int index1;
+} aedge_t;
+
+static aedge_t aedges[12] = {
+{0, 1}, {1, 2}, {2, 3}, {3, 0},
+{4, 5}, {5, 6}, {6, 7}, {7, 4},
+{0, 5}, {1, 4}, {2, 7}, {3, 6}
+};
+
+#define BBOX_TRIVIAL_ACCEPT 0
+#define BBOX_MUST_CLIP_XY 1
+#define BBOX_MUST_CLIP_Z 2
+#define BBOX_TRIVIAL_REJECT 8
+
+/*
+** R_AliasCheckFrameBBox
+**
+** Checks a specific alias frame bounding box
+*/
+unsigned long R_AliasCheckFrameBBox( daliasframe_t *frame, float worldxf[3][4] )
+{
+ unsigned long aggregate_and_clipcode = ~0U,
+ aggregate_or_clipcode = 0;
+ int i;
+ vec3_t mins, maxs;
+ vec3_t transformed_min, transformed_max;
+ qboolean zclipped = false, zfullyclipped = true;
+ //float minz = 9999.0F;
+
+ /*
+ ** get the exact frame bounding box
+ */
+ for (i=0 ; i<3 ; i++)
+ {
+ mins[i] = frame->translate[i];
+ maxs[i] = mins[i] + frame->scale[i]*255;
+ }
+
+ /*
+ ** transform the min and max values into view space
+ */
+ R_AliasTransformVector( mins, transformed_min, aliastransform );
+ R_AliasTransformVector( maxs, transformed_max, aliastransform );
+
+ if ( transformed_min[2] >= ALIAS_Z_CLIP_PLANE )
+ zfullyclipped = false;
+ if ( transformed_max[2] >= ALIAS_Z_CLIP_PLANE )
+ zfullyclipped = false;
+
+ if ( zfullyclipped )
+ {
+ return BBOX_TRIVIAL_REJECT;
+ }
+ if ( zclipped )
+ {
+ return ( BBOX_MUST_CLIP_XY | BBOX_MUST_CLIP_Z );
+ }
+
+ /*
+ ** build a transformed bounding box from the given min and max
+ */
+ for ( i = 0; i < 8; i++ )
+ {
+ int j;
+ vec3_t tmp, transformed;
+ unsigned long clipcode = 0;
+
+ if ( i & 1 )
+ tmp[0] = mins[0];
+ else
+ tmp[0] = maxs[0];
+
+ if ( i & 2 )
+ tmp[1] = mins[1];
+ else
+ tmp[1] = maxs[1];
+
+ if ( i & 4 )
+ tmp[2] = mins[2];
+ else
+ tmp[2] = maxs[2];
+
+ R_AliasTransformVector( tmp, transformed, worldxf );
+
+ for ( j = 0; j < 4; j++ )
+ {
+ float dp = DotProduct( transformed, view_clipplanes[j].normal );
+
+ if ( ( dp - view_clipplanes[j].dist ) < 0.0F )
+ clipcode |= 1 << j;
+ }
+
+ aggregate_and_clipcode &= clipcode;
+ aggregate_or_clipcode |= clipcode;
+ }
+
+ if ( aggregate_and_clipcode )
+ {
+ return BBOX_TRIVIAL_REJECT;
+ }
+ if ( !aggregate_or_clipcode )
+ {
+ return BBOX_TRIVIAL_ACCEPT;
+ }
+
+ return BBOX_MUST_CLIP_XY;
+}
+
+qboolean R_AliasCheckBBox (void)
+{
+ unsigned long ccodes[2] = { 0, 0 };
+
+ ccodes[0] = R_AliasCheckFrameBBox( r_thisframe, aliasworldtransform );
+
+ /*
+ ** non-lerping model
+ */
+ if ( currententity->backlerp == 0 )
+ {
+ if ( ccodes[0] == BBOX_TRIVIAL_ACCEPT )
+ return BBOX_TRIVIAL_ACCEPT;
+ else if ( ccodes[0] & BBOX_TRIVIAL_REJECT )
+ return BBOX_TRIVIAL_REJECT;
+ else
+ return ( ccodes[0] & ~BBOX_TRIVIAL_REJECT );
+ }
+
+ ccodes[1] = R_AliasCheckFrameBBox( r_lastframe, aliasoldworldtransform );
+
+ if ( ( ccodes[0] | ccodes[1] ) == BBOX_TRIVIAL_ACCEPT )
+ return BBOX_TRIVIAL_ACCEPT;
+ else if ( ( ccodes[0] & ccodes[1] ) & BBOX_TRIVIAL_REJECT )
+ return BBOX_TRIVIAL_REJECT;
+ else
+ return ( ccodes[0] | ccodes[1] ) & ~BBOX_TRIVIAL_REJECT;
+}
+
+
+/*
+================
+R_AliasTransformVector
+================
+*/
+void R_AliasTransformVector(vec3_t in, vec3_t out, float xf[3][4] )
+{
+ out[0] = DotProduct(in, xf[0]) + xf[0][3];
+ out[1] = DotProduct(in, xf[1]) + xf[1][3];
+ out[2] = DotProduct(in, xf[2]) + xf[2][3];
+}
+
+
+/*
+================
+R_AliasPreparePoints
+
+General clipped case
+================
+*/
+typedef struct
+{
+ int num_points;
+ dtrivertx_t *last_verts; // verts from the last frame
+ dtrivertx_t *this_verts; // verts from this frame
+ finalvert_t *dest_verts; // destination for transformed verts
+} aliasbatchedtransformdata_t;
+
+aliasbatchedtransformdata_t aliasbatchedtransformdata;
+
+void R_AliasPreparePoints (void)
+{
+ int i;
+ dstvert_t *pstverts;
+ dtriangle_t *ptri;
+ finalvert_t *pfv[3];
+ finalvert_t finalverts[MAXALIASVERTS +
+ ((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 3];
+ finalvert_t *pfinalverts;
+
+//PGM
+ iractive = (r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE);
+// iractive = 0;
+// if(r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE)
+// iractive = 1;
+//PGM
+
+ // put work vertexes on stack, cache aligned
+ pfinalverts = (finalvert_t *)
+ (((uintptr)&finalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
+
+ aliasbatchedtransformdata.num_points = s_pmdl->num_xyz;
+ aliasbatchedtransformdata.last_verts = r_lastframe->verts;
+ aliasbatchedtransformdata.this_verts = r_thisframe->verts;
+ aliasbatchedtransformdata.dest_verts = pfinalverts;
+
+ R_AliasTransformFinalVerts( aliasbatchedtransformdata.num_points,
+ aliasbatchedtransformdata.dest_verts,
+ aliasbatchedtransformdata.last_verts,
+ aliasbatchedtransformdata.this_verts );
+
+// clip and draw all triangles
+//
+ pstverts = (dstvert_t *)((byte *)s_pmdl + s_pmdl->ofs_st);
+ ptri = (dtriangle_t *)((byte *)s_pmdl + s_pmdl->ofs_tris);
+
+ if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
+ {
+ for (i=0 ; i<s_pmdl->num_tris ; i++, ptri++)
+ {
+ pfv[0] = &pfinalverts[ptri->index_xyz[0]];
+ pfv[1] = &pfinalverts[ptri->index_xyz[1]];
+ pfv[2] = &pfinalverts[ptri->index_xyz[2]];
+
+ if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags )
+ continue; // completely clipped
+
+ // insert s/t coordinates
+ pfv[0]->s = pstverts[ptri->index_st[0]].s << 16;
+ pfv[0]->t = pstverts[ptri->index_st[0]].t << 16;
+
+ pfv[1]->s = pstverts[ptri->index_st[1]].s << 16;
+ pfv[1]->t = pstverts[ptri->index_st[1]].t << 16;
+
+ pfv[2]->s = pstverts[ptri->index_st[2]].s << 16;
+ pfv[2]->t = pstverts[ptri->index_st[2]].t << 16;
+
+ if ( ! (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) )
+ { // totally unclipped
+ aliastriangleparms.a = pfv[2];
+ aliastriangleparms.b = pfv[1];
+ aliastriangleparms.c = pfv[0];
+
+ R_DrawTriangle();
+ }
+ else
+ {
+ R_AliasClipTriangle (pfv[2], pfv[1], pfv[0]);
+ }
+ }
+ }
+ else
+ {
+ for (i=0 ; i<s_pmdl->num_tris ; i++, ptri++)
+ {
+ pfv[0] = &pfinalverts[ptri->index_xyz[0]];
+ pfv[1] = &pfinalverts[ptri->index_xyz[1]];
+ pfv[2] = &pfinalverts[ptri->index_xyz[2]];
+
+ if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags )
+ continue; // completely clipped
+
+ // insert s/t coordinates
+ pfv[0]->s = pstverts[ptri->index_st[0]].s << 16;
+ pfv[0]->t = pstverts[ptri->index_st[0]].t << 16;
+
+ pfv[1]->s = pstverts[ptri->index_st[1]].s << 16;
+ pfv[1]->t = pstverts[ptri->index_st[1]].t << 16;
+
+ pfv[2]->s = pstverts[ptri->index_st[2]].s << 16;
+ pfv[2]->t = pstverts[ptri->index_st[2]].t << 16;
+
+ if ( ! (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) )
+ { // totally unclipped
+ aliastriangleparms.a = pfv[0];
+ aliastriangleparms.b = pfv[1];
+ aliastriangleparms.c = pfv[2];
+
+ R_DrawTriangle();
+ }
+ else
+ { // partially clipped
+ R_AliasClipTriangle (pfv[0], pfv[1], pfv[2]);
+ }
+ }
+ }
+}
+
+
+/*
+================
+R_AliasSetUpTransform
+================
+*/
+void R_AliasSetUpTransform (void)
+{
+ int i;
+ static float viewmatrix[3][4];
+ vec3_t angles;
+
+// TODO: should really be stored with the entity instead of being reconstructed
+// TODO: should use a look-up table
+// TODO: could cache lazily, stored in the entity
+//
+ angles[ROLL] = currententity->angles[ROLL];
+ angles[PITCH] = currententity->angles[PITCH];
+ angles[YAW] = currententity->angles[YAW];
+ AngleVectors( angles, s_alias_forward, s_alias_right, s_alias_up );
+
+// TODO: can do this with simple matrix rearrangement
+
+ memset( aliasworldtransform, 0, sizeof( aliasworldtransform ) );
+ memset( aliasoldworldtransform, 0, sizeof( aliasworldtransform ) );
+
+ for (i=0 ; i<3 ; i++)
+ {
+ aliasoldworldtransform[i][0] = aliasworldtransform[i][0] = s_alias_forward[i];
+ aliasoldworldtransform[i][0] = aliasworldtransform[i][1] = -s_alias_right[i];
+ aliasoldworldtransform[i][0] = aliasworldtransform[i][2] = s_alias_up[i];
+ }
+
+ aliasworldtransform[0][3] = currententity->origin[0]-r_origin[0];
+ aliasworldtransform[1][3] = currententity->origin[1]-r_origin[1];
+ aliasworldtransform[2][3] = currententity->origin[2]-r_origin[2];
+
+ aliasoldworldtransform[0][3] = currententity->oldorigin[0]-r_origin[0];
+ aliasoldworldtransform[1][3] = currententity->oldorigin[1]-r_origin[1];
+ aliasoldworldtransform[2][3] = currententity->oldorigin[2]-r_origin[2];
+
+// FIXME: can do more efficiently than full concatenation
+// memcpy( rotationmatrix, t2matrix, sizeof( rotationmatrix ) );
+
+// R_ConcatTransforms (t2matrix, tmatrix, rotationmatrix);
+
+// TODO: should be global, set when vright, etc., set
+ VectorCopy (vright, viewmatrix[0]);
+ VectorCopy (vup, viewmatrix[1]);
+ VectorInverse (viewmatrix[1]);
+ VectorCopy (vpn, viewmatrix[2]);
+
+ viewmatrix[0][3] = 0;
+ viewmatrix[1][3] = 0;
+ viewmatrix[2][3] = 0;
+
+// memcpy( aliasworldtransform, rotationmatrix, sizeof( aliastransform ) );
+
+ R_ConcatTransforms (viewmatrix, aliasworldtransform, aliastransform);
+
+ aliasworldtransform[0][3] = currententity->origin[0];
+ aliasworldtransform[1][3] = currententity->origin[1];
+ aliasworldtransform[2][3] = currententity->origin[2];
+
+ aliasoldworldtransform[0][3] = currententity->oldorigin[0];
+ aliasoldworldtransform[1][3] = currententity->oldorigin[1];
+ aliasoldworldtransform[2][3] = currententity->oldorigin[2];
+}
+
+
+/*
+================
+R_AliasTransformFinalVerts
+================
+*/
+void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv )
+{
+ int i;
+
+ for ( i = 0; i < numpoints; i++, fv++, oldv++, newv++ )
+ {
+ int temp;
+ float lightcos, *plightnormal;
+ vec3_t lerped_vert;
+
+ lerped_vert[0] = r_lerp_move[0] + oldv->v[0]*r_lerp_backv[0] + newv->v[0]*r_lerp_frontv[0];
+ lerped_vert[1] = r_lerp_move[1] + oldv->v[1]*r_lerp_backv[1] + newv->v[1]*r_lerp_frontv[1];
+ lerped_vert[2] = r_lerp_move[2] + oldv->v[2]*r_lerp_backv[2] + newv->v[2]*r_lerp_frontv[2];
+
+ plightnormal = r_avertexnormals[newv->lightnormalindex];
+
+ // PMM - added double damage shell
+ if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
+ {
+ lerped_vert[0] += plightnormal[0] * POWERSUIT_SCALE;
+ lerped_vert[1] += plightnormal[1] * POWERSUIT_SCALE;
+ lerped_vert[2] += plightnormal[2] * POWERSUIT_SCALE;
+ }
+
+ fv->xyz[0] = DotProduct(lerped_vert, aliastransform[0]) + aliastransform[0][3];
+ fv->xyz[1] = DotProduct(lerped_vert, aliastransform[1]) + aliastransform[1][3];
+ fv->xyz[2] = DotProduct(lerped_vert, aliastransform[2]) + aliastransform[2][3];
+
+ fv->flags = 0;
+
+ // lighting
+ lightcos = DotProduct (plightnormal, r_plightvec);
+ temp = r_ambientlight;
+
+ if (lightcos < 0)
+ {
+ temp += (int)(r_shadelight * lightcos);
+
+ // clamp; because we limited the minimum ambient and shading light, we
+ // don't have to clamp low light, just bright
+ if (temp < 0)
+ temp = 0;
+ }
+
+ fv->l = temp;
+
+ if ( fv->xyz[2] < ALIAS_Z_CLIP_PLANE )
+ {
+ fv->flags |= ALIAS_Z_CLIP;
+ }
+ else
+ {
+ R_AliasProjectAndClipTestFinalVert( fv );
+ }
+ }
+}
+
+/*
+================
+R_AliasProjectAndClipTestFinalVert
+================
+*/
+void R_AliasProjectAndClipTestFinalVert( finalvert_t *fv )
+{
+ float zi;
+ float x, y, z;
+
+ // project points
+ x = fv->xyz[0];
+ y = fv->xyz[1];
+ z = fv->xyz[2];
+ zi = 1.0 / z;
+
+ fv->zi = zi * s_ziscale;
+
+ fv->u = (x * aliasxscale * zi) + aliasxcenter;
+ fv->v = (y * aliasyscale * zi) + aliasycenter;
+
+ if (fv->u < r_refdef.aliasvrect.x)
+ fv->flags |= ALIAS_LEFT_CLIP;
+ if (fv->v < r_refdef.aliasvrect.y)
+ fv->flags |= ALIAS_TOP_CLIP;
+ if (fv->u > r_refdef.aliasvrectright)
+ fv->flags |= ALIAS_RIGHT_CLIP;
+ if (fv->v > r_refdef.aliasvrectbottom)
+ fv->flags |= ALIAS_BOTTOM_CLIP;
+}
+
+/*
+===============
+R_AliasSetupSkin
+===============
+*/
+static qboolean R_AliasSetupSkin (void)
+{
+ int skinnum;
+ image_t *pskindesc;
+
+ if (currententity->skin)
+ pskindesc = currententity->skin;
+ else
+ {
+ skinnum = currententity->skinnum;
+ if ((skinnum >= s_pmdl->num_skins) || (skinnum < 0))
+ {
+ ri.Con_Printf (PRINT_ALL, "R_AliasSetupSkin %s: no such skin # %d\n",
+ currentmodel->name, skinnum);
+ skinnum = 0;
+ }
+
+ pskindesc = currentmodel->skins[skinnum];
+ }
+
+ if ( !pskindesc )
+ return false;
+
+ r_affinetridesc.pskin = pskindesc->pixels[0];
+ r_affinetridesc.skinwidth = pskindesc->width;
+ r_affinetridesc.skinheight = pskindesc->height;
+
+ R_PolysetUpdateTables (); // FIXME: precalc edge lookups
+
+ return true;
+}
+
+
+/*
+================
+R_AliasSetupLighting
+
+ FIXME: put lighting into tables
+================
+*/
+void R_AliasSetupLighting (void)
+{
+ alight_t lighting;
+ float lightvec[3] = {-1, 0, 0};
+ vec3_t light;
+ int i, j;
+
+ // all components of light should be identical in software
+ if ( currententity->flags & RF_FULLBRIGHT )
+ {
+ for (i=0 ; i<3 ; i++)
+ light[i] = 1.0;
+ }
+ else
+ {
+ R_LightPoint (currententity->origin, light);
+ }
+
+ // save off light value for server to look at (BIG HACK!)
+ if ( currententity->flags & RF_WEAPONMODEL )
+ r_lightlevel->value = 150.0 * light[0];
+
+
+ if ( currententity->flags & RF_MINLIGHT )
+ {
+ for (i=0 ; i<3 ; i++)
+ if (light[i] < 0.1)
+ light[i] = 0.1;
+ }
+
+ if ( currententity->flags & RF_GLOW )
+ { // bonus items will pulse with time
+ float scale;
+ float min;
+
+ scale = 0.1 * sin(r_newrefdef.time*7);
+ for (i=0 ; i<3 ; i++)
+ {
+ min = light[i] * 0.8;
+ light[i] += scale;
+ if (light[i] < min)
+ light[i] = min;
+ }
+ }
+
+ j = (light[0] + light[1] + light[2])*0.3333*255;
+
+ lighting.ambientlight = j;
+ lighting.shadelight = j;
+
+ lighting.plightvec = lightvec;
+
+// clamp lighting so it doesn't overbright as much
+ if (lighting.ambientlight > 128)
+ lighting.ambientlight = 128;
+ if (lighting.ambientlight + lighting.shadelight > 192)
+ lighting.shadelight = 192 - lighting.ambientlight;
+
+// guarantee that no vertex will ever be lit below LIGHT_MIN, so we don't have
+// to clamp off the bottom
+ r_ambientlight = lighting.ambientlight;
+
+ if (r_ambientlight < LIGHT_MIN)
+ r_ambientlight = LIGHT_MIN;
+
+ r_ambientlight = (255 - r_ambientlight) << VID_CBITS;
+
+ if (r_ambientlight < LIGHT_MIN)
+ r_ambientlight = LIGHT_MIN;
+
+ r_shadelight = lighting.shadelight;
+
+ if (r_shadelight < 0)
+ r_shadelight = 0;
+
+ r_shadelight *= VID_GRADES;
+
+// rotate the lighting vector into the model's frame of reference
+ r_plightvec[0] = DotProduct( lighting.plightvec, s_alias_forward );
+ r_plightvec[1] = -DotProduct( lighting.plightvec, s_alias_right );
+ r_plightvec[2] = DotProduct( lighting.plightvec, s_alias_up );
+}
+
+
+/*
+=================
+R_AliasSetupFrames
+
+=================
+*/
+void R_AliasSetupFrames( dmdl_t *pmdl )
+{
+ int thisframe = currententity->frame;
+ int lastframe = currententity->oldframe;
+
+ if ( ( thisframe >= pmdl->num_frames ) || ( thisframe < 0 ) )
+ {
+ ri.Con_Printf (PRINT_ALL, "R_AliasSetupFrames %s: no such thisframe %d\n",
+ currentmodel->name, thisframe);
+ thisframe = 0;
+ }
+ if ( ( lastframe >= pmdl->num_frames ) || ( lastframe < 0 ) )
+ {
+ ri.Con_Printf (PRINT_ALL, "R_AliasSetupFrames %s: no such lastframe %d\n",
+ currentmodel->name, lastframe);
+ lastframe = 0;
+ }
+
+ r_thisframe = (daliasframe_t *)((byte *)pmdl + pmdl->ofs_frames
+ + thisframe * pmdl->framesize);
+
+ r_lastframe = (daliasframe_t *)((byte *)pmdl + pmdl->ofs_frames
+ + lastframe * pmdl->framesize);
+}
+
+/*
+** R_AliasSetUpLerpData
+**
+** Precomputes lerp coefficients used for the whole frame.
+*/
+void R_AliasSetUpLerpData( dmdl_t */*pmdl*/, float backlerp )
+{
+ float frontlerp;
+ vec3_t translation, vectors[3];
+ int i;
+
+ frontlerp = 1.0F - backlerp;
+
+ /*
+ ** convert entity's angles into discrete vectors for R, U, and F
+ */
+ AngleVectors (currententity->angles, vectors[0], vectors[1], vectors[2]);
+
+ /*
+ ** translation is the vector from last position to this position
+ */
+ VectorSubtract (currententity->oldorigin, currententity->origin, translation);
+
+ /*
+ ** move should be the delta back to the previous frame * backlerp
+ */
+ r_lerp_move[0] = DotProduct(translation, vectors[0]); // forward
+ r_lerp_move[1] = -DotProduct(translation, vectors[1]); // left
+ r_lerp_move[2] = DotProduct(translation, vectors[2]); // up
+
+ VectorAdd( r_lerp_move, r_lastframe->translate, r_lerp_move );
+
+ for (i=0 ; i<3 ; i++)
+ {
+ r_lerp_move[i] = backlerp*r_lerp_move[i] + frontlerp * r_thisframe->translate[i];
+ }
+
+ for (i=0 ; i<3 ; i++)
+ {
+ r_lerp_frontv[i] = frontlerp * r_thisframe->scale[i];
+ r_lerp_backv[i] = backlerp * r_lastframe->scale[i];
+ }
+}
+
+/*
+================
+R_AliasDrawModel
+================
+*/
+void R_AliasDrawModel (void)
+{
+ extern void (*d_pdrawspans)(void *);
+ extern void R_PolysetDrawSpans8_Opaque( void * );
+ extern void R_PolysetDrawSpans8_33( void * );
+ extern void R_PolysetDrawSpans8_66( void * );
+ extern void R_PolysetDrawSpansConstant8_33( void * );
+ extern void R_PolysetDrawSpansConstant8_66( void * );
+
+ s_pmdl = (dmdl_t *)currentmodel->extradata;
+
+ if ( r_lerpmodels->value == 0 )
+ currententity->backlerp = 0;
+
+ if ( currententity->flags & RF_WEAPONMODEL )
+ {
+ if ( r_lefthand->value == 1.0F )
+ aliasxscale = -aliasxscale;
+ else if ( r_lefthand->value == 2.0F )
+ return;
+ }
+
+ /*
+ ** we have to set our frame pointers and transformations before
+ ** doing any real work
+ */
+ R_AliasSetupFrames( s_pmdl );
+ R_AliasSetUpTransform();
+
+ // see if the bounding box lets us trivially reject, also sets
+ // trivial accept status
+ if ( R_AliasCheckBBox() == BBOX_TRIVIAL_REJECT )
+ {
+ if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
+ {
+ aliasxscale = -aliasxscale;
+ }
+ return;
+ }
+
+ // set up the skin and verify it exists
+ if ( !R_AliasSetupSkin () )
+ {
+ ri.Con_Printf( PRINT_ALL, "R_AliasDrawModel %s: NULL skin found\n",
+ currentmodel->name);
+ return;
+ }
+
+ r_amodels_drawn++;
+ R_AliasSetupLighting ();
+
+ /*
+ ** select the proper span routine based on translucency
+ */
+ // PMM - added double damage shell
+ // PMM - reordered to handle blending
+ if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
+ {
+ int color;
+
+ // PMM - added double
+ color = currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM);
+ // PMM - reordered, old code first
+/*
+ if ( color == RF_SHELL_RED )
+ r_aliasblendcolor = SHELL_RED_COLOR;
+ else if ( color == RF_SHELL_GREEN )
+ r_aliasblendcolor = SHELL_GREEN_COLOR;
+ else if ( color == RF_SHELL_BLUE )
+ r_aliasblendcolor = SHELL_BLUE_COLOR;
+ else if ( color == (RF_SHELL_RED | RF_SHELL_GREEN) )
+ r_aliasblendcolor = SHELL_RG_COLOR;
+ else if ( color == (RF_SHELL_RED | RF_SHELL_BLUE) )
+ r_aliasblendcolor = SHELL_RB_COLOR;
+ else if ( color == (RF_SHELL_BLUE | RF_SHELL_GREEN) )
+ r_aliasblendcolor = SHELL_BG_COLOR;
+ // PMM - added this .. it's yellowish
+ else if ( color == (RF_SHELL_DOUBLE) )
+ r_aliasblendcolor = SHELL_DOUBLE_COLOR;
+ else if ( color == (RF_SHELL_HALF_DAM) )
+ r_aliasblendcolor = SHELL_HALF_DAM_COLOR;
+ // pmm
+ else
+ r_aliasblendcolor = SHELL_WHITE_COLOR;
+*/
+ if ( color & RF_SHELL_RED )
+ {
+ if ( ( color & RF_SHELL_BLUE) && ( color & RF_SHELL_GREEN) )
+ r_aliasblendcolor = SHELL_WHITE_COLOR;
+ else if ( color & (RF_SHELL_BLUE | RF_SHELL_DOUBLE))
+ r_aliasblendcolor = SHELL_RB_COLOR;
+ else
+ r_aliasblendcolor = SHELL_RED_COLOR;
+ }
+ else if ( color & RF_SHELL_BLUE)
+ {
+ if ( color & RF_SHELL_DOUBLE )
+ r_aliasblendcolor = SHELL_CYAN_COLOR;
+ else
+ r_aliasblendcolor = SHELL_BLUE_COLOR;
+ }
+ else if ( color & (RF_SHELL_DOUBLE) )
+ r_aliasblendcolor = SHELL_DOUBLE_COLOR;
+ else if ( color & (RF_SHELL_HALF_DAM) )
+ r_aliasblendcolor = SHELL_HALF_DAM_COLOR;
+ else if ( color & RF_SHELL_GREEN )
+ r_aliasblendcolor = SHELL_GREEN_COLOR;
+ else
+ r_aliasblendcolor = SHELL_WHITE_COLOR;
+
+
+ if ( currententity->alpha > 0.33 )
+ d_pdrawspans = R_PolysetDrawSpansConstant8_66;
+ else
+ d_pdrawspans = R_PolysetDrawSpansConstant8_33;
+ }
+ else if ( currententity->flags & RF_TRANSLUCENT )
+ {
+ if ( currententity->alpha > 0.66 )
+ d_pdrawspans = R_PolysetDrawSpans8_Opaque;
+ else if ( currententity->alpha > 0.33 )
+ d_pdrawspans = R_PolysetDrawSpans8_66;
+ else
+ d_pdrawspans = R_PolysetDrawSpans8_33;
+ }
+ else
+ {
+ d_pdrawspans = R_PolysetDrawSpans8_Opaque;
+ }
+
+ /*
+ ** compute this_frame and old_frame addresses
+ */
+ R_AliasSetUpLerpData( s_pmdl, currententity->backlerp );
+
+ if (currententity->flags & RF_DEPTHHACK)
+ s_ziscale = (float)0x8000 * (float)0x10000 * 3.0;
+ else
+ s_ziscale = (float)0x8000 * (float)0x10000;
+
+ R_AliasPreparePoints ();
+
+ if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
+ {
+ aliasxscale = -aliasxscale;
+ }
+}
+
+
+
--- /dev/null
+++ b/r_bsp.c
@@ -1,0 +1,620 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+//
+// current entity info
+//
+qboolean insubmodel;
+entity_t *currententity;
+vec3_t modelorg; // modelorg is the viewpoint reletive to
+ // the currently rendering entity
+vec3_t r_entorigin; // the currently rendering entity in world
+ // coordinates
+
+float entity_rotation[3][3];
+
+int r_currentbkey;
+
+typedef enum {touchessolid, drawnode, nodrawnode} solidstate_t;
+
+#define MAX_BMODEL_VERTS 500 // 6K
+#define MAX_BMODEL_EDGES 1000 // 12K
+
+static mvertex_t *pbverts;
+static bedge_t *pbedges;
+static int numbverts, numbedges;
+
+static mvertex_t *pfrontenter, *pfrontexit;
+
+static qboolean makeclippededge;
+
+
+//===========================================================================
+
+/*
+================
+R_EntityRotate
+================
+*/
+void R_EntityRotate (vec3_t vec)
+{
+ vec3_t tvec;
+
+ VectorCopy (vec, tvec);
+ vec[0] = DotProduct (entity_rotation[0], tvec);
+ vec[1] = DotProduct (entity_rotation[1], tvec);
+ vec[2] = DotProduct (entity_rotation[2], tvec);
+}
+
+
+/*
+================
+R_RotateBmodel
+================
+*/
+void R_RotateBmodel (void)
+{
+ float angle, s, c, temp1[3][3], temp2[3][3], temp3[3][3];
+
+// TODO: should use a look-up table
+// TODO: should really be stored with the entity instead of being reconstructed
+// TODO: could cache lazily, stored in the entity
+// TODO: share work with R_SetUpAliasTransform
+
+// yaw
+ angle = currententity->angles[YAW];
+ angle = angle * M_PI*2 / 360;
+ s = sin(angle);
+ c = cos(angle);
+
+ temp1[0][0] = c;
+ temp1[0][1] = s;
+ temp1[0][2] = 0;
+ temp1[1][0] = -s;
+ temp1[1][1] = c;
+ temp1[1][2] = 0;
+ temp1[2][0] = 0;
+ temp1[2][1] = 0;
+ temp1[2][2] = 1;
+
+
+// pitch
+ angle = currententity->angles[PITCH];
+ angle = angle * M_PI*2 / 360;
+ s = sin(angle);
+ c = cos(angle);
+
+ temp2[0][0] = c;
+ temp2[0][1] = 0;
+ temp2[0][2] = -s;
+ temp2[1][0] = 0;
+ temp2[1][1] = 1;
+ temp2[1][2] = 0;
+ temp2[2][0] = s;
+ temp2[2][1] = 0;
+ temp2[2][2] = c;
+
+ R_ConcatRotations (temp2, temp1, temp3);
+
+// roll
+ angle = currententity->angles[ROLL];
+ angle = angle * M_PI*2 / 360;
+ s = sin(angle);
+ c = cos(angle);
+
+ temp1[0][0] = 1;
+ temp1[0][1] = 0;
+ temp1[0][2] = 0;
+ temp1[1][0] = 0;
+ temp1[1][1] = c;
+ temp1[1][2] = s;
+ temp1[2][0] = 0;
+ temp1[2][1] = -s;
+ temp1[2][2] = c;
+
+ R_ConcatRotations (temp1, temp3, entity_rotation);
+
+//
+// rotate modelorg and the transformation matrix
+//
+ R_EntityRotate (modelorg);
+ R_EntityRotate (vpn);
+ R_EntityRotate (vright);
+ R_EntityRotate (vup);
+
+ R_TransformFrustum ();
+}
+
+
+/*
+================
+R_RecursiveClipBPoly
+
+Clip a bmodel poly down the world bsp tree
+================
+*/
+void R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf)
+{
+ bedge_t *psideedges[2], *pnextedge, *ptedge;
+ int i, side, lastside;
+ float dist, frac, lastdist;
+ mplane_t *splitplane, tplane;
+ mvertex_t *pvert, *plastvert, *ptvert;
+ mnode_t *pn;
+ int area;
+
+ psideedges[0] = psideedges[1] = NULL;
+
+ makeclippededge = false;
+
+// transform the BSP plane into model space
+// FIXME: cache these?
+ splitplane = pnode->plane;
+ tplane.dist = splitplane->dist -
+ DotProduct(r_entorigin, splitplane->normal);
+ tplane.normal[0] = DotProduct (entity_rotation[0], splitplane->normal);
+ tplane.normal[1] = DotProduct (entity_rotation[1], splitplane->normal);
+ tplane.normal[2] = DotProduct (entity_rotation[2], splitplane->normal);
+
+// clip edges to BSP plane
+ for ( ; pedges ; pedges = pnextedge)
+ {
+ pnextedge = pedges->pnext;
+
+ // set the status for the last point as the previous point
+ // FIXME: cache this stuff somehow?
+ plastvert = pedges->v[0];
+ lastdist = DotProduct (plastvert->position, tplane.normal) -
+ tplane.dist;
+
+ if (lastdist > 0)
+ lastside = 0;
+ else
+ lastside = 1;
+
+ pvert = pedges->v[1];
+
+ dist = DotProduct (pvert->position, tplane.normal) - tplane.dist;
+
+ if (dist > 0)
+ side = 0;
+ else
+ side = 1;
+
+ if (side != lastside)
+ {
+ // clipped
+ if (numbverts >= MAX_BMODEL_VERTS)
+ return;
+
+ // generate the clipped vertex
+ frac = lastdist / (lastdist - dist);
+ ptvert = &pbverts[numbverts++];
+ ptvert->position[0] = plastvert->position[0] +
+ frac * (pvert->position[0] -
+ plastvert->position[0]);
+ ptvert->position[1] = plastvert->position[1] +
+ frac * (pvert->position[1] -
+ plastvert->position[1]);
+ ptvert->position[2] = plastvert->position[2] +
+ frac * (pvert->position[2] -
+ plastvert->position[2]);
+
+ // split into two edges, one on each side, and remember entering
+ // and exiting points
+ // FIXME: share the clip edge by having a winding direction flag?
+ if (numbedges >= (MAX_BMODEL_EDGES - 1))
+ {
+ ri.Con_Printf (PRINT_ALL,"Out of edges for bmodel\n");
+ return;
+ }
+
+ ptedge = &pbedges[numbedges];
+ ptedge->pnext = psideedges[lastside];
+ psideedges[lastside] = ptedge;
+ ptedge->v[0] = plastvert;
+ ptedge->v[1] = ptvert;
+
+ ptedge = &pbedges[numbedges + 1];
+ ptedge->pnext = psideedges[side];
+ psideedges[side] = ptedge;
+ ptedge->v[0] = ptvert;
+ ptedge->v[1] = pvert;
+
+ numbedges += 2;
+
+ if (side == 0)
+ {
+ // entering for front, exiting for back
+ pfrontenter = ptvert;
+ makeclippededge = true;
+ }
+ else
+ {
+ pfrontexit = ptvert;
+ makeclippededge = true;
+ }
+ }
+ else
+ {
+ // add the edge to the appropriate side
+ pedges->pnext = psideedges[side];
+ psideedges[side] = pedges;
+ }
+ }
+
+// if anything was clipped, reconstitute and add the edges along the clip
+// plane to both sides (but in opposite directions)
+ if (makeclippededge)
+ {
+ if (numbedges >= (MAX_BMODEL_EDGES - 2))
+ {
+ ri.Con_Printf (PRINT_ALL,"Out of edges for bmodel\n");
+ return;
+ }
+
+ ptedge = &pbedges[numbedges];
+ ptedge->pnext = psideedges[0];
+ psideedges[0] = ptedge;
+ ptedge->v[0] = pfrontexit;
+ ptedge->v[1] = pfrontenter;
+
+ ptedge = &pbedges[numbedges + 1];
+ ptedge->pnext = psideedges[1];
+ psideedges[1] = ptedge;
+ ptedge->v[0] = pfrontenter;
+ ptedge->v[1] = pfrontexit;
+
+ numbedges += 2;
+ }
+
+// draw or recurse further
+ for (i=0 ; i<2 ; i++)
+ {
+ if (psideedges[i])
+ {
+ // draw if we've reached a non-solid leaf, done if all that's left is a
+ // solid leaf, and continue down the tree if it's not a leaf
+ pn = pnode->children[i];
+
+ // we're done with this branch if the node or leaf isn't in the PVS
+ if (pn->visframe == r_visframecount)
+ {
+ if (pn->contents != CONTENTS_NODE)
+ {
+ if (pn->contents != CONTENTS_SOLID)
+ {
+ if (r_newrefdef.areabits)
+ {
+ area = ((mleaf_t *)pn)->area;
+ if (! (r_newrefdef.areabits[area>>3] & (1<<(area&7)) ) )
+ continue; // not visible
+ }
+
+ r_currentbkey = ((mleaf_t *)pn)->key;
+ R_RenderBmodelFace (psideedges[i], psurf);
+ }
+ }
+ else
+ {
+ R_RecursiveClipBPoly (psideedges[i], pnode->children[i],
+ psurf);
+ }
+ }
+ }
+ }
+}
+
+
+/*
+================
+R_DrawSolidClippedSubmodelPolygons
+
+Bmodel crosses multiple leafs
+================
+*/
+void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel, mnode_t *topnode)
+{
+ int i, j, lindex;
+ vec_t dot;
+ msurface_t *psurf;
+ int numsurfaces;
+ mplane_t *pplane;
+ mvertex_t bverts[MAX_BMODEL_VERTS];
+ bedge_t bedges[MAX_BMODEL_EDGES], *pbedge;
+ medge_t *pedge, *pedges;
+
+// FIXME: use bounding-box-based frustum clipping info?
+
+ psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
+ numsurfaces = pmodel->nummodelsurfaces;
+ pedges = pmodel->edges;
+
+ for (i=0 ; i<numsurfaces ; i++, psurf++)
+ {
+ // find which side of the node we are on
+ pplane = psurf->plane;
+
+ dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
+
+ // draw the polygon
+ if (( !(psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
+ ((psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
+ continue;
+
+ // FIXME: use bounding-box-based frustum clipping info?
+
+ // copy the edges to bedges, flipping if necessary so always
+ // clockwise winding
+ // FIXME: if edges and vertices get caches, these assignments must move
+ // outside the loop, and overflow checking must be done here
+ pbverts = bverts;
+ pbedges = bedges;
+ numbverts = numbedges = 0;
+ pbedge = &bedges[numbedges];
+ numbedges += psurf->numedges;
+
+ for (j=0 ; j<psurf->numedges ; j++)
+ {
+ lindex = pmodel->surfedges[psurf->firstedge+j];
+
+ if (lindex > 0)
+ {
+ pedge = &pedges[lindex];
+ pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]];
+ pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]];
+ }
+ else
+ {
+ lindex = -lindex;
+ pedge = &pedges[lindex];
+ pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]];
+ pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]];
+ }
+
+ pbedge[j].pnext = &pbedge[j+1];
+ }
+
+ pbedge[j-1].pnext = NULL; // mark end of edges
+
+ if ( !( psurf->texinfo->flags & ( SURF_TRANS66 | SURF_TRANS33 ) ) )
+ R_RecursiveClipBPoly (pbedge, topnode, psurf);
+ else
+ R_RenderBmodelFace( pbedge, psurf );
+ }
+}
+
+
+/*
+================
+R_DrawSubmodelPolygons
+
+All in one leaf
+================
+*/
+void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags, mnode_t *topnode)
+{
+ int i;
+ vec_t dot;
+ msurface_t *psurf;
+ int numsurfaces;
+ mplane_t *pplane;
+
+// FIXME: use bounding-box-based frustum clipping info?
+
+ psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
+ numsurfaces = pmodel->nummodelsurfaces;
+
+ for (i=0 ; i<numsurfaces ; i++, psurf++)
+ {
+ // find which side of the node we are on
+ pplane = psurf->plane;
+
+ dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
+
+ // draw the polygon
+ if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
+ (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
+ {
+ r_currentkey = ((mleaf_t *)topnode)->key;
+
+ // FIXME: use bounding-box-based frustum clipping info?
+ R_RenderFace (psurf, clipflags);
+ }
+ }
+}
+
+
+int c_drawnode;
+
+/*
+================
+R_RecursiveWorldNode
+================
+*/
+void R_RecursiveWorldNode (mnode_t *node, int clipflags)
+{
+ int i, c, side, *pindex;
+ vec3_t acceptpt, rejectpt;
+ mplane_t *plane;
+ msurface_t *surf, **mark;
+ float d, dot;
+ mleaf_t *pleaf;
+
+ if (node->contents == CONTENTS_SOLID)
+ return; // solid
+
+ if (node->visframe != r_visframecount)
+ return;
+
+// cull the clipping planes if not trivial accept
+// FIXME: the compiler is doing a lousy job of optimizing here; it could be
+// twice as fast in ASM
+ if (clipflags)
+ {
+ for (i=0 ; i<4 ; i++)
+ {
+ if (! (clipflags & (1<<i)) )
+ continue; // don't need to clip against it
+
+ // generate accept and reject points
+ // FIXME: do with fast look-ups or integer tests based on the sign bit
+ // of the floating point values
+
+ pindex = pfrustum_indexes[i];
+
+ rejectpt[0] = (float)node->minmaxs[pindex[0]];
+ rejectpt[1] = (float)node->minmaxs[pindex[1]];
+ rejectpt[2] = (float)node->minmaxs[pindex[2]];
+
+ d = DotProduct (rejectpt, view_clipplanes[i].normal);
+ d -= view_clipplanes[i].dist;
+ if (d <= 0)
+ return;
+ acceptpt[0] = (float)node->minmaxs[pindex[3+0]];
+ acceptpt[1] = (float)node->minmaxs[pindex[3+1]];
+ acceptpt[2] = (float)node->minmaxs[pindex[3+2]];
+
+ d = DotProduct (acceptpt, view_clipplanes[i].normal);
+ d -= view_clipplanes[i].dist;
+
+ if (d >= 0)
+ clipflags &= ~(1<<i); // node is entirely on screen
+ }
+ }
+
+c_drawnode++;
+
+// if a leaf node, draw stuff
+ if (node->contents != -1)
+ {
+ pleaf = (mleaf_t *)node;
+
+ // check for door connected areas
+ if (r_newrefdef.areabits)
+ {
+ if (! (r_newrefdef.areabits[pleaf->area>>3] & (1<<(pleaf->area&7)) ) )
+ return; // not visible
+ }
+
+ mark = pleaf->firstmarksurface;
+ c = pleaf->nummarksurfaces;
+
+ if (c)
+ {
+ do
+ {
+ (*mark)->visframe = r_framecount;
+ mark++;
+ } while (--c);
+ }
+
+ pleaf->key = r_currentkey;
+ r_currentkey++; // all bmodels in a leaf share the same key
+ }
+ else
+ {
+ // node is just a decision point, so go down the apropriate sides
+
+ // find which side of the node we are on
+ plane = node->plane;
+
+ switch (plane->type)
+ {
+ case PLANE_X:
+ dot = modelorg[0] - plane->dist;
+ break;
+ case PLANE_Y:
+ dot = modelorg[1] - plane->dist;
+ break;
+ case PLANE_Z:
+ dot = modelorg[2] - plane->dist;
+ break;
+ default:
+ dot = DotProduct (modelorg, plane->normal) - plane->dist;
+ break;
+ }
+
+ if (dot >= 0)
+ side = 0;
+ else
+ side = 1;
+
+ // recurse down the children, front side first
+ R_RecursiveWorldNode (node->children[side], clipflags);
+
+ // draw stuff
+ c = node->numsurfaces;
+
+ if (c)
+ {
+ surf = r_worldmodel->surfaces + node->firstsurface;
+
+ if (dot < -BACKFACE_EPSILON)
+ {
+ do
+ {
+ if ((surf->flags & SURF_PLANEBACK) &&
+ (surf->visframe == r_framecount))
+ {
+ R_RenderFace (surf, clipflags);
+ }
+
+ surf++;
+ } while (--c);
+ }
+ else if (dot > BACKFACE_EPSILON)
+ {
+ do
+ {
+ if (!(surf->flags & SURF_PLANEBACK) &&
+ (surf->visframe == r_framecount))
+ {
+ R_RenderFace (surf, clipflags);
+ }
+
+ surf++;
+ } while (--c);
+ }
+
+ // all surfaces on the same node share the same sequence number
+ r_currentkey++;
+ }
+
+ // recurse down the back side
+ R_RecursiveWorldNode (node->children[!side], clipflags);
+ }
+}
+
+
+
+/*
+================
+R_RenderWorld
+================
+*/
+void R_RenderWorld (void)
+{
+
+ if (!r_drawworld->value)
+ return;
+ if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
+ return;
+
+ c_drawnode=0;
+
+ // auto cycle the world frame for texture animation
+ r_worldentity.frame = (int)(r_newrefdef.time*2);
+ currententity = &r_worldentity;
+
+ VectorCopy (r_origin, modelorg);
+ currentmodel = r_worldmodel;
+ r_pcurrentvertbase = currentmodel->vertexes;
+
+ R_RecursiveWorldNode (currentmodel->nodes, 15);
+}
+
+
--- /dev/null
+++ b/r_draw.c
@@ -1,0 +1,427 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+
+image_t *draw_chars; // 8*8 graphic characters
+
+//=============================================================================
+
+/*
+================
+Draw_FindPic
+================
+*/
+image_t *Draw_FindPic (char *name)
+{
+ image_t *image;
+ char fullname[MAX_QPATH];
+
+ if (name[0] != '/' && name[0] != '\\')
+ {
+ Com_sprintf (fullname, sizeof(fullname), "pics/%s.pcx", name);
+ image = R_FindImage (fullname, it_pic);
+ }
+ else
+ image = R_FindImage (name+1, it_pic);
+
+ return image;
+}
+
+
+
+/*
+===============
+Draw_InitLocal
+===============
+*/
+void Draw_InitLocal (void)
+{
+ draw_chars = Draw_FindPic ("conchars");
+}
+
+
+
+/*
+================
+Draw_Char
+
+Draws one 8*8 graphics character
+It can be clipped to the top of the screen to allow the console to be
+smoothly scrolled off.
+================
+*/
+void Draw_Char (int x, int y, int num)
+{
+ byte *dest;
+ byte *source;
+ int drawline;
+ int row, col;
+
+ num &= 255;
+
+ if (num == 32 || num == 32+128)
+ return;
+
+ if (y <= -8)
+ return; // totally off screen
+
+// if ( ( y + 8 ) >= vid.height )
+ if ( ( y + 8 ) > vid.height ) // PGM - status text was missing in sw...
+ return;
+
+#ifdef PARANOID
+ if (y > vid.height - 8 || x < 0 || x > vid.width - 8)
+ ri.Sys_Error (ERR_FATAL,"Con_DrawCharacter: (%i, %i)", x, y);
+ if (num < 0 || num > 255)
+ ri.Sys_Error (ERR_FATAL,"Con_DrawCharacter: char %i", num);
+#endif
+
+ row = num>>4;
+ col = num&15;
+ source = draw_chars->pixels[0] + (row<<10) + (col<<3);
+
+ if (y < 0)
+ { // clipped
+ drawline = 8 + y;
+ source -= 128*y;
+ y = 0;
+ }
+ else
+ drawline = 8;
+
+
+ dest = vid.buffer + y*vid.rowbytes + x;
+
+ while (drawline--)
+ {
+ if (source[0] != TRANSPARENT_COLOR)
+ dest[0] = source[0];
+ if (source[1] != TRANSPARENT_COLOR)
+ dest[1] = source[1];
+ if (source[2] != TRANSPARENT_COLOR)
+ dest[2] = source[2];
+ if (source[3] != TRANSPARENT_COLOR)
+ dest[3] = source[3];
+ if (source[4] != TRANSPARENT_COLOR)
+ dest[4] = source[4];
+ if (source[5] != TRANSPARENT_COLOR)
+ dest[5] = source[5];
+ if (source[6] != TRANSPARENT_COLOR)
+ dest[6] = source[6];
+ if (source[7] != TRANSPARENT_COLOR)
+ dest[7] = source[7];
+ source += 128;
+ dest += vid.rowbytes;
+ }
+}
+
+/*
+=============
+Draw_GetPicSize
+=============
+*/
+void Draw_GetPicSize (int *w, int *h, char *pic)
+{
+ image_t *gl;
+
+ gl = Draw_FindPic (pic);
+ if (!gl)
+ {
+ *w = *h = -1;
+ return;
+ }
+ *w = gl->width;
+ *h = gl->height;
+}
+
+/*
+=============
+Draw_StretchPicImplementation
+=============
+*/
+void Draw_StretchPicImplementation (int x, int y, int w, int h, image_t *pic)
+{
+ byte *dest, *source;
+ int v, u, sv;
+ int height;
+ int f, fstep;
+ int skip;
+
+ if ((x < 0) ||
+ (x + w > vid.width) ||
+ (y + h > vid.height))
+ {
+ ri.Sys_Error (ERR_FATAL,"Draw_Pic: bad coordinates");
+ }
+
+ height = h;
+ if (y < 0)
+ {
+ skip = -y;
+ height += y;
+ y = 0;
+ }
+ else
+ skip = 0;
+
+ dest = vid.buffer + y * vid.rowbytes + x;
+
+ for (v=0 ; v<height ; v++, dest += vid.rowbytes)
+ {
+ sv = (skip + v)*pic->height/h;
+ source = pic->pixels[0] + sv*pic->width;
+ if (w == pic->width)
+ memcpy (dest, source, w);
+ else
+ {
+ f = 0;
+ fstep = pic->width*0x10000/w;
+ for (u=0 ; u<w ; u+=4)
+ {
+ dest[u] = source[f>>16];
+ f += fstep;
+ dest[u+1] = source[f>>16];
+ f += fstep;
+ dest[u+2] = source[f>>16];
+ f += fstep;
+ dest[u+3] = source[f>>16];
+ f += fstep;
+ }
+ }
+ }
+}
+
+/*
+=============
+Draw_StretchPic
+=============
+*/
+void Draw_StretchPic (int x, int y, int w, int h, char *name)
+{
+ image_t *pic;
+
+ pic = Draw_FindPic (name);
+ if (!pic)
+ {
+ ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", name);
+ return;
+ }
+ Draw_StretchPicImplementation (x, y, w, h, pic);
+}
+
+/*
+=============
+Draw_StretchRaw
+=============
+*/
+void Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data)
+{
+ image_t pic;
+
+ pic.pixels[0] = data;
+ pic.width = cols;
+ pic.height = rows;
+ Draw_StretchPicImplementation (x, y, w, h, &pic);
+}
+
+/*
+=============
+Draw_Pic
+=============
+*/
+void Draw_Pic (int x, int y, char *name)
+{
+ image_t *pic;
+ byte *dest, *source;
+ int v, u;
+ int tbyte;
+ int height;
+
+ pic = Draw_FindPic (name);
+ if (!pic)
+ {
+ ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", name);
+ return;
+ }
+
+ if ((x < 0) ||
+ (x + pic->width > vid.width) ||
+ (y + pic->height > vid.height))
+ return; // ri.Sys_Error (ERR_FATAL,"Draw_Pic: bad coordinates");
+
+ height = pic->height;
+ source = pic->pixels[0];
+ if (y < 0)
+ {
+ height += y;
+ source += pic->width*-y;
+ y = 0;
+ }
+
+ dest = vid.buffer + y * vid.rowbytes + x;
+
+ if (!pic->transparent)
+ {
+ for (v=0 ; v<height ; v++)
+ {
+ memcpy (dest, source, pic->width);
+ dest += vid.rowbytes;
+ source += pic->width;
+ }
+ }
+ else
+ {
+ if (pic->width & 7)
+ { // general
+ for (v=0 ; v<height ; v++)
+ {
+ for (u=0 ; u<pic->width ; u++)
+ if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
+ dest[u] = tbyte;
+
+ dest += vid.rowbytes;
+ source += pic->width;
+ }
+ }
+ else
+ { // unwound
+ for (v=0 ; v<height ; v++)
+ {
+ for (u=0 ; u<pic->width ; u+=8)
+ {
+ if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
+ dest[u] = tbyte;
+ if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR)
+ dest[u+1] = tbyte;
+ if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR)
+ dest[u+2] = tbyte;
+ if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR)
+ dest[u+3] = tbyte;
+ if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR)
+ dest[u+4] = tbyte;
+ if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR)
+ dest[u+5] = tbyte;
+ if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR)
+ dest[u+6] = tbyte;
+ if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR)
+ dest[u+7] = tbyte;
+ }
+ dest += vid.rowbytes;
+ source += pic->width;
+ }
+ }
+ }
+}
+
+/*
+=============
+Draw_TileClear
+
+This repeats a 64*64 tile graphic to fill the screen around a sized down
+refresh window.
+=============
+*/
+void Draw_TileClear (int x, int y, int w, int h, char *name)
+{
+ int i, j;
+ byte *psrc;
+ byte *pdest;
+ image_t *pic;
+ int x2;
+
+ if (x < 0)
+ {
+ w += x;
+ x = 0;
+ }
+ if (y < 0)
+ {
+ h += y;
+ y = 0;
+ }
+ if (x + w > vid.width)
+ w = vid.width - x;
+ if (y + h > vid.height)
+ h = vid.height - y;
+ if (w <= 0 || h <= 0)
+ return;
+
+ pic = Draw_FindPic (name);
+ if (!pic)
+ {
+ ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", name);
+ return;
+ }
+ x2 = x + w;
+ pdest = vid.buffer + y*vid.rowbytes;
+ for (i=0 ; i<h ; i++, pdest += vid.rowbytes)
+ {
+ psrc = pic->pixels[0] + pic->width * ((i+y)&63);
+ for (j=x ; j<x2 ; j++)
+ pdest[j] = psrc[j&63];
+ }
+}
+
+
+/*
+=============
+Draw_Fill
+
+Fills a box of pixels with a single color
+=============
+*/
+void Draw_Fill (int x, int y, int w, int h, int c)
+{
+ byte *dest;
+ int u, v;
+
+ if (x+w > vid.width)
+ w = vid.width - x;
+ if (y+h > vid.height)
+ h = vid.height - y;
+ if (x < 0)
+ {
+ w += x;
+ x = 0;
+ }
+ if (y < 0)
+ {
+ h += y;
+ y = 0;
+ }
+ if (w < 0 || h < 0)
+ return;
+ dest = vid.buffer + y*vid.rowbytes + x;
+ for (v=0 ; v<h ; v++, dest += vid.rowbytes)
+ for (u=0 ; u<w ; u++)
+ dest[u] = c;
+}
+//=============================================================================
+
+/*
+================
+Draw_FadeScreen
+
+================
+*/
+void Draw_FadeScreen (void)
+{
+ int x,y;
+ byte *pbuf;
+ int t;
+
+ for (y=0 ; y<vid.height ; y++)
+ {
+ pbuf = (byte *)(vid.buffer + vid.rowbytes*y);
+ t = (y & 1) << 1;
+
+ for (x=0 ; x<vid.width ; x++)
+ {
+ if ((x & 3) != t)
+ pbuf[x] = 0;
+ }
+ }
+}
--- /dev/null
+++ b/r_edge.c
@@ -1,0 +1,1085 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+void R_SurfacePatch (void)
+{
+}
+
+void R_EdgeCodeStart (void)
+{
+}
+
+void R_EdgeCodeEnd (void)
+{
+}
+
+
+/*
+the complex cases add new polys on most lines, so dont optimize for keeping them the same
+have multiple free span lists to try to get better coherence?
+low depth complexity -- 1 to 3 or so
+
+have a sentinal at both ends?
+*/
+
+
+edge_t *auxedges;
+edge_t *r_edges, *edge_p, *edge_max;
+
+surf_t *surfaces, *surface_p, *surf_max;
+
+// surfaces are generated in back to front order by the bsp, so if a surf
+// pointer is greater than another one, it should be drawn in front
+// surfaces[1] is the background, and is used as the active surface stack
+
+edge_t *newedges[MAXHEIGHT];
+edge_t *removeedges[MAXHEIGHT];
+
+espan_t *span_p, *max_span_p;
+
+int r_currentkey;
+
+int current_iv;
+
+int edge_head_u_shift20, edge_tail_u_shift20;
+
+static void (*pdrawfunc)(void);
+
+edge_t edge_head;
+edge_t edge_tail;
+edge_t edge_aftertail;
+edge_t edge_sentinel;
+
+float fv;
+
+static int miplevel;
+
+float scale_for_mip;
+int ubasestep, errorterm, erroradjustup, erroradjustdown;
+
+// FIXME: should go away
+extern void R_RotateBmodel (void);
+extern void R_TransformFrustum (void);
+
+
+
+void R_GenerateSpans (void);
+void R_GenerateSpansBackward (void);
+
+void R_LeadingEdge (edge_t *edge);
+void R_LeadingEdgeBackwards (edge_t *edge);
+void R_TrailingEdge (surf_t *surf, edge_t *edge);
+
+
+/*
+===============================================================================
+
+EDGE SCANNING
+
+===============================================================================
+*/
+
+/*
+==============
+R_BeginEdgeFrame
+==============
+*/
+void R_BeginEdgeFrame (void)
+{
+ int v;
+
+ edge_p = r_edges;
+ edge_max = &r_edges[r_numallocatededges];
+
+ surface_p = &surfaces[2]; // background is surface 1,
+ // surface 0 is a dummy
+ surfaces[1].spans = NULL; // no background spans yet
+ surfaces[1].flags = SURF_DRAWBACKGROUND;
+
+// put the background behind everything in the world
+ if (sw_draworder->value)
+ {
+ pdrawfunc = R_GenerateSpansBackward;
+ surfaces[1].key = 0;
+ r_currentkey = 1;
+ }
+ else
+ {
+ pdrawfunc = R_GenerateSpans;
+ surfaces[1].key = 0x7FFfFFFF;
+ r_currentkey = 0;
+ }
+
+// FIXME: set with memset
+ for (v=r_refdef.vrect.y ; v<r_refdef.vrectbottom ; v++)
+ {
+ newedges[v] = removeedges[v] = NULL;
+ }
+}
+
+/*
+==============
+R_InsertNewEdges
+
+Adds the edges in the linked list edgestoadd, adding them to the edges in the
+linked list edgelist. edgestoadd is assumed to be sorted on u, and non-empty (this is actually newedges[v]). edgelist is assumed to be sorted on u, with a
+sentinel at the end (actually, this is the active edge table starting at
+edge_head.next).
+==============
+*/
+void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist)
+{
+ edge_t *next_edge;
+
+ do
+ {
+ next_edge = edgestoadd->next;
+edgesearch:
+ if (edgelist->u >= edgestoadd->u)
+ goto addedge;
+ edgelist=edgelist->next;
+ if (edgelist->u >= edgestoadd->u)
+ goto addedge;
+ edgelist=edgelist->next;
+ if (edgelist->u >= edgestoadd->u)
+ goto addedge;
+ edgelist=edgelist->next;
+ if (edgelist->u >= edgestoadd->u)
+ goto addedge;
+ edgelist=edgelist->next;
+ goto edgesearch;
+
+ // insert edgestoadd before edgelist
+addedge:
+ edgestoadd->next = edgelist;
+ edgestoadd->prev = edgelist->prev;
+ edgelist->prev->next = edgestoadd;
+ edgelist->prev = edgestoadd;
+ } while ((edgestoadd = next_edge) != NULL);
+}
+
+
+/*
+==============
+R_RemoveEdges
+==============
+*/
+void R_RemoveEdges (edge_t *pedge)
+{
+
+ do
+ {
+ pedge->next->prev = pedge->prev;
+ pedge->prev->next = pedge->next;
+ } while ((pedge = pedge->nextremove) != NULL);
+}
+
+
+/*
+==============
+R_StepActiveU
+==============
+*/
+void R_StepActiveU (edge_t *pedge)
+{
+ edge_t *pnext_edge, *pwedge;
+
+ while (1)
+ {
+nextedge:
+ pedge->u += pedge->u_step;
+ if (pedge->u < pedge->prev->u)
+ goto pushback;
+ pedge = pedge->next;
+
+ pedge->u += pedge->u_step;
+ if (pedge->u < pedge->prev->u)
+ goto pushback;
+ pedge = pedge->next;
+
+ pedge->u += pedge->u_step;
+ if (pedge->u < pedge->prev->u)
+ goto pushback;
+ pedge = pedge->next;
+
+ pedge->u += pedge->u_step;
+ if (pedge->u < pedge->prev->u)
+ goto pushback;
+ pedge = pedge->next;
+
+ goto nextedge;
+
+pushback:
+ if (pedge == &edge_aftertail)
+ return;
+
+ // push it back to keep it sorted
+ pnext_edge = pedge->next;
+
+ // pull the edge out of the edge list
+ pedge->next->prev = pedge->prev;
+ pedge->prev->next = pedge->next;
+
+ // find out where the edge goes in the edge list
+ pwedge = pedge->prev->prev;
+
+ while (pwedge->u > pedge->u)
+ {
+ pwedge = pwedge->prev;
+ }
+
+ // put the edge back into the edge list
+ pedge->next = pwedge->next;
+ pedge->prev = pwedge;
+ pedge->next->prev = pedge;
+ pwedge->next = pedge;
+
+ pedge = pnext_edge;
+ if (pedge == &edge_tail)
+ return;
+ }
+}
+
+
+/*
+==============
+R_CleanupSpan
+==============
+*/
+void R_CleanupSpan (void)
+{
+ surf_t *surf;
+ int iu;
+ espan_t *span;
+
+// now that we've reached the right edge of the screen, we're done with any
+// unfinished surfaces, so emit a span for whatever's on top
+ surf = surfaces[1].next;
+ iu = edge_tail_u_shift20;
+ if (iu > surf->last_u)
+ {
+ span = span_p++;
+ span->u = surf->last_u;
+ span->count = iu - span->u;
+ span->v = current_iv;
+ span->pnext = surf->spans;
+ surf->spans = span;
+ }
+
+// reset spanstate for all surfaces in the surface stack
+ do
+ {
+ surf->spanstate = 0;
+ surf = surf->next;
+ } while (surf != &surfaces[1]);
+}
+
+
+/*
+==============
+R_LeadingEdgeBackwards
+==============
+*/
+void R_LeadingEdgeBackwards (edge_t *edge)
+{
+ espan_t *span;
+ surf_t *surf, *surf2;
+ int iu;
+
+// it's adding a new surface in, so find the correct place
+ surf = &surfaces[edge->surfs[1]];
+
+// don't start a span if this is an inverted span, with the end
+// edge preceding the start edge (that is, we've already seen the
+// end edge)
+ if (++surf->spanstate == 1)
+ {
+ surf2 = surfaces[1].next;
+
+ if (surf->key > surf2->key)
+ goto newtop;
+
+ // if it's two surfaces on the same plane, the one that's already
+ // active is in front, so keep going unless it's a bmodel
+ if (surf->insubmodel && (surf->key == surf2->key))
+ {
+ // must be two bmodels in the same leaf; don't care, because they'll
+ // never be farthest anyway
+ goto newtop;
+ }
+
+continue_search:
+
+ do
+ {
+ surf2 = surf2->next;
+ } while (surf->key < surf2->key);
+
+ if (surf->key == surf2->key)
+ {
+ // if it's two surfaces on the same plane, the one that's already
+ // active is in front, so keep going unless it's a bmodel
+ if (!surf->insubmodel)
+ goto continue_search;
+
+ // must be two bmodels in the same leaf; don't care which is really
+ // in front, because they'll never be farthest anyway
+ }
+
+ goto gotposition;
+
+newtop:
+ // emit a span (obscures current top)
+ iu = edge->u >> 20;
+
+ if (iu > surf2->last_u)
+ {
+ span = span_p++;
+ span->u = surf2->last_u;
+ span->count = iu - span->u;
+ span->v = current_iv;
+ span->pnext = surf2->spans;
+ surf2->spans = span;
+ }
+
+ // set last_u on the new span
+ surf->last_u = iu;
+
+gotposition:
+ // insert before surf2
+ surf->next = surf2;
+ surf->prev = surf2->prev;
+ surf2->prev->next = surf;
+ surf2->prev = surf;
+ }
+}
+
+
+/*
+==============
+R_TrailingEdge
+==============
+*/
+void R_TrailingEdge (surf_t *surf, edge_t *edge)
+{
+ espan_t *span;
+ int iu;
+
+// don't generate a span if this is an inverted span, with the end
+// edge preceding the start edge (that is, we haven't seen the
+// start edge yet)
+ if (--surf->spanstate == 0)
+ {
+ if (surf == surfaces[1].next)
+ {
+ // emit a span (current top going away)
+ iu = edge->u >> 20;
+ if (iu > surf->last_u)
+ {
+ span = span_p++;
+ span->u = surf->last_u;
+ span->count = iu - span->u;
+ span->v = current_iv;
+ span->pnext = surf->spans;
+ surf->spans = span;
+ }
+
+ // set last_u on the surface below
+ surf->next->last_u = iu;
+ }
+
+ surf->prev->next = surf->next;
+ surf->next->prev = surf->prev;
+ }
+}
+
+
+/*
+==============
+R_LeadingEdge
+==============
+*/
+void R_LeadingEdge (edge_t *edge)
+{
+ espan_t *span;
+ surf_t *surf, *surf2;
+ int iu;
+ float fu, newzi, testzi, newzitop, newzibottom;
+
+ if (edge->surfs[1])
+ {
+ // it's adding a new surface in, so find the correct place
+ surf = &surfaces[edge->surfs[1]];
+
+ // don't start a span if this is an inverted span, with the end
+ // edge preceding the start edge (that is, we've already seen the
+ // end edge)
+ if (++surf->spanstate == 1)
+ {
+ surf2 = surfaces[1].next;
+
+ if (surf->key < surf2->key)
+ goto newtop;
+
+ // if it's two surfaces on the same plane, the one that's already
+ // active is in front, so keep going unless it's a bmodel
+ if (surf->insubmodel && (surf->key == surf2->key))
+ {
+ // must be two bmodels in the same leaf; sort on 1/z
+ fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
+ newzi = surf->d_ziorigin + fv*surf->d_zistepv +
+ fu*surf->d_zistepu;
+ newzibottom = newzi * 0.99;
+
+ testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
+ fu*surf2->d_zistepu;
+
+ if (newzibottom >= testzi)
+ {
+ goto newtop;
+ }
+
+ newzitop = newzi * 1.01;
+ if (newzitop >= testzi)
+ {
+ if (surf->d_zistepu >= surf2->d_zistepu)
+ {
+ goto newtop;
+ }
+ }
+ }
+
+continue_search:
+
+ do
+ {
+ surf2 = surf2->next;
+ } while (surf->key > surf2->key);
+
+ if (surf->key == surf2->key)
+ {
+ // if it's two surfaces on the same plane, the one that's already
+ // active is in front, so keep going unless it's a bmodel
+ if (!surf->insubmodel)
+ goto continue_search;
+
+ // must be two bmodels in the same leaf; sort on 1/z
+ fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
+ newzi = surf->d_ziorigin + fv*surf->d_zistepv +
+ fu*surf->d_zistepu;
+ newzibottom = newzi * 0.99;
+
+ testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
+ fu*surf2->d_zistepu;
+
+ if (newzibottom >= testzi)
+ {
+ goto gotposition;
+ }
+
+ newzitop = newzi * 1.01;
+ if (newzitop >= testzi)
+ {
+ if (surf->d_zistepu >= surf2->d_zistepu)
+ {
+ goto gotposition;
+ }
+ }
+
+ goto continue_search;
+ }
+
+ goto gotposition;
+
+newtop:
+ // emit a span (obscures current top)
+ iu = edge->u >> 20;
+
+ if (iu > surf2->last_u)
+ {
+ span = span_p++;
+ span->u = surf2->last_u;
+ span->count = iu - span->u;
+ span->v = current_iv;
+ span->pnext = surf2->spans;
+ surf2->spans = span;
+ }
+
+ // set last_u on the new span
+ surf->last_u = iu;
+
+gotposition:
+ // insert before surf2
+ surf->next = surf2;
+ surf->prev = surf2->prev;
+ surf2->prev->next = surf;
+ surf2->prev = surf;
+ }
+ }
+}
+
+
+/*
+==============
+R_GenerateSpans
+==============
+*/
+void R_GenerateSpans (void)
+{
+ edge_t *edge;
+ surf_t *surf;
+
+// clear active surfaces to just the background surface
+ surfaces[1].next = surfaces[1].prev = &surfaces[1];
+ surfaces[1].last_u = edge_head_u_shift20;
+
+// generate spans
+ for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
+ {
+ if (edge->surfs[0])
+ {
+ // it has a left surface, so a surface is going away for this span
+ surf = &surfaces[edge->surfs[0]];
+
+ R_TrailingEdge (surf, edge);
+
+ if (!edge->surfs[1])
+ continue;
+ }
+
+ R_LeadingEdge (edge);
+ }
+
+ R_CleanupSpan ();
+}
+
+
+/*
+==============
+R_GenerateSpansBackward
+==============
+*/
+void R_GenerateSpansBackward (void)
+{
+ edge_t *edge;
+
+// clear active surfaces to just the background surface
+ surfaces[1].next = surfaces[1].prev = &surfaces[1];
+ surfaces[1].last_u = edge_head_u_shift20;
+
+// generate spans
+ for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
+ {
+ if (edge->surfs[0])
+ R_TrailingEdge (&surfaces[edge->surfs[0]], edge);
+
+ if (edge->surfs[1])
+ R_LeadingEdgeBackwards (edge);
+ }
+
+ R_CleanupSpan ();
+}
+
+
+/*
+==============
+R_ScanEdges
+
+Input:
+newedges[] array
+ this has links to edges, which have links to surfaces
+
+Output:
+Each surface has a linked list of its visible spans
+==============
+*/
+void R_ScanEdges (void)
+{
+ int iv, bottom;
+ byte basespans[MAXSPANS*sizeof(espan_t)+CACHE_SIZE];
+ espan_t *basespan_p;
+ surf_t *s;
+
+ basespan_p = (espan_t *)
+ ((uintptr)(basespans + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
+ max_span_p = &basespan_p[MAXSPANS - r_refdef.vrect.width];
+
+ span_p = basespan_p;
+
+// clear active edges to just the background edges around the whole screen
+// FIXME: most of this only needs to be set up once
+ edge_head.u = r_refdef.vrect.x << 20;
+ edge_head_u_shift20 = edge_head.u >> 20;
+ edge_head.u_step = 0;
+ edge_head.prev = NULL;
+ edge_head.next = &edge_tail;
+ edge_head.surfs[0] = 0;
+ edge_head.surfs[1] = 1;
+
+ edge_tail.u = (r_refdef.vrectright << 20) + 0xFFFFF;
+ edge_tail_u_shift20 = edge_tail.u >> 20;
+ edge_tail.u_step = 0;
+ edge_tail.prev = &edge_head;
+ edge_tail.next = &edge_aftertail;
+ edge_tail.surfs[0] = 1;
+ edge_tail.surfs[1] = 0;
+
+ edge_aftertail.u = -1; // force a move
+ edge_aftertail.u_step = 0;
+ edge_aftertail.next = &edge_sentinel;
+ edge_aftertail.prev = &edge_tail;
+
+// FIXME: do we need this now that we clamp x in r_draw.c?
+ edge_sentinel.u = 2000 << 24; // make sure nothing sorts past this
+ edge_sentinel.prev = &edge_aftertail;
+
+//
+// process all scan lines
+//
+ bottom = r_refdef.vrectbottom - 1;
+
+ for (iv=r_refdef.vrect.y ; iv<bottom ; iv++)
+ {
+ current_iv = iv;
+ fv = (float)iv;
+
+ // mark that the head (background start) span is pre-included
+ surfaces[1].spanstate = 1;
+
+ if (newedges[iv])
+ {
+ R_InsertNewEdges (newedges[iv], edge_head.next);
+ }
+
+ (*pdrawfunc) ();
+
+ // flush the span list if we can't be sure we have enough spans left for
+ // the next scan
+ if (span_p > max_span_p)
+ {
+ D_DrawSurfaces ();
+
+ // clear the surface span pointers
+ for (s = &surfaces[1] ; s<surface_p ; s++)
+ s->spans = NULL;
+
+ span_p = basespan_p;
+ }
+
+ if (removeedges[iv])
+ R_RemoveEdges (removeedges[iv]);
+
+ if (edge_head.next != &edge_tail)
+ R_StepActiveU (edge_head.next);
+ }
+
+// do the last scan (no need to step or sort or remove on the last scan)
+
+ current_iv = iv;
+ fv = (float)iv;
+
+// mark that the head (background start) span is pre-included
+ surfaces[1].spanstate = 1;
+
+ if (newedges[iv])
+ R_InsertNewEdges (newedges[iv], edge_head.next);
+
+ (*pdrawfunc) ();
+
+// draw whatever's left in the span list
+ D_DrawSurfaces ();
+}
+
+
+/*
+=========================================================================
+
+SURFACE FILLING
+
+=========================================================================
+*/
+
+msurface_t *pface;
+surfcache_t *pcurrentcache;
+vec3_t transformed_modelorg;
+vec3_t world_transformed_modelorg;
+vec3_t local_modelorg;
+
+/*
+=============
+D_MipLevelForScale
+=============
+*/
+int D_MipLevelForScale (float scale)
+{
+ int lmiplevel;
+
+ if (scale >= d_scalemip[0] )
+ lmiplevel = 0;
+ else if (scale >= d_scalemip[1] )
+ lmiplevel = 1;
+ else if (scale >= d_scalemip[2] )
+ lmiplevel = 2;
+ else
+ lmiplevel = 3;
+
+ if (lmiplevel < d_minmip)
+ lmiplevel = d_minmip;
+
+ return lmiplevel;
+}
+
+
+/*
+==============
+D_FlatFillSurface
+
+Simple single color fill with no texture mapping
+==============
+*/
+void D_FlatFillSurface (surf_t *surf, int color)
+{
+ espan_t *span;
+ byte *pdest;
+ int u, u2;
+
+ for (span=surf->spans ; span ; span=span->pnext)
+ {
+ pdest = (byte *)d_viewbuffer + r_screenwidth*span->v;
+ u = span->u;
+ u2 = span->u + span->count - 1;
+ for ( ; u <= u2 ; u++)
+ pdest[u] = color;
+ }
+}
+
+
+/*
+==============
+D_CalcGradients
+==============
+*/
+void D_CalcGradients (msurface_t *pface)
+{
+ float mipscale;
+ vec3_t p_temp1;
+ vec3_t p_saxis, p_taxis;
+ float t;
+
+ mipscale = 1.0 / (float)(1 << miplevel);
+
+ TransformVector (pface->texinfo->vecs[0], p_saxis);
+ TransformVector (pface->texinfo->vecs[1], p_taxis);
+
+ t = xscaleinv * mipscale;
+ d_sdivzstepu = p_saxis[0] * t;
+ d_tdivzstepu = p_taxis[0] * t;
+
+ t = yscaleinv * mipscale;
+ d_sdivzstepv = -p_saxis[1] * t;
+ d_tdivzstepv = -p_taxis[1] * t;
+
+ d_sdivzorigin = p_saxis[2] * mipscale - xcenter * d_sdivzstepu -
+ ycenter * d_sdivzstepv;
+ d_tdivzorigin = p_taxis[2] * mipscale - xcenter * d_tdivzstepu -
+ ycenter * d_tdivzstepv;
+
+ VectorScale (transformed_modelorg, mipscale, p_temp1);
+
+ t = 0x10000*mipscale;
+ sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) -
+ ((pface->texturemins[0] << 16) >> miplevel)
+ + pface->texinfo->vecs[0][3]*t;
+ tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) -
+ ((pface->texturemins[1] << 16) >> miplevel)
+ + pface->texinfo->vecs[1][3]*t;
+
+ // PGM - changing flow speed for non-warping textures.
+ if (pface->texinfo->flags & SURF_FLOWING)
+ {
+ if(pface->texinfo->flags & SURF_WARP)
+ sadjust += 0x10000 * (-128 * ( (r_newrefdef.time * 0.25) - (int)(r_newrefdef.time * 0.25) ));
+ else
+ sadjust += 0x10000 * (-128 * ( (r_newrefdef.time * 0.77) - (int)(r_newrefdef.time * 0.77) ));
+ }
+ // PGM
+
+//
+// -1 (-epsilon) so we never wander off the edge of the texture
+//
+ bbextents = ((pface->extents[0] << 16) >> miplevel) - 1;
+ bbextentt = ((pface->extents[1] << 16) >> miplevel) - 1;
+}
+
+
+/*
+==============
+D_BackgroundSurf
+
+The grey background filler seen when there is a hole in the map
+==============
+*/
+void D_BackgroundSurf (surf_t *s)
+{
+// set up a gradient for the background surface that places it
+// effectively at infinity distance from the viewpoint
+ d_zistepu = 0;
+ d_zistepv = 0;
+ d_ziorigin = -0.9;
+
+ D_FlatFillSurface (s, (int)sw_clearcolor->value & 0xFF);
+ D_DrawZSpans (s->spans);
+}
+
+/*
+=================
+D_TurbulentSurf
+=================
+*/
+void D_TurbulentSurf (surf_t *s)
+{
+ d_zistepu = s->d_zistepu;
+ d_zistepv = s->d_zistepv;
+ d_ziorigin = s->d_ziorigin;
+
+ pface = s->msurf;
+ miplevel = 0;
+ cacheblock = pface->texinfo->image->pixels[0];
+ cachewidth = 64;
+
+ if (s->insubmodel)
+ {
+ // FIXME: we don't want to do all this for every polygon!
+ // TODO: store once at start of frame
+ currententity = s->entity; //FIXME: make this passed in to
+ // R_RotateBmodel ()
+ VectorSubtract (r_origin, currententity->origin,
+ local_modelorg);
+ TransformVector (local_modelorg, transformed_modelorg);
+
+ R_RotateBmodel (); // FIXME: don't mess with the frustum,
+ // make entity passed in
+ }
+
+ D_CalcGradients (pface);
+
+//============
+//PGM
+ // textures that aren't warping are just flowing. Use NonTurbulent8 instead
+ if(!(pface->texinfo->flags & SURF_WARP))
+ NonTurbulent8 (s->spans);
+ else
+ Turbulent8 (s->spans);
+//PGM
+//============
+
+ D_DrawZSpans (s->spans);
+
+ if (s->insubmodel)
+ {
+ //
+ // restore the old drawing state
+ // FIXME: we don't want to do this every time!
+ // TODO: speed up
+ //
+ currententity = NULL; // &r_worldentity;
+ VectorCopy (world_transformed_modelorg,
+ transformed_modelorg);
+ VectorCopy (base_vpn, vpn);
+ VectorCopy (base_vup, vup);
+ VectorCopy (base_vright, vright);
+ R_TransformFrustum ();
+ }
+}
+
+/*
+==============
+D_SkySurf
+==============
+*/
+void D_SkySurf (surf_t *s)
+{
+ pface = s->msurf;
+ miplevel = 0;
+ if (!pface->texinfo->image)
+ return;
+ cacheblock = pface->texinfo->image->pixels[0];
+ cachewidth = 256;
+
+ d_zistepu = s->d_zistepu;
+ d_zistepv = s->d_zistepv;
+ d_ziorigin = s->d_ziorigin;
+
+ D_CalcGradients (pface);
+
+ D_DrawSpans16 (s->spans);
+
+// set up a gradient for the background surface that places it
+// effectively at infinity distance from the viewpoint
+ d_zistepu = 0;
+ d_zistepv = 0;
+ d_ziorigin = -0.9;
+
+ D_DrawZSpans (s->spans);
+}
+
+/*
+==============
+D_SolidSurf
+
+Normal surface cached, texture mapped surface
+==============
+*/
+void D_SolidSurf (surf_t *s)
+{
+ d_zistepu = s->d_zistepu;
+ d_zistepv = s->d_zistepv;
+ d_ziorigin = s->d_ziorigin;
+
+ if (s->insubmodel)
+ {
+ // FIXME: we don't want to do all this for every polygon!
+ // TODO: store once at start of frame
+ currententity = s->entity; //FIXME: make this passed in to
+ // R_RotateBmodel ()
+ VectorSubtract (r_origin, currententity->origin, local_modelorg);
+ TransformVector (local_modelorg, transformed_modelorg);
+
+ R_RotateBmodel (); // FIXME: don't mess with the frustum,
+ // make entity passed in
+ }
+ else
+ currententity = &r_worldentity;
+
+ pface = s->msurf;
+/* commented out in release
+ {
+ float dot;
+ float normal[3];
+
+ if ( s->insubmodel )
+ {
+ VectorCopy( pface->plane->normal, normal );
+// TransformVector( pface->plane->normal, normal);
+ dot = DotProduct( normal, vpn );
+ }
+ else
+ {
+ VectorCopy( pface->plane->normal, normal );
+ dot = DotProduct( normal, vpn );
+ }
+
+ if ( pface->flags & SURF_PLANEBACK )
+ dot = -dot;
+
+ if ( dot > 0 )
+ printf( "blah" );
+
+ miplevel = D_MipLevelForScale(s->nearzi * scale_for_mip * pface->texinfo->mipadjust);
+ }
+*/
+ miplevel = D_MipLevelForScale(s->nearzi * scale_for_mip * pface->texinfo->mipadjust);
+
+// FIXME: make this passed in to D_CacheSurface
+ pcurrentcache = D_CacheSurface (pface, miplevel);
+
+ cacheblock = (pixel_t *)pcurrentcache->data;
+ cachewidth = pcurrentcache->width;
+
+ D_CalcGradients (pface);
+
+ D_DrawSpans16 (s->spans);
+
+ D_DrawZSpans (s->spans);
+
+ if (s->insubmodel)
+ {
+ //
+ // restore the old drawing state
+ // FIXME: we don't want to do this every time!
+ // TODO: speed up
+ //
+ VectorCopy (world_transformed_modelorg,
+ transformed_modelorg);
+ VectorCopy (base_vpn, vpn);
+ VectorCopy (base_vup, vup);
+ VectorCopy (base_vright, vright);
+ R_TransformFrustum ();
+ currententity = NULL; //&r_worldentity;
+ }
+}
+
+/*
+=============
+D_DrawflatSurfaces
+
+To allow developers to see the polygon carving of the world
+=============
+*/
+void D_DrawflatSurfaces (void)
+{
+ surf_t *s;
+
+ for (s = &surfaces[1] ; s<surface_p ; s++)
+ {
+ if (!s->spans)
+ continue;
+
+ d_zistepu = s->d_zistepu;
+ d_zistepv = s->d_zistepv;
+ d_ziorigin = s->d_ziorigin;
+
+ // make a stable color for each surface by taking the low
+ // bits of the msurface pointer
+ D_FlatFillSurface (s, (uintptr)s->msurf & 0xFF);
+ D_DrawZSpans (s->spans);
+ }
+}
+
+/*
+==============
+D_DrawSurfaces
+
+Rasterize all the span lists. Guaranteed zero overdraw.
+May be called more than once a frame if the surf list overflows (higher res)
+==============
+*/
+void D_DrawSurfaces (void)
+{
+ surf_t *s;
+
+// currententity = NULL; //&r_worldentity;
+ VectorSubtract (r_origin, vec3_origin, modelorg);
+ TransformVector (modelorg, transformed_modelorg);
+ VectorCopy (transformed_modelorg, world_transformed_modelorg);
+
+ if (!sw_drawflat->value)
+ {
+ for (s = &surfaces[1] ; s<surface_p ; s++)
+ {
+ if (!s->spans)
+ continue;
+
+ r_drawnpolycount++;
+
+ if (! (s->flags & (SURF_DRAWSKYBOX|SURF_DRAWBACKGROUND|SURF_DRAWTURB) ) )
+ D_SolidSurf (s);
+ else if (s->flags & SURF_DRAWSKYBOX)
+ D_SkySurf (s);
+ else if (s->flags & SURF_DRAWBACKGROUND)
+ D_BackgroundSurf (s);
+ else if (s->flags & SURF_DRAWTURB)
+ D_TurbulentSurf (s);
+ }
+ }
+ else
+ D_DrawflatSurfaces ();
+
+ currententity = NULL; //&r_worldentity;
+ VectorSubtract (r_origin, vec3_origin, modelorg);
+ R_TransformFrustum ();
+}
+
--- /dev/null
+++ b/r_image.c
@@ -1,0 +1,581 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+
+#define MAX_RIMAGES 1024
+image_t r_images[MAX_RIMAGES];
+int numr_images;
+
+
+/*
+===============
+R_ImageList_f
+===============
+*/
+void R_ImageList_f (void)
+{
+ int i;
+ image_t *image;
+ int texels;
+
+ ri.Con_Printf (PRINT_ALL, "------------------\n");
+ texels = 0;
+
+ for (i=0, image=r_images ; i<numr_images ; i++, image++)
+ {
+ if (image->registration_sequence <= 0)
+ continue;
+ texels += image->width*image->height;
+ switch (image->type)
+ {
+ case it_skin:
+ ri.Con_Printf (PRINT_ALL, "M");
+ break;
+ case it_sprite:
+ ri.Con_Printf (PRINT_ALL, "S");
+ break;
+ case it_wall:
+ ri.Con_Printf (PRINT_ALL, "W");
+ break;
+ case it_pic:
+ ri.Con_Printf (PRINT_ALL, "P");
+ break;
+ default:
+ ri.Con_Printf (PRINT_ALL, " ");
+ break;
+ }
+
+ ri.Con_Printf (PRINT_ALL, " %3i %3i : %s\n",
+ image->width, image->height, image->name);
+ }
+ ri.Con_Printf (PRINT_ALL, "Total texel count: %i\n", texels);
+}
+
+
+/*
+=================================================================
+
+PCX LOADING
+
+=================================================================
+*/
+
+/*
+==============
+LoadPCX
+==============
+*/
+void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
+{
+ byte *raw;
+ pcx_t *pcx;
+ int x, y;
+ int len;
+ int dataByte, runLength;
+ byte *out, *pix;
+
+ *pic = NULL;
+
+ //
+ // load the file
+ //
+ len = ri.FS_LoadFile (filename, (void **)&raw);
+ if (!raw)
+ {
+ ri.Con_Printf (PRINT_DEVELOPER, "Bad pcx file %s\n", filename);
+ return;
+ }
+
+ //
+ // parse the PCX file
+ //
+ pcx = (pcx_t *)raw;
+
+ pcx->xmin = LittleShort(pcx->xmin);
+ pcx->ymin = LittleShort(pcx->ymin);
+ pcx->xmax = LittleShort(pcx->xmax);
+ pcx->ymax = LittleShort(pcx->ymax);
+ pcx->hres = LittleShort(pcx->hres);
+ pcx->vres = LittleShort(pcx->vres);
+ pcx->bytes_per_line = LittleShort(pcx->bytes_per_line);
+ pcx->palette_type = LittleShort(pcx->palette_type);
+
+ raw = &pcx->data;
+
+ if (pcx->manufacturer != 0x0a
+ || pcx->version != 5
+ || pcx->encoding != 1
+ || pcx->bits_per_pixel != 8
+ || pcx->xmax >= 640
+ || pcx->ymax >= 480)
+ {
+ ri.Con_Printf (PRINT_ALL, "Bad pcx file %s\n", filename);
+ return;
+ }
+
+ out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
+
+ *pic = out;
+
+ pix = out;
+
+ if (palette)
+ {
+ *palette = malloc(768);
+ memcpy (*palette, (byte *)pcx + len - 768, 768);
+ }
+
+ if (width)
+ *width = pcx->xmax+1;
+ if (height)
+ *height = pcx->ymax+1;
+
+ for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
+ {
+ for (x=0 ; x<=pcx->xmax ; )
+ {
+ dataByte = *raw++;
+
+ if((dataByte & 0xC0) == 0xC0)
+ {
+ runLength = dataByte & 0x3F;
+ dataByte = *raw++;
+ }
+ else
+ runLength = 1;
+
+ while(runLength-- > 0)
+ pix[x++] = dataByte;
+ }
+
+ }
+
+ if ( raw - (byte *)pcx > len)
+ {
+ ri.Con_Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename);
+ free (*pic);
+ *pic = NULL;
+ }
+
+ ri.FS_FreeFile (pcx);
+}
+
+/*
+=========================================================
+
+TARGA LOADING
+
+=========================================================
+*/
+
+typedef struct _TargaHeader {
+ unsigned char id_length, colormap_type, image_type;
+ unsigned short colormap_index, colormap_length;
+ unsigned char colormap_size;
+ unsigned short x_origin, y_origin, width, height;
+ unsigned char pixel_size, attributes;
+} TargaHeader;
+
+
+/*
+=============
+LoadTGA
+=============
+*/
+void LoadTGA (char *name, byte **pic, int *width, int *height)
+{
+ int columns, rows, numPixels;
+ byte *pixbuf;
+ int row, column;
+ byte *buf_p;
+ byte *buffer;
+ TargaHeader targa_header;
+ byte *targa_rgba;
+ uchar red = 0, green = 0, blue = 0, alphabyte = 0, packetHeader, packetSize, j;
+
+ *pic = NULL;
+
+ //
+ // load the file
+ //
+ ri.FS_LoadFile (name, (void **)&buffer); /* int length = */
+ if (!buffer)
+ {
+ ri.Con_Printf (PRINT_DEVELOPER, "Bad tga file %s\n", name);
+ return;
+ }
+
+ buf_p = buffer;
+
+ targa_header.id_length = *buf_p++;
+ targa_header.colormap_type = *buf_p++;
+ targa_header.image_type = *buf_p++;
+
+ targa_header.colormap_index = LittleShort ( *((short *)buf_p) );
+ buf_p+=2;
+ targa_header.colormap_length = LittleShort ( *((short *)buf_p) );
+ buf_p+=2;
+ targa_header.colormap_size = *buf_p++;
+ targa_header.x_origin = LittleShort ( *((short *)buf_p) );
+ buf_p+=2;
+ targa_header.y_origin = LittleShort ( *((short *)buf_p) );
+ buf_p+=2;
+ targa_header.width = LittleShort ( *((short *)buf_p) );
+ buf_p+=2;
+ targa_header.height = LittleShort ( *((short *)buf_p) );
+ buf_p+=2;
+ targa_header.pixel_size = *buf_p++;
+ targa_header.attributes = *buf_p++;
+
+ if (targa_header.image_type!=2
+ && targa_header.image_type!=10)
+ ri.Sys_Error (ERR_DROP, "LoadTGA: Only type 2 and 10 targa RGB images supported\n");
+
+ if (targa_header.colormap_type !=0
+ || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24))
+ ri.Sys_Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
+
+ columns = targa_header.width;
+ rows = targa_header.height;
+ numPixels = columns * rows;
+
+ if (width)
+ *width = columns;
+ if (height)
+ *height = rows;
+
+ targa_rgba = malloc (numPixels*4);
+ *pic = targa_rgba;
+
+ if (targa_header.id_length != 0)
+ buf_p += targa_header.id_length; // skip TARGA image comment
+
+ if (targa_header.image_type==2) { // Uncompressed, RGB images
+ for(row=rows-1; row>=0; row--) {
+ pixbuf = targa_rgba + row*columns*4;
+ for(column=0; column<columns; column++) {
+ switch (targa_header.pixel_size) {
+ case 24:
+
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ *pixbuf++ = red;
+ *pixbuf++ = green;
+ *pixbuf++ = blue;
+ *pixbuf++ = 255;
+ break;
+ case 32:
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ alphabyte = *buf_p++;
+ *pixbuf++ = red;
+ *pixbuf++ = green;
+ *pixbuf++ = blue;
+ *pixbuf++ = alphabyte;
+ break;
+ }
+ }
+ }
+ }
+ else if (targa_header.image_type==10) { // Runlength encoded RGB images
+ for(row=rows-1; row>=0; row--) {
+ pixbuf = targa_rgba + row*columns*4;
+ for(column=0; column<columns; ) {
+ packetHeader= *buf_p++;
+ packetSize = 1 + (packetHeader & 0x7f);
+ if (packetHeader & 0x80) { // run-length packet
+ switch (targa_header.pixel_size) {
+ case 24:
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ alphabyte = 255;
+ break;
+ case 32:
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ alphabyte = *buf_p++;
+ break;
+ }
+
+ for(j=0;j<packetSize;j++) {
+ *pixbuf++=red;
+ *pixbuf++=green;
+ *pixbuf++=blue;
+ *pixbuf++=alphabyte;
+ column++;
+ if (column==columns) { // run spans across rows
+ column=0;
+ if (row>0)
+ row--;
+ else
+ goto breakOut;
+ pixbuf = targa_rgba + row*columns*4;
+ }
+ }
+ }
+ else { // non run-length packet
+ for(j=0;j<packetSize;j++) {
+ switch (targa_header.pixel_size) {
+ case 24:
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ *pixbuf++ = red;
+ *pixbuf++ = green;
+ *pixbuf++ = blue;
+ *pixbuf++ = 255;
+ break;
+ case 32:
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ alphabyte = *buf_p++;
+ *pixbuf++ = red;
+ *pixbuf++ = green;
+ *pixbuf++ = blue;
+ *pixbuf++ = alphabyte;
+ break;
+ }
+ column++;
+ if (column==columns) { // pixel packet run spans across rows
+ column=0;
+ if (row>0)
+ row--;
+ else
+ goto breakOut;
+ pixbuf = targa_rgba + row*columns*4;
+ }
+ }
+ }
+ }
+ breakOut:;
+ }
+ }
+
+ ri.FS_FreeFile (buffer);
+}
+
+
+//=======================================================
+
+image_t *R_FindFreeImage (void)
+{
+ image_t *image;
+ int i;
+
+ // find a free image_t
+ for (i=0, image=r_images ; i<numr_images ; i++,image++)
+ {
+ if (!image->registration_sequence)
+ break;
+ }
+ if (i == numr_images)
+ {
+ if (numr_images == MAX_RIMAGES)
+ ri.Sys_Error (ERR_DROP, "MAX_RIMAGES");
+ numr_images++;
+ }
+ image = &r_images[i];
+
+ return image;
+}
+
+/*
+================
+GL_LoadPic
+
+================
+*/
+image_t *GL_LoadPic (char *name, byte *pic, int width, int height, imagetype_t type)
+{
+ image_t *image;
+ int i, c, b;
+
+ image = R_FindFreeImage ();
+ if (strlen(name) >= sizeof(image->name))
+ ri.Sys_Error (ERR_DROP, "Draw_LoadPic: \"%s\" is too long", name);
+ strcpy (image->name, name);
+ image->registration_sequence = registration_sequence;
+
+ image->width = width;
+ image->height = height;
+ image->type = type;
+
+ c = width*height;
+ image->pixels[0] = malloc (c);
+ image->transparent = false;
+ for (i=0 ; i<c ; i++)
+ {
+ b = pic[i];
+ if (b == 255)
+ image->transparent = true;
+ image->pixels[0][i] = b;
+ }
+
+ return image;
+}
+
+/*
+================
+R_LoadWal
+================
+*/
+image_t *R_LoadWal (char *name)
+{
+ miptex_t *mt;
+ int ofs;
+ image_t *image;
+ int size;
+
+ ri.FS_LoadFile (name, (void **)&mt);
+ if (!mt)
+ {
+ ri.Con_Printf (PRINT_ALL, "R_LoadWal: can't load %s\n", name);
+ return r_notexture_mip;
+ }
+
+ image = R_FindFreeImage ();
+ strcpy (image->name, name);
+ image->width = LittleLong (mt->width);
+ image->height = LittleLong (mt->height);
+ image->type = it_wall;
+ image->registration_sequence = registration_sequence;
+
+ size = image->width*image->height * (256+64+16+4)/256;
+ image->pixels[0] = malloc (size);
+ image->pixels[1] = image->pixels[0] + image->width*image->height;
+ image->pixels[2] = image->pixels[1] + image->width*image->height/4;
+ image->pixels[3] = image->pixels[2] + image->width*image->height/16;
+
+ ofs = LittleLong (mt->offsets[0]);
+ memcpy ( image->pixels[0], (byte *)mt + ofs, size);
+
+ ri.FS_FreeFile ((void *)mt);
+
+ return image;
+}
+
+
+/*
+===============
+R_FindImage
+
+Finds or loads the given image
+===============
+*/
+image_t *R_FindImage (char *name, imagetype_t type)
+{
+ image_t *image;
+ int i, len;
+ byte *pic, *palette;
+ int width, height;
+
+ if (!name)
+ return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: NULL name");
+ len = strlen(name);
+ if (len<5)
+ return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: bad name: %s", name);
+
+ // look for it
+ for (i=0, image=r_images ; i<numr_images ; i++,image++)
+ {
+ if (!strcmp(name, image->name))
+ {
+ image->registration_sequence = registration_sequence;
+ return image;
+ }
+ }
+
+ //
+ // load the pic from disk
+ //
+ pic = NULL;
+ palette = NULL;
+ if (!strcmp(name+len-4, ".pcx"))
+ {
+ LoadPCX (name, &pic, &palette, &width, &height);
+ if (!pic)
+ return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: can't load %s", name);
+ image = GL_LoadPic (name, pic, width, height, type);
+ }
+ else if (!strcmp(name+len-4, ".wal"))
+ {
+ image = R_LoadWal (name);
+ }
+ else if (!strcmp(name+len-4, ".tga"))
+ return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: can't load %s in software renderer", name);
+ else
+ return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: bad extension on: %s", name);
+
+ if (pic)
+ free(pic);
+ if (palette)
+ free(palette);
+
+ return image;
+}
+
+image_t *
+R_RegisterSkin(char *name)
+{
+ return R_FindImage(name, it_skin);
+}
+
+
+/*
+================
+R_FreeUnusedImages
+
+Any image that was not touched on this registration sequence
+will be freed.
+================
+*/
+void R_FreeUnusedImages (void)
+{
+ int i;
+ image_t *image;
+
+ for (i=0, image=r_images ; i<numr_images ; i++, image++)
+ {
+ if (image->registration_sequence == registration_sequence)
+ {
+ Com_PageInMemory ((byte *)image->pixels[0], image->width*image->height);
+ continue; // used this sequence
+ }
+ if (!image->registration_sequence)
+ continue; // free texture
+ if (image->type == it_pic)
+ continue; // don't free pics
+ // free it
+ free (image->pixels[0]); // the other mip levels just follow
+ memset (image, 0, sizeof(*image));
+ }
+}
+
+void
+R_InitImages(void)
+{
+ registration_sequence = 1;
+}
+
+void
+R_ShutdownImages(void)
+{
+ int i;
+ image_t *image;
+
+ for(i=0, image=r_images; i<numr_images; i++, image++){
+ if(!image->registration_sequence)
+ continue; // free texture
+ // free it
+ free(image->pixels[0]); // the other mip levels just follow
+ memset(image, 0, sizeof *image);
+ }
+}
--- /dev/null
+++ b/r_light.c
@@ -1,0 +1,423 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+int r_dlightframecount;
+
+
+/*
+=============================================================================
+
+DYNAMIC LIGHTS
+
+=============================================================================
+*/
+
+/*
+=============
+R_MarkLights
+=============
+*/
+void R_MarkLights (dlight_t *light, int bit, mnode_t *node)
+{
+ mplane_t *splitplane;
+ float dist;
+ msurface_t *surf;
+ int i;
+
+ if (node->contents != -1)
+ return;
+
+ splitplane = node->plane;
+ dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist;
+
+//=====
+//PGM
+ i=light->intensity;
+ if(i<0)
+ i=-i;
+//PGM
+//=====
+
+ if (dist > i) // PGM (dist > light->intensity)
+ {
+ R_MarkLights (light, bit, node->children[0]);
+ return;
+ }
+ if (dist < -i) // PGM (dist < -light->intensity)
+ {
+ R_MarkLights (light, bit, node->children[1]);
+ return;
+ }
+
+// mark the polygons
+ surf = r_worldmodel->surfaces + node->firstsurface;
+ for (i=0 ; i<node->numsurfaces ; i++, surf++)
+ {
+ if (surf->dlightframe != r_dlightframecount)
+ {
+ surf->dlightbits = 0;
+ surf->dlightframe = r_dlightframecount;
+ }
+ surf->dlightbits |= bit;
+ }
+
+ R_MarkLights (light, bit, node->children[0]);
+ R_MarkLights (light, bit, node->children[1]);
+}
+
+
+/*
+=============
+R_PushDlights
+=============
+*/
+void R_PushDlights (model_t *model)
+{
+ int i;
+ dlight_t *l;
+
+ r_dlightframecount = r_framecount;
+ for (i=0, l = r_newrefdef.dlights ; i<r_newrefdef.num_dlights ; i++, l++)
+ {
+ R_MarkLights ( l, 1<<i,
+ model->nodes + model->firstnode);
+ }
+}
+
+
+/*
+=============================================================================
+
+LIGHT SAMPLING
+
+=============================================================================
+*/
+
+vec3_t pointcolor;
+mplane_t *lightplane; // used as shadow plane
+vec3_t lightspot;
+
+int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end)
+{
+ float front, back, frac;
+ int side;
+ mplane_t *plane;
+ vec3_t mid;
+ msurface_t *surf;
+ int s, t, ds, dt;
+ int i;
+ mtexinfo_t *tex;
+ byte *lightmap;
+ float *scales;
+ int maps;
+ float samp;
+ int r;
+
+ if (node->contents != -1)
+ return -1; // didn't hit anything
+
+// calculate mid point
+
+// FIXME: optimize for axial
+ plane = node->plane;
+ front = DotProduct (start, plane->normal) - plane->dist;
+ back = DotProduct (end, plane->normal) - plane->dist;
+ side = front < 0;
+
+ if ( (back < 0) == side)
+ return RecursiveLightPoint (node->children[side], start, end);
+
+ frac = front / (front-back);
+ mid[0] = start[0] + (end[0] - start[0])*frac;
+ mid[1] = start[1] + (end[1] - start[1])*frac;
+ mid[2] = start[2] + (end[2] - start[2])*frac;
+ if (plane->type < 3) // axial planes
+ mid[plane->type] = plane->dist;
+
+// go down front side
+ r = RecursiveLightPoint (node->children[side], start, mid);
+ if (r >= 0)
+ return r; // hit something
+
+ if ( (back < 0) == side )
+ return -1; // didn't hit anuthing
+
+// check for impact on this node
+ VectorCopy (mid, lightspot);
+ lightplane = plane;
+
+ surf = r_worldmodel->surfaces + node->firstsurface;
+ for (i=0 ; i<node->numsurfaces ; i++, surf++)
+ {
+ if (surf->flags&(SURF_DRAWTURB|SURF_DRAWSKY))
+ continue; // no lightmaps
+
+ tex = surf->texinfo;
+
+ s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3];
+ t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3];
+ if (s < surf->texturemins[0] ||
+ t < surf->texturemins[1])
+ continue;
+
+ ds = s - surf->texturemins[0];
+ dt = t - surf->texturemins[1];
+
+ if ( ds > surf->extents[0] || dt > surf->extents[1] )
+ continue;
+
+ if (!surf->samples)
+ return 0;
+
+ ds >>= 4;
+ dt >>= 4;
+
+ lightmap = surf->samples;
+ VectorCopy (vec3_origin, pointcolor);
+ if (lightmap)
+ {
+ lightmap += dt * ((surf->extents[0]>>4)+1) + ds;
+
+ for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
+ maps++)
+ {
+ samp = *lightmap * /* 0.5 * */ (1.0/255); // adjust for gl scale
+ scales = r_newrefdef.lightstyles[surf->styles[maps]].rgb;
+ VectorMA (pointcolor, samp, scales, pointcolor);
+ lightmap += ((surf->extents[0]>>4)+1) *
+ ((surf->extents[1]>>4)+1);
+ }
+ }
+
+ return 1;
+ }
+
+// go down back side
+ return RecursiveLightPoint (node->children[!side], mid, end);
+}
+
+/*
+===============
+R_LightPoint
+===============
+*/
+void R_LightPoint (vec3_t p, vec3_t color)
+{
+ vec3_t end;
+ float r;
+ int lnum;
+ dlight_t *dl;
+ vec3_t dist;
+ float add;
+
+ if (!r_worldmodel->lightdata)
+ {
+ color[0] = color[1] = color[2] = 1.0;
+ return;
+ }
+
+ end[0] = p[0];
+ end[1] = p[1];
+ end[2] = p[2] - 2048;
+
+ r = RecursiveLightPoint (r_worldmodel->nodes, p, end);
+
+ if (r == -1)
+ {
+ VectorCopy (vec3_origin, color);
+ }
+ else
+ {
+ VectorCopy (pointcolor, color);
+ }
+
+ //
+ // add dynamic lights
+ //
+ for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++)
+ {
+ dl = &r_newrefdef.dlights[lnum];
+ VectorSubtract (currententity->origin,
+ dl->origin,
+ dist);
+ add = dl->intensity - VectorLength(dist);
+ add *= (1.0/256);
+ if (add > 0)
+ {
+ VectorMA (color, add, dl->color, color);
+ }
+ }
+}
+
+//===================================================================
+
+
+unsigned blocklights[1024]; // allow some very large lightmaps
+
+/*
+===============
+R_AddDynamicLights
+===============
+*/
+void R_AddDynamicLights (void)
+{
+ msurface_t *surf;
+ int lnum;
+ int sd, td;
+ float dist, rad, minlight;
+ vec3_t impact, local;
+ int s, t;
+ int i;
+ int smax, tmax;
+ mtexinfo_t *tex;
+ dlight_t *dl;
+ int negativeLight; //PGM
+
+ surf = r_drawsurf.surf;
+ smax = (surf->extents[0]>>4)+1;
+ tmax = (surf->extents[1]>>4)+1;
+ tex = surf->texinfo;
+
+ for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++)
+ {
+ if ( !(surf->dlightbits & (1<<lnum) ) )
+ continue; // not lit by this light
+
+ dl = &r_newrefdef.dlights[lnum];
+ rad = dl->intensity;
+
+//=====
+//PGM
+ negativeLight = 0;
+ if(rad < 0)
+ {
+ negativeLight = 1;
+ rad = -rad;
+ }
+//PGM
+//=====
+
+ dist = DotProduct (dl->origin, surf->plane->normal) -
+ surf->plane->dist;
+ rad -= fabs(dist);
+ minlight = 32; // dl->minlight;
+ if (rad < minlight)
+ continue;
+ minlight = rad - minlight;
+
+ for (i=0 ; i<3 ; i++)
+ {
+ impact[i] = dl->origin[i] -
+ surf->plane->normal[i]*dist;
+ }
+
+ local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3];
+ local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3];
+
+ local[0] -= surf->texturemins[0];
+ local[1] -= surf->texturemins[1];
+
+ for (t = 0 ; t<tmax ; t++)
+ {
+ td = local[1] - t*16;
+ if (td < 0)
+ td = -td;
+ for (s=0 ; s<smax ; s++)
+ {
+ sd = local[0] - s*16;
+ if (sd < 0)
+ sd = -sd;
+ if (sd > td)
+ dist = sd + (td>>1);
+ else
+ dist = td + (sd>>1);
+//====
+//PGM
+ if(!negativeLight)
+ {
+ if (dist < minlight)
+ blocklights[t*smax + s] += (rad - dist)*256;
+ }
+ else
+ {
+ if (dist < minlight)
+ blocklights[t*smax + s] -= (rad - dist)*256;
+ if(blocklights[t*smax + s] < minlight)
+ blocklights[t*smax + s] = minlight;
+ }
+//PGM
+//====
+ }
+ }
+ }
+}
+
+/*
+===============
+R_BuildLightMap
+
+Combine and scale multiple lightmaps into the 8.8 format in blocklights
+===============
+*/
+void R_BuildLightMap (void)
+{
+ int smax, tmax;
+ int t;
+ int i, size;
+ byte *lightmap;
+ unsigned scale;
+ int maps;
+ msurface_t *surf;
+
+ surf = r_drawsurf.surf;
+
+ smax = (surf->extents[0]>>4)+1;
+ tmax = (surf->extents[1]>>4)+1;
+ size = smax*tmax;
+
+ if (r_fullbright->value || !r_worldmodel->lightdata)
+ {
+ for (i=0 ; i<size ; i++)
+ blocklights[i] = 0;
+ return;
+ }
+
+// clear to no light
+ for (i=0 ; i<size ; i++)
+ blocklights[i] = 0;
+
+
+// add all the lightmaps
+ lightmap = surf->samples;
+ if (lightmap)
+ for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
+ maps++)
+ {
+ scale = r_drawsurf.lightadj[maps]; // 8.8 fraction
+ for (i=0 ; i<size ; i++)
+ blocklights[i] += lightmap[i] * scale;
+ lightmap += size; // skip to next lightmap
+ }
+
+// add all the dynamic lights
+ if (surf->dlightframe == r_framecount)
+ R_AddDynamicLights ();
+
+// bound, invert, and shift
+ for (i=0 ; i<size ; i++)
+ {
+ t = (int)blocklights[i];
+ if (t < 0)
+ t = 0;
+ t = (255*256 - t) >> (8 - VID_CBITS);
+
+ if (t < (1 << 6))
+ t = (1 << 6);
+
+ blocklights[i] = t;
+ }
+}
+
--- /dev/null
+++ b/r_main.c
@@ -1,0 +1,1350 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+viddef_t vid;
+refimport_t ri;
+
+unsigned d_8to24table[256];
+
+entity_t r_worldentity;
+
+char skyname[MAX_QPATH];
+float skyrotate;
+vec3_t skyaxis;
+image_t *sky_images[6];
+
+refdef_t r_newrefdef;
+model_t *currentmodel;
+
+model_t *r_worldmodel;
+
+byte r_warpbuffer[WARP_WIDTH * WARP_HEIGHT];
+
+swstate_t sw_state;
+
+void *colormap;
+vec3_t viewlightvec;
+alight_t r_viewlighting = {128, 192, viewlightvec};
+float r_time1;
+int r_numallocatededges;
+float r_aliasuvscale = 1.0;
+int r_outofsurfaces;
+int r_outofedges;
+
+qboolean r_dowarp;
+
+mvertex_t *r_pcurrentvertbase;
+
+int c_surf;
+int r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs;
+qboolean r_surfsonstack;
+int r_clipflags;
+
+//
+// view origin
+//
+vec3_t vup, base_vup;
+vec3_t vpn, base_vpn;
+vec3_t vright, base_vright;
+vec3_t r_origin;
+
+//
+// screen size info
+//
+oldrefdef_t r_refdef;
+float xcenter, ycenter;
+float xscale, yscale;
+float xscaleinv, yscaleinv;
+float xscaleshrink, yscaleshrink;
+float aliasxscale, aliasyscale, aliasxcenter, aliasycenter;
+
+int r_screenwidth;
+
+float verticalFieldOfView;
+float xOrigin, yOrigin;
+
+mplane_t screenedge[4];
+
+//
+// refresh flags
+//
+int r_framecount = 1; // so frame counts initialized to 0 don't match
+int r_visframecount;
+int d_spanpixcount;
+int r_polycount;
+int r_drawnpolycount;
+int r_wholepolycount;
+
+int *pfrustum_indexes[4];
+int r_frustum_indexes[4*6];
+
+mleaf_t *r_viewleaf;
+int r_viewcluster, r_oldviewcluster;
+
+image_t *r_notexture_mip;
+
+float da_time1, da_time2, dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;
+float se_time1, se_time2, de_time1, de_time2;
+
+void R_MarkLeaves (void);
+
+cvar_t *r_lefthand;
+cvar_t *sw_aliasstats;
+cvar_t *sw_allow_modex;
+cvar_t *sw_clearcolor;
+cvar_t *sw_drawflat;
+cvar_t *sw_draworder;
+cvar_t *sw_maxedges;
+cvar_t *sw_maxsurfs;
+cvar_t *sw_mode;
+cvar_t *sw_reportedgeout;
+cvar_t *sw_reportsurfout;
+cvar_t *sw_stipplealpha;
+cvar_t *sw_surfcacheoverride;
+cvar_t *sw_waterwarp;
+
+cvar_t *r_drawworld;
+cvar_t *r_drawentities;
+cvar_t *r_dspeeds;
+cvar_t *r_fullbright;
+cvar_t *r_lerpmodels;
+cvar_t *r_novis;
+
+cvar_t *r_speeds;
+cvar_t *r_lightlevel; //FIXME HACK
+
+cvar_t *vid_fullscreen;
+cvar_t *vid_gamma;
+
+//PGM
+cvar_t *sw_lockpvs;
+//PGM
+
+#define STRINGER(x) "x"
+
+
+// r_vars.c
+
+// all global and static refresh variables are collected in a contiguous block
+// to avoid cache conflicts.
+
+//-------------------------------------------------------
+// global refresh variables
+//-------------------------------------------------------
+
+// FIXME: make into one big structure, like cl or sv
+// FIXME: do separately for refresh engine and driver
+
+
+// d_vars.c
+
+// all global and static refresh variables are collected in a contiguous block
+// to avoid cache conflicts.
+
+//-------------------------------------------------------
+// global refresh variables
+//-------------------------------------------------------
+
+// FIXME: make into one big structure, like cl or sv
+// FIXME: do separately for refresh engine and driver
+
+float d_sdivzstepu, d_tdivzstepu, d_zistepu;
+float d_sdivzstepv, d_tdivzstepv, d_zistepv;
+float d_sdivzorigin, d_tdivzorigin, d_ziorigin;
+
+fixed16_t sadjust, tadjust, bbextents, bbextentt;
+
+pixel_t *cacheblock;
+int cachewidth;
+pixel_t *d_viewbuffer;
+short *d_pzbuffer;
+unsigned int d_zrowbytes;
+unsigned int d_zwidth;
+
+
+byte r_notexture_buffer[1024];
+
+/*
+==================
+R_InitTextures
+==================
+*/
+void R_InitTextures (void)
+{
+ int x,y, m;
+ byte *dest;
+
+// create a simple checkerboard texture for the default
+ r_notexture_mip = (image_t *)r_notexture_buffer;
+
+ r_notexture_mip->width = r_notexture_mip->height = 16;
+ r_notexture_mip->pixels[0] = &r_notexture_buffer[sizeof(image_t)];
+ r_notexture_mip->pixels[1] = r_notexture_mip->pixels[0] + 16*16;
+ r_notexture_mip->pixels[2] = r_notexture_mip->pixels[1] + 8*8;
+ r_notexture_mip->pixels[3] = r_notexture_mip->pixels[2] + 4*4;
+
+ for (m=0 ; m<4 ; m++)
+ {
+ dest = r_notexture_mip->pixels[m];
+ for (y=0 ; y< (16>>m) ; y++)
+ for (x=0 ; x< (16>>m) ; x++)
+ {
+ if ( (y< (8>>m) ) ^ (x< (8>>m) ) )
+
+ *dest++ = 0;
+ else
+ *dest++ = 0xff;
+ }
+ }
+}
+
+
+/*
+================
+R_InitTurb
+================
+*/
+void R_InitTurb (void)
+{
+ int i;
+
+ for (i=0 ; i<1280 ; i++)
+ {
+ sintable[i] = AMP + sin(i*3.14159*2/CYCLE)*AMP;
+ intsintable[i] = AMP2 + sin(i*3.14159*2/CYCLE)*AMP2; // AMP2, not 20
+ blanktable[i] = 0; //PGM
+ }
+}
+
+void R_ImageList_f( void );
+
+void R_Register (void)
+{
+ sw_aliasstats = Cvar_Get("sw_polymodelstats", "0", 0);
+ sw_allow_modex = Cvar_Get("sw_allow_modex", "1", CVAR_ARCHIVE);
+ sw_clearcolor = Cvar_Get("sw_clearcolor", "2", 0);
+ sw_drawflat = Cvar_Get("sw_drawflat", "0", 0);
+ sw_draworder = Cvar_Get("sw_draworder", "0", 0);
+ sw_maxedges = Cvar_Get("sw_maxedges", STRINGER(MAXSTACKSURFACES), 0);
+ sw_maxsurfs = Cvar_Get("sw_maxsurfs", "0", 0);
+ sw_mipcap = Cvar_Get("sw_mipcap", "0", 0);
+ sw_mipscale = Cvar_Get("sw_mipscale", "1", 0);
+ sw_reportedgeout = Cvar_Get("sw_reportedgeout", "0", 0);
+ sw_reportsurfout = Cvar_Get("sw_reportsurfout", "0", 0);
+ sw_stipplealpha = Cvar_Get("sw_stipplealpha", "0", CVAR_ARCHIVE);
+ sw_surfcacheoverride = Cvar_Get("sw_surfcacheoverride", "0", 0);
+ sw_waterwarp = Cvar_Get ("sw_waterwarp", "1", 0);
+ sw_mode = Cvar_Get("sw_mode", "0", CVAR_ARCHIVE);
+
+ r_lefthand = Cvar_Get("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE);
+ r_speeds = Cvar_Get("r_speeds", "0", 0);
+ r_fullbright = Cvar_Get("r_fullbright", "0", 0);
+ r_drawentities = Cvar_Get("r_drawentities", "1", 0);
+ r_drawworld = Cvar_Get("r_drawworld", "1", 0);
+ r_dspeeds = Cvar_Get("r_dspeeds", "0", 0);
+ r_lightlevel = Cvar_Get("r_lightlevel", "0", 0);
+ r_lerpmodels = Cvar_Get("r_lerpmodels", "1", 0);
+ r_novis = Cvar_Get("r_novis", "0", 0);
+
+ vid_fullscreen = Cvar_Get("vid_fullscreen", "0", CVAR_ARCHIVE);
+ vid_gamma = Cvar_Get("vid_gamma", "1", CVAR_ARCHIVE);
+
+ Cmd_AddCommand("modellist", Mod_Modellist_f);
+ Cmd_AddCommand("screenshot", R_ScreenShot_f);
+ Cmd_AddCommand("imagelist", R_ImageList_f);
+
+ sw_mode->modified = true; // force us to do mode specific stuff later
+ vid_gamma->modified = true; // force us to rebuild the gamma table later
+
+//PGM
+ sw_lockpvs = ri.Cvar_Get ("sw_lockpvs", "0", 0);
+//PGM
+}
+
+void
+R_UnRegister(void)
+{
+ Cmd_RemoveCommand("screenshot");
+ Cmd_RemoveCommand("modellist");
+ Cmd_RemoveCommand("imagelist");
+}
+
+/*
+===============
+R_Init
+===============
+*/
+qboolean R_Init( void *hInstance, void *wndProc )
+{
+ R_InitImages ();
+ Mod_Init ();
+ Draw_InitLocal ();
+ R_InitTextures ();
+
+ R_InitTurb ();
+
+ view_clipplanes[0].leftedge = true;
+ view_clipplanes[1].rightedge = true;
+ view_clipplanes[1].leftedge = view_clipplanes[2].leftedge =
+ view_clipplanes[3].leftedge = false;
+ view_clipplanes[0].rightedge = view_clipplanes[2].rightedge =
+ view_clipplanes[3].rightedge = false;
+
+ r_refdef.xOrigin = XCENTERING;
+ r_refdef.yOrigin = YCENTERING;
+
+ r_aliasuvscale = 1.0;
+
+ R_Register ();
+ Draw_GetPalette ();
+ SWimp_Init( hInstance, wndProc );
+
+ // create the window
+ R_BeginFrame( 0 );
+
+ ri.Con_Printf (PRINT_ALL, "ref_soft version: "REF_VERSION"\n");
+
+ return true;
+}
+
+void
+R_Shutdown(void)
+{
+ if(d_pzbuffer){
+ free(d_pzbuffer);
+ d_pzbuffer = nil;
+ }
+ if(sc_base){
+ D_FlushCaches();
+ free(sc_base);
+ sc_base = nil;
+ }
+ if(vid.colormap){
+ free(vid.colormap);
+ vid.colormap = nil;
+ }
+ R_UnRegister();
+ Mod_FreeAll();
+ R_ShutdownImages();
+
+ SWimp_Shutdown();
+}
+
+/*
+===============
+R_NewMap
+===============
+*/
+void R_NewMap (void)
+{
+ r_viewcluster = -1;
+
+ r_cnumsurfs = sw_maxsurfs->value;
+
+ if (r_cnumsurfs <= MINSURFACES)
+ r_cnumsurfs = MINSURFACES;
+
+ if (r_cnumsurfs > NUMSTACKSURFACES)
+ {
+ surfaces = malloc (r_cnumsurfs * sizeof(surf_t));
+ surface_p = surfaces;
+ surf_max = &surfaces[r_cnumsurfs];
+ r_surfsonstack = false;
+ // surface 0 doesn't really exist; it's just a dummy because index 0
+ // is used to indicate no edge attached to surface
+ surfaces--;
+ R_SurfacePatch ();
+ }
+ else
+ {
+ r_surfsonstack = true;
+ }
+
+ r_maxedgesseen = 0;
+ r_maxsurfsseen = 0;
+
+ r_numallocatededges = sw_maxedges->value;
+
+ if (r_numallocatededges < MINEDGES)
+ r_numallocatededges = MINEDGES;
+
+ if (r_numallocatededges <= NUMSTACKEDGES)
+ {
+ auxedges = NULL;
+ }
+ else
+ {
+ auxedges = malloc (r_numallocatededges * sizeof(edge_t));
+ }
+}
+
+
+/*
+===============
+R_MarkLeaves
+
+Mark the leaves and nodes that are in the PVS for the current
+cluster
+===============
+*/
+void R_MarkLeaves (void)
+{
+ byte *vis;
+ mnode_t *node;
+ int i;
+ mleaf_t *leaf;
+ int cluster;
+
+ if (r_oldviewcluster == r_viewcluster && !r_novis->value && r_viewcluster != -1)
+ return;
+
+ // development aid to let you run around and see exactly where
+ // the pvs ends
+ if (sw_lockpvs->value)
+ return;
+
+ r_visframecount++;
+ r_oldviewcluster = r_viewcluster;
+
+ if (r_novis->value || r_viewcluster == -1 || !r_worldmodel->vis)
+ {
+ // mark everything
+ for (i=0 ; i<r_worldmodel->numleafs ; i++)
+ r_worldmodel->leafs[i].visframe = r_visframecount;
+ for (i=0 ; i<r_worldmodel->numnodes ; i++)
+ r_worldmodel->nodes[i].visframe = r_visframecount;
+ return;
+ }
+
+ vis = Mod_ClusterPVS (r_viewcluster, r_worldmodel);
+
+ for (i=0,leaf=r_worldmodel->leafs ; i<r_worldmodel->numleafs ; i++, leaf++)
+ {
+ cluster = leaf->cluster;
+ if (cluster == -1)
+ continue;
+ if (vis[cluster>>3] & (1<<(cluster&7)))
+ {
+ node = (mnode_t *)leaf;
+ do
+ {
+ if (node->visframe == r_visframecount)
+ break;
+ node->visframe = r_visframecount;
+ node = node->parent;
+ } while (node);
+ }
+ }
+
+/*
+ for (i=0 ; i<r_worldmodel->vis->numclusters ; i++)
+ {
+ if (vis[i>>3] & (1<<(i&7)))
+ {
+ node = (mnode_t *)&r_worldmodel->leafs[i]; // FIXME: cluster
+ do
+ {
+ if (node->visframe == r_visframecount)
+ break;
+ node->visframe = r_visframecount;
+ node = node->parent;
+ } while (node);
+ }
+ }
+*/
+}
+
+/*
+** R_DrawNullModel
+**
+** IMPLEMENT THIS!
+*/
+void R_DrawNullModel( void )
+{
+}
+
+/*
+=============
+R_DrawEntitiesOnList
+=============
+*/
+void R_DrawEntitiesOnList (void)
+{
+ int i;
+ qboolean translucent_entities = false;
+
+ if (!r_drawentities->value)
+ return;
+
+ // all bmodels have already been drawn by the edge list
+ for (i=0 ; i<r_newrefdef.num_entities ; i++)
+ {
+ currententity = &r_newrefdef.entities[i];
+
+ if ( currententity->flags & RF_TRANSLUCENT )
+ {
+ translucent_entities = true;
+ continue;
+ }
+
+ if ( currententity->flags & RF_BEAM )
+ {
+ modelorg[0] = -r_origin[0];
+ modelorg[1] = -r_origin[1];
+ modelorg[2] = -r_origin[2];
+ VectorCopy( vec3_origin, r_entorigin );
+ R_DrawBeam( currententity );
+ }
+ else
+ {
+ currentmodel = currententity->model;
+ if (!currentmodel)
+ {
+ R_DrawNullModel();
+ continue;
+ }
+ VectorCopy (currententity->origin, r_entorigin);
+ VectorSubtract (r_origin, r_entorigin, modelorg);
+
+ switch (currentmodel->type)
+ {
+ case mod_sprite:
+ R_DrawSprite ();
+ break;
+
+ case mod_alias:
+ R_AliasDrawModel ();
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ if ( !translucent_entities )
+ return;
+
+ for (i=0 ; i<r_newrefdef.num_entities ; i++)
+ {
+ currententity = &r_newrefdef.entities[i];
+
+ if ( !( currententity->flags & RF_TRANSLUCENT ) )
+ continue;
+
+ if ( currententity->flags & RF_BEAM )
+ {
+ modelorg[0] = -r_origin[0];
+ modelorg[1] = -r_origin[1];
+ modelorg[2] = -r_origin[2];
+ VectorCopy( vec3_origin, r_entorigin );
+ R_DrawBeam( currententity );
+ }
+ else
+ {
+ currentmodel = currententity->model;
+ if (!currentmodel)
+ {
+ R_DrawNullModel();
+ continue;
+ }
+ VectorCopy (currententity->origin, r_entorigin);
+ VectorSubtract (r_origin, r_entorigin, modelorg);
+
+ switch (currentmodel->type)
+ {
+ case mod_sprite:
+ R_DrawSprite ();
+ break;
+
+ case mod_alias:
+ R_AliasDrawModel ();
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+}
+
+
+/*
+=============
+R_BmodelCheckBBox
+=============
+*/
+int R_BmodelCheckBBox (float *minmaxs)
+{
+ int i, *pindex, clipflags;
+ vec3_t acceptpt, rejectpt;
+ float d;
+
+ clipflags = 0;
+
+ for (i=0 ; i<4 ; i++)
+ {
+ // generate accept and reject points
+ // FIXME: do with fast look-ups or integer tests based on the sign bit
+ // of the floating point values
+
+ pindex = pfrustum_indexes[i];
+
+ rejectpt[0] = minmaxs[pindex[0]];
+ rejectpt[1] = minmaxs[pindex[1]];
+ rejectpt[2] = minmaxs[pindex[2]];
+
+ d = DotProduct (rejectpt, view_clipplanes[i].normal);
+ d -= view_clipplanes[i].dist;
+
+ if (d <= 0)
+ return BMODEL_FULLY_CLIPPED;
+
+ acceptpt[0] = minmaxs[pindex[3+0]];
+ acceptpt[1] = minmaxs[pindex[3+1]];
+ acceptpt[2] = minmaxs[pindex[3+2]];
+
+ d = DotProduct (acceptpt, view_clipplanes[i].normal);
+ d -= view_clipplanes[i].dist;
+
+ if (d <= 0)
+ clipflags |= (1<<i);
+ }
+
+ return clipflags;
+}
+
+
+/*
+===================
+R_FindTopnode
+
+Find the first node that splits the given box
+===================
+*/
+mnode_t *R_FindTopnode (vec3_t mins, vec3_t maxs)
+{
+ mplane_t *splitplane;
+ int sides;
+ mnode_t *node;
+
+ node = r_worldmodel->nodes;
+
+ while (1)
+ {
+ if (node->visframe != r_visframecount)
+ return NULL; // not visible at all
+
+ if (node->contents != CONTENTS_NODE)
+ {
+ if (node->contents != CONTENTS_SOLID)
+ return node; // we've reached a non-solid leaf, so it's
+ // visible and not BSP clipped
+ return NULL; // in solid, so not visible
+ }
+
+ splitplane = node->plane;
+ sides = BOX_ON_PLANE_SIDE(mins, maxs, (cplane_t *)splitplane);
+
+ if (sides == 3)
+ return node; // this is the splitter
+
+ // not split yet; recurse down the contacted side
+ if (sides & 1)
+ node = node->children[0];
+ else
+ node = node->children[1];
+ }
+}
+
+
+/*
+=============
+RotatedBBox
+
+Returns an axially aligned box that contains the input box at the given rotation
+=============
+*/
+void RotatedBBox (vec3_t mins, vec3_t maxs, vec3_t angles, vec3_t tmins, vec3_t tmaxs)
+{
+ vec3_t tmp, v;
+ int i, j;
+ vec3_t forward, right, up;
+
+ if (!angles[0] && !angles[1] && !angles[2])
+ {
+ VectorCopy (mins, tmins);
+ VectorCopy (maxs, tmaxs);
+ return;
+ }
+
+ for (i=0 ; i<3 ; i++)
+ {
+ tmins[i] = 99999;
+ tmaxs[i] = -99999;
+ }
+
+ AngleVectors (angles, forward, right, up);
+
+ for ( i = 0; i < 8; i++ )
+ {
+ if ( i & 1 )
+ tmp[0] = mins[0];
+ else
+ tmp[0] = maxs[0];
+
+ if ( i & 2 )
+ tmp[1] = mins[1];
+ else
+ tmp[1] = maxs[1];
+
+ if ( i & 4 )
+ tmp[2] = mins[2];
+ else
+ tmp[2] = maxs[2];
+
+
+ VectorScale (forward, tmp[0], v);
+ VectorMA (v, -tmp[1], right, v);
+ VectorMA (v, tmp[2], up, v);
+
+ for (j=0 ; j<3 ; j++)
+ {
+ if (v[j] < tmins[j])
+ tmins[j] = v[j];
+ if (v[j] > tmaxs[j])
+ tmaxs[j] = v[j];
+ }
+ }
+}
+
+/*
+=============
+R_DrawBEntitiesOnList
+=============
+*/
+void R_DrawBEntitiesOnList (void)
+{
+ int i, clipflags;
+ vec3_t oldorigin;
+ vec3_t mins, maxs;
+ float minmaxs[6];
+ mnode_t *topnode;
+
+ if (!r_drawentities->value)
+ return;
+
+ VectorCopy (modelorg, oldorigin);
+ insubmodel = true;
+ r_dlightframecount = r_framecount;
+
+ for (i=0 ; i<r_newrefdef.num_entities ; i++)
+ {
+ currententity = &r_newrefdef.entities[i];
+ currentmodel = currententity->model;
+ if (!currentmodel)
+ continue;
+ if (currentmodel->nummodelsurfaces == 0)
+ continue; // clip brush only
+ if ( currententity->flags & RF_BEAM )
+ continue;
+ if (currentmodel->type != mod_brush)
+ continue;
+ // see if the bounding box lets us trivially reject, also sets
+ // trivial accept status
+ RotatedBBox (currentmodel->mins, currentmodel->maxs,
+ currententity->angles, mins, maxs);
+ VectorAdd (mins, currententity->origin, minmaxs);
+ VectorAdd (maxs, currententity->origin, (minmaxs+3));
+
+ clipflags = R_BmodelCheckBBox (minmaxs);
+ if (clipflags == BMODEL_FULLY_CLIPPED)
+ continue; // off the edge of the screen
+
+ topnode = R_FindTopnode (minmaxs, minmaxs+3);
+ if (!topnode)
+ continue; // no part in a visible leaf
+
+ VectorCopy (currententity->origin, r_entorigin);
+ VectorSubtract (r_origin, r_entorigin, modelorg);
+
+ r_pcurrentvertbase = currentmodel->vertexes;
+
+ // FIXME: stop transforming twice
+ R_RotateBmodel ();
+
+ // calculate dynamic lighting for bmodel
+ R_PushDlights (currentmodel);
+
+ if (topnode->contents == CONTENTS_NODE)
+ {
+ // not a leaf; has to be clipped to the world BSP
+ r_clipflags = clipflags;
+ R_DrawSolidClippedSubmodelPolygons (currentmodel, topnode);
+ }
+ else
+ {
+ // falls entirely in one leaf, so we just put all the
+ // edges in the edge list and let 1/z sorting handle
+ // drawing order
+ R_DrawSubmodelPolygons (currentmodel, clipflags, topnode);
+ }
+
+ // put back world rotation and frustum clipping
+ // FIXME: R_RotateBmodel should just work off base_vxx
+ VectorCopy (base_vpn, vpn);
+ VectorCopy (base_vup, vup);
+ VectorCopy (base_vright, vright);
+ VectorCopy (oldorigin, modelorg);
+ R_TransformFrustum ();
+ }
+
+ insubmodel = false;
+}
+
+
+/*
+================
+R_EdgeDrawing
+================
+*/
+void R_EdgeDrawing (void)
+{
+ edge_t ledges[NUMSTACKEDGES +
+ ((CACHE_SIZE - 1) / sizeof(edge_t)) + 1];
+ surf_t lsurfs[NUMSTACKSURFACES +
+ ((CACHE_SIZE - 1) / sizeof(surf_t)) + 1];
+
+ if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
+ return;
+
+ if (auxedges)
+ {
+ r_edges = auxedges;
+ }
+ else
+ {
+ r_edges = (edge_t *)
+ (((uintptr)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
+ }
+
+ if (r_surfsonstack)
+ {
+ surfaces = (surf_t *)
+ (((uintptr)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
+ surf_max = &surfaces[r_cnumsurfs];
+ // surface 0 doesn't really exist; it's just a dummy because index 0
+ // is used to indicate no edge attached to surface
+ surfaces--;
+ R_SurfacePatch ();
+ }
+
+ R_BeginEdgeFrame ();
+
+ if (r_dspeeds->value)
+ {
+ rw_time1 = Sys_Milliseconds ();
+ }
+
+ R_RenderWorld ();
+
+ if (r_dspeeds->value)
+ {
+ rw_time2 = Sys_Milliseconds ();
+ db_time1 = rw_time2;
+ }
+
+ R_DrawBEntitiesOnList ();
+
+ if (r_dspeeds->value)
+ {
+ db_time2 = Sys_Milliseconds ();
+ se_time1 = db_time2;
+ }
+
+ R_ScanEdges ();
+}
+
+//=======================================================================
+
+
+/*
+=============
+R_CalcPalette
+
+=============
+*/
+void R_CalcPalette (void)
+{
+ static qboolean modified;
+ byte palette[256][4], *in, *out;
+ int i, j;
+ float alpha, one_minus_alpha;
+ vec3_t premult;
+ int v;
+
+ alpha = r_newrefdef.blend[3];
+ if (alpha <= 0)
+ {
+ if (modified)
+ { // set back to default
+ modified = false;
+ R_GammaCorrectAndSetPalette((uchar *)d_8to24table);
+ return;
+ }
+ return;
+ }
+
+ modified = true;
+ if (alpha > 1)
+ alpha = 1;
+
+ premult[0] = r_newrefdef.blend[0]*alpha*255;
+ premult[1] = r_newrefdef.blend[1]*alpha*255;
+ premult[2] = r_newrefdef.blend[2]*alpha*255;
+
+ one_minus_alpha = (1.0 - alpha);
+
+ in = (byte *)d_8to24table;
+ out = palette[0];
+ for (i=0 ; i<256 ; i++, in+=4, out+=4)
+ {
+ for (j=0 ; j<3 ; j++)
+ {
+ v = premult[j] + one_minus_alpha * in[j];
+ if (v > 255)
+ v = 255;
+ out[j] = v;
+ }
+ out[3] = 255;
+ }
+
+ R_GammaCorrectAndSetPalette((uchar *)palette[0]);
+// SWimp_SetPalette( palette[0] );
+}
+
+//=======================================================================
+
+void R_SetLightLevel (void)
+{
+ vec3_t light;
+
+ if ((r_newrefdef.rdflags & RDF_NOWORLDMODEL) || (!r_drawentities->value) || (!currententity))
+ {
+ r_lightlevel->value = 150.0;
+ return;
+ }
+
+ // save off light value for server to look at (BIG HACK!)
+ R_LightPoint (r_newrefdef.vieworg, light);
+ r_lightlevel->value = 150.0 * light[0];
+}
+
+
+/*
+@@@@@@@@@@@@@@@@
+R_RenderFrame
+
+@@@@@@@@@@@@@@@@
+*/
+void R_RenderFrame (refdef_t *fd)
+{
+ r_newrefdef = *fd;
+
+ if (!r_worldmodel && !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) )
+ ri.Sys_Error (ERR_FATAL,"R_RenderView: NULL worldmodel");
+
+ VectorCopy (fd->vieworg, r_refdef.vieworg);
+ VectorCopy (fd->viewangles, r_refdef.viewangles);
+
+ if (r_speeds->value || r_dspeeds->value)
+ r_time1 = Sys_Milliseconds ();
+
+ R_SetupFrame ();
+
+ R_MarkLeaves (); // done here so we know if we're in water
+
+ R_PushDlights (r_worldmodel);
+
+ R_EdgeDrawing ();
+
+ if (r_dspeeds->value)
+ {
+ se_time2 = Sys_Milliseconds ();
+ de_time1 = se_time2;
+ }
+
+ R_DrawEntitiesOnList ();
+
+ if (r_dspeeds->value)
+ {
+ de_time2 = Sys_Milliseconds ();
+ dp_time1 = Sys_Milliseconds ();
+ }
+
+ R_DrawParticles ();
+
+ if (r_dspeeds->value)
+ dp_time2 = Sys_Milliseconds ();
+
+ R_DrawAlphaSurfaces();
+
+ R_SetLightLevel ();
+
+ if (r_dowarp)
+ D_WarpScreen ();
+
+ if (r_dspeeds->value)
+ da_time1 = Sys_Milliseconds ();
+
+ if (r_dspeeds->value)
+ da_time2 = Sys_Milliseconds ();
+
+ R_CalcPalette ();
+
+ if (sw_aliasstats->value)
+ R_PrintAliasStats ();
+
+ if (r_speeds->value)
+ R_PrintTimes ();
+
+ if (r_dspeeds->value)
+ R_PrintDSpeeds ();
+
+ if (sw_reportsurfout->value && r_outofsurfaces)
+ ri.Con_Printf (PRINT_ALL,"Short %d surfaces\n", r_outofsurfaces);
+
+ if (sw_reportedgeout->value && r_outofedges)
+ ri.Con_Printf (PRINT_ALL,"Short roughly %d edges\n", r_outofedges * 2 / 3);
+}
+
+/*
+** R_InitGraphics
+*/
+void R_InitGraphics( int width, int height )
+{
+ vid.width = width;
+ vid.height = height;
+
+ // free z buffer
+ if ( d_pzbuffer )
+ {
+ free( d_pzbuffer );
+ d_pzbuffer = NULL;
+ }
+
+ // free surface cache
+ if ( sc_base )
+ {
+ D_FlushCaches ();
+ free( sc_base );
+ sc_base = NULL;
+ }
+
+ d_pzbuffer = malloc(vid.width*vid.height*2);
+
+ R_InitCaches ();
+
+ R_GammaCorrectAndSetPalette((uchar *)d_8to24table);
+}
+
+/*
+** R_BeginFrame
+*/
+void R_BeginFrame( float /*camera_separation*/ )
+{
+ extern void Draw_BuildGammaTable( void );
+
+ /*
+ ** rebuild the gamma correction palette if necessary
+ */
+ if ( vid_gamma->modified )
+ {
+ Draw_BuildGammaTable();
+ R_GammaCorrectAndSetPalette((uchar *)d_8to24table);
+
+ vid_gamma->modified = false;
+ }
+
+ while ( sw_mode->modified || vid_fullscreen->modified )
+ {
+ rserr_t err;
+
+ /*
+ ** if this returns rserr_invalid_fullscreen then it set the mode but not as a
+ ** fullscreen mode, e.g. 320x200 on a system that doesn't support that res
+ */
+ if ( ( err = SWimp_SetMode( &vid.width, &vid.height, sw_mode->value, vid_fullscreen->value ) ) == rserr_ok )
+ {
+ R_InitGraphics( vid.width, vid.height );
+
+ sw_state.prev_mode = sw_mode->value;
+ vid_fullscreen->modified = false;
+ sw_mode->modified = false;
+ }
+ else
+ {
+ if ( err == rserr_invalid_mode )
+ {
+ ri.Cvar_SetValue( "sw_mode", sw_state.prev_mode );
+ ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - could not set mode\n" );
+ }
+ else if ( err == rserr_invalid_fullscreen )
+ {
+ R_InitGraphics( vid.width, vid.height );
+
+ ri.Cvar_SetValue( "vid_fullscreen", 0);
+ ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - fullscreen unavailable in this mode\n" );
+ sw_state.prev_mode = sw_mode->value;
+// vid_fullscreen->modified = false;
+// sw_mode->modified = false;
+ }
+ else
+ {
+ ri.Sys_Error( ERR_FATAL, "ref_soft::R_BeginFrame() - catastrophic mode change failure\n" );
+ }
+ }
+ }
+}
+
+void
+R_GammaCorrectAndSetPalette(uchar *palette)
+{
+ int i;
+
+ for ( i = 0; i < 256; i++ )
+ {
+ sw_state.currentpalette[i*4+0] = sw_state.gammatable[palette[i*4+0]];
+ sw_state.currentpalette[i*4+1] = sw_state.gammatable[palette[i*4+1]];
+ sw_state.currentpalette[i*4+2] = sw_state.gammatable[palette[i*4+2]];
+ }
+
+ SWimp_SetPalette( sw_state.currentpalette );
+}
+
+void
+R_CinematicSetPalette(uchar *palette)
+{
+ byte palette32[1024];
+ int i, j, w;
+ int *d;
+
+ // clear screen to black to avoid any palette flash
+ w = abs(vid.rowbytes)>>2; // stupid negative pitch win32 stuff...
+ for (i=0 ; i<vid.height ; i++)
+ {
+ d = (int *)(vid.buffer + i*vid.rowbytes);
+ for (j=0 ; j<w ; j++)
+ d[j] = 0;
+ }
+ // flush it to the screen
+ SWimp_EndFrame ();
+
+ if ( palette )
+ {
+ for ( i = 0; i < 256; i++ )
+ {
+ palette32[i*4+0] = palette[i*3+0];
+ palette32[i*4+1] = palette[i*3+1];
+ palette32[i*4+2] = palette[i*3+2];
+ palette32[i*4+3] = 0xFF;
+ }
+
+ R_GammaCorrectAndSetPalette( palette32 );
+ }
+ else
+ {
+ R_GammaCorrectAndSetPalette((uchar *)d_8to24table);
+ }
+}
+
+/*
+================
+Draw_BuildGammaTable
+================
+*/
+void Draw_BuildGammaTable (void)
+{
+ int i, inf;
+ float g;
+
+ g = vid_gamma->value;
+
+ if (g == 1.0)
+ {
+ for (i=0 ; i<256 ; i++)
+ sw_state.gammatable[i] = i;
+ return;
+ }
+
+ for (i=0 ; i<256 ; i++)
+ {
+ inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5;
+ if (inf < 0)
+ inf = 0;
+ if (inf > 255)
+ inf = 255;
+ sw_state.gammatable[i] = inf;
+ }
+}
+
+/*
+** R_DrawBeam
+*/
+void R_DrawBeam( entity_t *e )
+{
+#define NUM_BEAM_SEGS 6
+
+ int i;
+
+ vec3_t perpvec;
+ vec3_t direction, normalized_direction;
+ vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS];
+ vec3_t oldorigin, origin;
+
+ oldorigin[0] = e->oldorigin[0];
+ oldorigin[1] = e->oldorigin[1];
+ oldorigin[2] = e->oldorigin[2];
+
+ origin[0] = e->origin[0];
+ origin[1] = e->origin[1];
+ origin[2] = e->origin[2];
+
+ normalized_direction[0] = direction[0] = oldorigin[0] - origin[0];
+ normalized_direction[1] = direction[1] = oldorigin[1] - origin[1];
+ normalized_direction[2] = direction[2] = oldorigin[2] - origin[2];
+
+ if ( VectorNormalize( normalized_direction ) == 0 )
+ return;
+
+ PerpendicularVector( perpvec, normalized_direction );
+ VectorScale( perpvec, e->frame / 2, perpvec );
+
+ for ( i = 0; i < NUM_BEAM_SEGS; i++ )
+ {
+ RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i );
+ VectorAdd( start_points[i], origin, start_points[i] );
+ VectorAdd( start_points[i], direction, end_points[i] );
+ }
+
+ for ( i = 0; i < NUM_BEAM_SEGS; i++ )
+ {
+ R_IMFlatShadedQuad( start_points[i],
+ end_points[i],
+ end_points[(i+1)%NUM_BEAM_SEGS],
+ start_points[(i+1)%NUM_BEAM_SEGS],
+ e->skinnum & 0xFF,
+ e->alpha );
+ }
+}
+
+
+//===================================================================
+
+/*
+============
+R_SetSky
+============
+*/
+// 3dstudio environment map names
+char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
+int r_skysideimage[6] = {5, 2, 4, 1, 0, 3};
+extern mtexinfo_t r_skytexinfo[6];
+void R_SetSky (char *name, float rotate, vec3_t axis)
+{
+ int i;
+ char pathname[MAX_QPATH];
+
+ strncpy (skyname, name, sizeof(skyname)-1);
+ skyrotate = rotate;
+ VectorCopy (axis, skyaxis);
+
+ for (i=0 ; i<6 ; i++)
+ {
+ Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[r_skysideimage[i]]);
+ r_skytexinfo[i].image = R_FindImage (pathname, it_sky);
+ }
+}
+
+
+/*
+===============
+Draw_GetPalette
+===============
+*/
+void Draw_GetPalette (void)
+{
+ byte *pal, *out;
+ int i;
+ int r, g, b;
+
+ // get the palette and colormap
+ LoadPCX ("pics/colormap.pcx", &vid.colormap, &pal, NULL, NULL);
+ if (!vid.colormap)
+ ri.Sys_Error (ERR_FATAL, "Couldn't load pics/colormap.pcx");
+ vid.alphamap = vid.colormap + 64*256;
+
+ out = (byte *)d_8to24table;
+ for (i=0 ; i<256 ; i++, out+=4)
+ {
+ r = pal[i*3+0];
+ g = pal[i*3+1];
+ b = pal[i*3+2];
+
+ out[0] = r;
+ out[1] = g;
+ out[2] = b;
+ }
+
+ free (pal);
+}
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+GetRefAPI
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+refexport_t GetRefAPI (refimport_t rimp)
+{
+ refexport_t re;
+
+ ri = rimp;
+
+ re.api_version = API_VERSION;
+
+ re.BeginRegistration = R_BeginRegistration;
+ re.RegisterModel = R_RegisterModel;
+ re.RegisterSkin = R_RegisterSkin;
+ re.RegisterPic = Draw_FindPic;
+ re.SetSky = R_SetSky;
+ re.EndRegistration = R_EndRegistration;
+
+ re.RenderFrame = R_RenderFrame;
+
+ re.DrawGetPicSize = Draw_GetPicSize;
+ re.DrawPic = Draw_Pic;
+ re.DrawStretchPic = Draw_StretchPic;
+ re.DrawChar = Draw_Char;
+ re.DrawTileClear = Draw_TileClear;
+ re.DrawFill = Draw_Fill;
+ re.DrawFadeScreen= Draw_FadeScreen;
+
+ re.DrawStretchRaw = Draw_StretchRaw;
+
+ re.Init = R_Init;
+ re.Shutdown = R_Shutdown;
+
+ re.CinematicSetPalette = R_CinematicSetPalette;
+ re.BeginFrame = R_BeginFrame;
+ re.EndFrame = SWimp_EndFrame;
+
+ re.AppActivate = SWimp_AppActivate;
+
+ Swap_Init ();
+
+ return re;
+}
--- /dev/null
+++ b/r_misc.c
@@ -1,0 +1,567 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+#define NUM_MIPS 4
+
+cvar_t *sw_mipcap;
+cvar_t *sw_mipscale;
+
+surfcache_t *d_initial_rover;
+qboolean d_roverwrapped;
+int d_minmip;
+float d_scalemip[NUM_MIPS-1];
+
+static float basemip[NUM_MIPS-1] = {1.0, 0.5*0.8, 0.25*0.8};
+
+extern int d_aflatcolor;
+
+int d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle;
+
+int d_pix_min, d_pix_max, d_pix_shift;
+
+int d_scantable[MAXHEIGHT];
+short *zspantable[MAXHEIGHT];
+
+/*
+================
+D_Patch
+================
+*/
+void D_Patch (void)
+{
+}
+/*
+================
+D_ViewChanged
+================
+*/
+unsigned char *alias_colormap;
+
+void D_ViewChanged (void)
+{
+ int i;
+
+ scale_for_mip = xscale;
+ if (yscale > xscale)
+ scale_for_mip = yscale;
+
+ d_zrowbytes = vid.width * 2;
+ d_zwidth = vid.width;
+
+ d_pix_min = r_refdef.vrect.width / 320;
+ if (d_pix_min < 1)
+ d_pix_min = 1;
+
+ d_pix_max = (int)((float)r_refdef.vrect.width / (320.0 / 4.0) + 0.5);
+ d_pix_shift = 8 - (int)((float)r_refdef.vrect.width / 320.0 + 0.5);
+ if (d_pix_max < 1)
+ d_pix_max = 1;
+
+ d_vrectx = r_refdef.vrect.x;
+ d_vrecty = r_refdef.vrect.y;
+ d_vrectright_particle = r_refdef.vrectright - d_pix_max;
+ d_vrectbottom_particle =
+ r_refdef.vrectbottom - d_pix_max;
+
+ for (i=0 ; i<vid.height; i++)
+ {
+ d_scantable[i] = i*r_screenwidth;
+ zspantable[i] = d_pzbuffer + i*d_zwidth;
+ }
+
+ /*
+ ** clear Z-buffer and color-buffers if we're doing the gallery
+ */
+ if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
+ {
+ memset( d_pzbuffer, 0xff, vid.width * vid.height * sizeof( d_pzbuffer[0] ) );
+ Draw_Fill( r_newrefdef.x, r_newrefdef.y, r_newrefdef.width, r_newrefdef.height,( int ) sw_clearcolor->value & 0xff );
+ }
+
+ alias_colormap = vid.colormap;
+
+ D_Patch ();
+}
+
+
+
+/*
+=============
+R_PrintTimes
+=============
+*/
+void R_PrintTimes (void)
+{
+ int r_time2;
+ int ms;
+
+ r_time2 = Sys_Milliseconds ();
+
+ ms = r_time2 - r_time1;
+
+ ri.Con_Printf (PRINT_ALL,"%5i ms %3i/%3i/%3i poly %3i surf\n",
+ ms, c_faceclip, r_polycount, r_drawnpolycount, c_surf);
+ c_surf = 0;
+}
+
+
+/*
+=============
+R_PrintDSpeeds
+=============
+*/
+void R_PrintDSpeeds (void)
+{
+ int ms, dp_time, r_time2, rw_time, db_time, se_time, de_time, da_time;
+
+ r_time2 = Sys_Milliseconds ();
+
+ da_time = (da_time2 - da_time1);
+ dp_time = (dp_time2 - dp_time1);
+ rw_time = (rw_time2 - rw_time1);
+ db_time = (db_time2 - db_time1);
+ se_time = (se_time2 - se_time1);
+ de_time = (de_time2 - de_time1);
+ ms = (r_time2 - r_time1);
+
+ ri.Con_Printf (PRINT_ALL,"%3i %2ip %2iw %2ib %2is %2ie %2ia\n",
+ ms, dp_time, rw_time, db_time, se_time, de_time, da_time);
+}
+
+
+/*
+=============
+R_PrintAliasStats
+=============
+*/
+void R_PrintAliasStats (void)
+{
+ ri.Con_Printf (PRINT_ALL,"%3i polygon model drawn\n", r_amodels_drawn);
+}
+
+
+
+/*
+===================
+R_TransformFrustum
+===================
+*/
+void R_TransformFrustum (void)
+{
+ int i;
+ vec3_t v, v2;
+
+ for (i=0 ; i<4 ; i++)
+ {
+ v[0] = screenedge[i].normal[2];
+ v[1] = -screenedge[i].normal[0];
+ v[2] = screenedge[i].normal[1];
+
+ v2[0] = v[1]*vright[0] + v[2]*vup[0] + v[0]*vpn[0];
+ v2[1] = v[1]*vright[1] + v[2]*vup[1] + v[0]*vpn[1];
+ v2[2] = v[1]*vright[2] + v[2]*vup[2] + v[0]*vpn[2];
+
+ VectorCopy (v2, view_clipplanes[i].normal);
+
+ view_clipplanes[i].dist = DotProduct (modelorg, v2);
+ }
+}
+
+
+/*
+================
+TransformVector
+================
+*/
+void TransformVector (vec3_t in, vec3_t out)
+{
+ out[0] = DotProduct(in,vright);
+ out[1] = DotProduct(in,vup);
+ out[2] = DotProduct(in,vpn);
+}
+
+
+/*
+================
+R_TransformPlane
+================
+*/
+void R_TransformPlane (mplane_t *p, float *normal, float *dist)
+{
+ float d;
+
+ d = DotProduct (r_origin, p->normal);
+ *dist = p->dist - d;
+// TODO: when we have rotating entities, this will need to use the view matrix
+ TransformVector (p->normal, normal);
+}
+
+
+/*
+===============
+R_SetUpFrustumIndexes
+===============
+*/
+void R_SetUpFrustumIndexes (void)
+{
+ int i, j, *pindex;
+
+ pindex = r_frustum_indexes;
+
+ for (i=0 ; i<4 ; i++)
+ {
+ for (j=0 ; j<3 ; j++)
+ {
+ if (view_clipplanes[i].normal[j] < 0)
+ {
+ pindex[j] = j;
+ pindex[j+3] = j+3;
+ }
+ else
+ {
+ pindex[j] = j+3;
+ pindex[j+3] = j;
+ }
+ }
+
+ // FIXME: do just once at start
+ pfrustum_indexes[i] = pindex;
+ pindex += 6;
+ }
+}
+
+/*
+===============
+R_ViewChanged
+
+Called every time the vid structure or r_refdef changes.
+Guaranteed to be called before the first refresh
+===============
+*/
+void R_ViewChanged (vrect_t *vr)
+{
+ int i;
+
+ r_refdef.vrect = *vr;
+
+ r_refdef.horizontalFieldOfView = 2*tan((float)r_newrefdef.fov_x/360*M_PI);;
+ verticalFieldOfView = 2*tan((float)r_newrefdef.fov_y/360*M_PI);
+
+ r_refdef.fvrectx = (float)r_refdef.vrect.x;
+ r_refdef.fvrectx_adj = (float)r_refdef.vrect.x - 0.5;
+ r_refdef.vrect_x_adj_shift20 = (r_refdef.vrect.x<<20) + (1<<19) - 1;
+ r_refdef.fvrecty = (float)r_refdef.vrect.y;
+ r_refdef.fvrecty_adj = (float)r_refdef.vrect.y - 0.5;
+ r_refdef.vrectright = r_refdef.vrect.x + r_refdef.vrect.width;
+ r_refdef.vrectright_adj_shift20 = (r_refdef.vrectright<<20) + (1<<19) - 1;
+ r_refdef.fvrectright = (float)r_refdef.vrectright;
+ r_refdef.fvrectright_adj = (float)r_refdef.vrectright - 0.5;
+ r_refdef.vrectrightedge = (float)r_refdef.vrectright - 0.99;
+ r_refdef.vrectbottom = r_refdef.vrect.y + r_refdef.vrect.height;
+ r_refdef.fvrectbottom = (float)r_refdef.vrectbottom;
+ r_refdef.fvrectbottom_adj = (float)r_refdef.vrectbottom - 0.5;
+
+ r_refdef.aliasvrect.x = (int)(r_refdef.vrect.x * r_aliasuvscale);
+ r_refdef.aliasvrect.y = (int)(r_refdef.vrect.y * r_aliasuvscale);
+ r_refdef.aliasvrect.width = (int)(r_refdef.vrect.width * r_aliasuvscale);
+ r_refdef.aliasvrect.height = (int)(r_refdef.vrect.height * r_aliasuvscale);
+ r_refdef.aliasvrectright = r_refdef.aliasvrect.x +
+ r_refdef.aliasvrect.width;
+ r_refdef.aliasvrectbottom = r_refdef.aliasvrect.y +
+ r_refdef.aliasvrect.height;
+
+ xOrigin = r_refdef.xOrigin;
+ yOrigin = r_refdef.yOrigin;
+
+// values for perspective projection
+// if math were exact, the values would range from 0.5 to to range+0.5
+// hopefully they wll be in the 0.000001 to range+.999999 and truncate
+// the polygon rasterization will never render in the first row or column
+// but will definately render in the [range] row and column, so adjust the
+// buffer origin to get an exact edge to edge fill
+ xcenter = ((float)r_refdef.vrect.width * XCENTERING) +
+ r_refdef.vrect.x - 0.5;
+ aliasxcenter = xcenter * r_aliasuvscale;
+ ycenter = ((float)r_refdef.vrect.height * YCENTERING) +
+ r_refdef.vrect.y - 0.5;
+ aliasycenter = ycenter * r_aliasuvscale;
+
+ xscale = r_refdef.vrect.width / r_refdef.horizontalFieldOfView;
+ aliasxscale = xscale * r_aliasuvscale;
+ xscaleinv = 1.0 / xscale;
+
+ yscale = xscale;
+ aliasyscale = yscale * r_aliasuvscale;
+ yscaleinv = 1.0 / yscale;
+ xscaleshrink = (r_refdef.vrect.width-6)/r_refdef.horizontalFieldOfView;
+ yscaleshrink = xscaleshrink;
+
+// left side clip
+ screenedge[0].normal[0] = -1.0 / (xOrigin*r_refdef.horizontalFieldOfView);
+ screenedge[0].normal[1] = 0;
+ screenedge[0].normal[2] = 1;
+ screenedge[0].type = PLANE_ANYZ;
+
+// right side clip
+ screenedge[1].normal[0] =
+ 1.0 / ((1.0-xOrigin)*r_refdef.horizontalFieldOfView);
+ screenedge[1].normal[1] = 0;
+ screenedge[1].normal[2] = 1;
+ screenedge[1].type = PLANE_ANYZ;
+
+// top side clip
+ screenedge[2].normal[0] = 0;
+ screenedge[2].normal[1] = -1.0 / (yOrigin*verticalFieldOfView);
+ screenedge[2].normal[2] = 1;
+ screenedge[2].type = PLANE_ANYZ;
+
+// bottom side clip
+ screenedge[3].normal[0] = 0;
+ screenedge[3].normal[1] = 1.0 / ((1.0-yOrigin)*verticalFieldOfView);
+ screenedge[3].normal[2] = 1;
+ screenedge[3].type = PLANE_ANYZ;
+
+ for (i=0 ; i<4 ; i++)
+ VectorNormalize (screenedge[i].normal);
+
+ D_ViewChanged ();
+}
+
+
+/*
+===============
+R_SetupFrame
+===============
+*/
+void R_SetupFrame (void)
+{
+ int i;
+ vrect_t vrect;
+
+ if (r_fullbright->modified)
+ {
+ r_fullbright->modified = false;
+ D_FlushCaches (); // so all lighting changes
+ }
+
+ r_framecount++;
+
+
+// build the transformation matrix for the given view angles
+ VectorCopy (r_refdef.vieworg, modelorg);
+ VectorCopy (r_refdef.vieworg, r_origin);
+
+ AngleVectors (r_refdef.viewangles, vpn, vright, vup);
+
+// current viewleaf
+ if ( !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) )
+ {
+ r_viewleaf = Mod_PointInLeaf (r_origin, r_worldmodel);
+ r_viewcluster = r_viewleaf->cluster;
+ }
+
+ if (sw_waterwarp->value && (r_newrefdef.rdflags & RDF_UNDERWATER) )
+ r_dowarp = true;
+ else
+ r_dowarp = false;
+
+ if (r_dowarp)
+ { // warp into off screen buffer
+ vrect.x = 0;
+ vrect.y = 0;
+ vrect.width = r_newrefdef.width < WARP_WIDTH ? r_newrefdef.width : WARP_WIDTH;
+ vrect.height = r_newrefdef.height < WARP_HEIGHT ? r_newrefdef.height : WARP_HEIGHT;
+
+ d_viewbuffer = r_warpbuffer;
+ r_screenwidth = WARP_WIDTH;
+ }
+ else
+ {
+ vrect.x = r_newrefdef.x;
+ vrect.y = r_newrefdef.y;
+ vrect.width = r_newrefdef.width;
+ vrect.height = r_newrefdef.height;
+
+ d_viewbuffer = (void *)vid.buffer;
+ r_screenwidth = vid.rowbytes;
+ }
+
+ R_ViewChanged (&vrect);
+
+// start off with just the four screen edge clip planes
+ R_TransformFrustum ();
+ R_SetUpFrustumIndexes ();
+
+// save base values
+ VectorCopy (vpn, base_vpn);
+ VectorCopy (vright, base_vright);
+ VectorCopy (vup, base_vup);
+
+// clear frame counts
+ c_faceclip = 0;
+ d_spanpixcount = 0;
+ r_polycount = 0;
+ r_drawnpolycount = 0;
+ r_wholepolycount = 0;
+ r_amodels_drawn = 0;
+ r_outofsurfaces = 0;
+ r_outofedges = 0;
+
+// d_setup
+ d_roverwrapped = false;
+ d_initial_rover = sc_rover;
+
+ d_minmip = sw_mipcap->value;
+ if (d_minmip > 3)
+ d_minmip = 3;
+ else if (d_minmip < 0)
+ d_minmip = 0;
+
+ for (i=0 ; i<(NUM_MIPS-1) ; i++)
+ d_scalemip[i] = basemip[i] * sw_mipscale->value;
+
+ d_aflatcolor = 0;
+}
+
+
+/*
+==============================================================================
+
+ SCREEN SHOTS
+
+==============================================================================
+*/
+
+
+/*
+==============
+WritePCXfile
+==============
+*/
+void WritePCXfile (char *filename, byte *data, int width, int height,
+ int rowbytes, byte *palette)
+{
+ int i, j, length;
+ pcx_t *pcx;
+ byte *pack;
+ FILE *f;
+
+ pcx = (pcx_t *)malloc (width*height*2+1000);
+ if (!pcx)
+ return;
+
+ pcx->manufacturer = 0x0a; // PCX id
+ pcx->version = 5; // 256 color
+ pcx->encoding = 1; // uncompressed
+ pcx->bits_per_pixel = 8; // 256 color
+ pcx->xmin = 0;
+ pcx->ymin = 0;
+ pcx->xmax = LittleShort((short)(width-1));
+ pcx->ymax = LittleShort((short)(height-1));
+ pcx->hres = LittleShort((short)width);
+ pcx->vres = LittleShort((short)height);
+ memset (pcx->palette,0,sizeof(pcx->palette));
+ pcx->color_planes = 1; // chunky image
+ pcx->bytes_per_line = LittleShort((short)width);
+ pcx->palette_type = LittleShort(2); // not a grey scale
+ memset (pcx->filler,0,sizeof(pcx->filler));
+
+// pack the image
+ pack = &pcx->data;
+
+ for (i=0 ; i<height ; i++)
+ {
+ for (j=0 ; j<width ; j++)
+ {
+ if ( (*data & 0xc0) != 0xc0)
+ *pack++ = *data++;
+ else
+ {
+ *pack++ = 0xc1;
+ *pack++ = *data++;
+ }
+ }
+
+ data += rowbytes - width;
+ }
+
+// write the palette
+ *pack++ = 0x0c; // palette ID byte
+ for (i=0 ; i<768 ; i++)
+ *pack++ = *palette++;
+
+// write output file
+ length = pack - (byte *)pcx;
+ f = fopen (filename, "wb");
+ if (!f)
+ ri.Con_Printf (PRINT_ALL, "Failed to open to %s\n", filename);
+ else
+ {
+ fwrite ((void *)pcx, 1, length, f);
+ fclose (f);
+ }
+
+ free (pcx);
+}
+
+
+
+/*
+==================
+R_ScreenShot_f
+==================
+*/
+void R_ScreenShot_f (void)
+{
+ int i;
+ char pcxname[80];
+ char checkname[MAX_OSPATH];
+ FILE *f;
+ byte palette[768];
+
+ // create the scrnshots directory if it doesn't exist
+ Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot", ri.FS_Gamedir());
+ Sys_Mkdir (checkname);
+
+//
+// find a file name to save it to
+//
+ strcpy(pcxname,"quake00.pcx");
+
+ for (i=0 ; i<=99 ; i++)
+ {
+ pcxname[5] = i/10 + '0';
+ pcxname[6] = i%10 + '0';
+ Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/%s", ri.FS_Gamedir(), pcxname);
+ f = fopen (checkname, "r");
+ if (!f)
+ break; // file doesn't exist
+ fclose (f);
+ }
+ if (i==100)
+ {
+ ri.Con_Printf (PRINT_ALL, "R_ScreenShot_f: Couldn't create a PCX");
+ return;
+ }
+
+ // turn the current 32 bit palette into a 24 bit palette
+ for (i=0 ; i<256 ; i++)
+ {
+ palette[i*3+0] = sw_state.currentpalette[i*4+0];
+ palette[i*3+1] = sw_state.currentpalette[i*4+1];
+ palette[i*3+2] = sw_state.currentpalette[i*4+2];
+ }
+
+//
+// save the pcx file
+//
+
+ WritePCXfile (checkname, vid.buffer, vid.width, vid.height, vid.rowbytes,
+ palette);
+
+ ri.Con_Printf (PRINT_ALL, "Wrote %s\n", checkname);
+}
+
--- /dev/null
+++ b/r_model.c
@@ -1,0 +1,1205 @@
+// models.c -- model loading and caching
+
+// models are the only shared resource between a client and server running
+// on the same machine.
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+model_t *loadmodel;
+char loadname[32]; // for hunk tags
+
+void Mod_LoadSpriteModel (model_t *mod, void *buffer);
+void Mod_LoadBrushModel (model_t *mod, void *buffer);
+void Mod_LoadAliasModel (model_t *mod, void *buffer);
+model_t *Mod_LoadModel (model_t *mod, qboolean crash);
+
+byte mod_novis[MAX_MAP_LEAFS/8];
+
+#define MAX_MOD_KNOWN 256
+model_t mod_known[MAX_MOD_KNOWN];
+int mod_numknown;
+
+// the inline * models from the current map are kept seperate
+model_t mod_inline[MAX_MOD_KNOWN];
+
+int registration_sequence;
+int modfilelen;
+
+//===============================================================================
+
+
+/*
+================
+Mod_Modellist_f
+================
+*/
+void Mod_Modellist_f (void)
+{
+ int i;
+ model_t *mod;
+ int total;
+
+ total = 0;
+ ri.Con_Printf (PRINT_ALL,"Loaded models:\n");
+ for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++)
+ {
+ if (!mod->name[0])
+ continue;
+ ri.Con_Printf (PRINT_ALL, "%8i : %s\n",mod->extradatasize, mod->name);
+ total += mod->extradatasize;
+ }
+ ri.Con_Printf (PRINT_ALL, "Total resident: %i\n", total);
+}
+
+/*
+===============
+Mod_Init
+===============
+*/
+void Mod_Init (void)
+{
+ memset (mod_novis, 0xff, sizeof(mod_novis));
+}
+
+/*
+==================
+Mod_ForName
+
+Loads in a model for the given name
+==================
+*/
+model_t *Mod_ForName (char *name, qboolean crash)
+{
+ model_t *mod;
+ unsigned *buf;
+ int i;
+
+ if (!name[0])
+ ri.Sys_Error (ERR_DROP,"Mod_ForName: NULL name");
+
+ //
+ // inline models are grabbed only from worldmodel
+ //
+ if (name[0] == '*')
+ {
+ i = atoi(name+1);
+ if (i < 1 || !r_worldmodel || i >= r_worldmodel->numsubmodels)
+ ri.Sys_Error (ERR_DROP, "bad inline model number");
+ return &mod_inline[i];
+ }
+
+ //
+ // search the currently loaded models
+ //
+ for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
+ if (!strcmp (mod->name, name) )
+ return mod;
+
+ //
+ // find a free model slot spot
+ //
+ for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
+ {
+ if (!mod->name[0])
+ break; // free spot
+ }
+ if (i == mod_numknown)
+ {
+ if (mod_numknown == MAX_MOD_KNOWN)
+ ri.Sys_Error (ERR_DROP, "mod_numknown == MAX_MOD_KNOWN");
+ mod_numknown++;
+ }
+ strcpy (mod->name, name);
+
+ //
+ // load the file
+ //
+ modfilelen = ri.FS_LoadFile (mod->name, (void **)&buf);
+ if (!buf)
+ {
+ if (crash)
+ ri.Sys_Error (ERR_DROP,"Mod_NumForName: %s not found", mod->name);
+ memset (mod->name, 0, sizeof(mod->name));
+ return NULL;
+ }
+
+ loadmodel = mod;
+
+ //
+ // fill it in
+ //
+
+ // call the apropriate loader
+
+ switch (LittleLong(*(unsigned *)buf))
+ {
+ case IDALIASHEADER:
+ loadmodel->extradata = Hunk_Begin (0x200000);
+ Mod_LoadAliasModel (mod, buf);
+ break;
+
+ case IDSPRITEHEADER:
+ loadmodel->extradata = Hunk_Begin (0x10000);
+ Mod_LoadSpriteModel (mod, buf);
+ break;
+
+ case IDBSPHEADER:
+ loadmodel->extradata = Hunk_Begin (0x1000000);
+ Mod_LoadBrushModel (mod, buf);
+ break;
+
+ default:
+ ri.Sys_Error (ERR_DROP,"Mod_NumForName: unknown fileid for %s", mod->name);
+ break;
+ }
+
+ loadmodel->extradatasize = Hunk_End ();
+
+ ri.FS_FreeFile (buf);
+
+ return mod;
+}
+
+
+/*
+===============
+Mod_PointInLeaf
+===============
+*/
+mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
+{
+ mnode_t *node;
+ float d;
+ mplane_t *plane;
+
+ if (!model || !model->nodes)
+ ri.Sys_Error (ERR_DROP, "Mod_PointInLeaf: bad model");
+
+ node = model->nodes;
+ while (1)
+ {
+ if (node->contents != -1)
+ return (mleaf_t *)node;
+ plane = node->plane;
+ d = DotProduct (p,plane->normal) - plane->dist;
+ if (d > 0)
+ node = node->children[0];
+ else
+ node = node->children[1];
+ }
+}
+
+
+/*
+===================
+Mod_DecompressVis
+===================
+*/
+byte *Mod_DecompressVis (byte *in, model_t *model)
+{
+ static byte decompressed[MAX_MAP_LEAFS/8];
+ int c;
+ byte *out;
+ int row;
+
+ row = (model->vis->numclusters+7)>>3;
+ out = decompressed;
+
+ /*
+ memcpy (out, in, row);
+ */
+ if (!in)
+ { // no vis info, so make all visible
+ while (row)
+ {
+ *out++ = 0xff;
+ row--;
+ }
+ return decompressed;
+ }
+
+ do
+ {
+ if (*in)
+ {
+ *out++ = *in++;
+ continue;
+ }
+
+ c = in[1];
+ in += 2;
+ while (c)
+ {
+ *out++ = 0;
+ c--;
+ }
+ } while (out - decompressed < row);
+
+ return decompressed;
+}
+
+/*
+==============
+Mod_ClusterPVS
+==============
+*/
+byte *Mod_ClusterPVS (int cluster, model_t *model)
+{
+ if (cluster == -1 || !model->vis)
+ return mod_novis;
+ return Mod_DecompressVis ( (byte *)model->vis + model->vis->bitofs[cluster][DVIS_PVS],
+ model);
+}
+
+/*
+===============================================================================
+
+ BRUSHMODEL LOADING
+
+===============================================================================
+*/
+
+byte *mod_base;
+
+
+/*
+=================
+Mod_LoadLighting
+
+Converts the 24 bit lighting down to 8 bit
+by taking the brightest component
+=================
+*/
+void Mod_LoadLighting (lump_t *l)
+{
+ int i, size;
+ byte *in;
+
+ if (!l->filelen)
+ {
+ loadmodel->lightdata = NULL;
+ return;
+ }
+ size = l->filelen/3;
+ loadmodel->lightdata = Hunk_Alloc (size);
+ in = (void *)(mod_base + l->fileofs);
+ for (i=0 ; i<size ; i++, in+=3)
+ {
+ if (in[0] > in[1] && in[0] > in[2])
+ loadmodel->lightdata[i] = in[0];
+ else if (in[1] > in[0] && in[1] > in[2])
+ loadmodel->lightdata[i] = in[1];
+ else
+ loadmodel->lightdata[i] = in[2];
+ }
+}
+
+
+int r_leaftovis[MAX_MAP_LEAFS];
+int r_vistoleaf[MAX_MAP_LEAFS];
+int r_numvisleafs;
+
+void R_NumberLeafs (mnode_t *node)
+{
+ mleaf_t *leaf;
+ int leafnum;
+
+ if (node->contents != -1)
+ {
+ leaf = (mleaf_t *)node;
+ leafnum = leaf - loadmodel->leafs;
+ if (leaf->contents & CONTENTS_SOLID)
+ return;
+ r_leaftovis[leafnum] = r_numvisleafs;
+ r_vistoleaf[r_numvisleafs] = leafnum;
+ r_numvisleafs++;
+ return;
+ }
+
+ R_NumberLeafs (node->children[0]);
+ R_NumberLeafs (node->children[1]);
+}
+
+
+/*
+=================
+Mod_LoadVisibility
+=================
+*/
+void Mod_LoadVisibility (lump_t *l)
+{
+ int i;
+
+ if (!l->filelen)
+ {
+ loadmodel->vis = NULL;
+ return;
+ }
+ loadmodel->vis = Hunk_Alloc ( l->filelen);
+ memcpy (loadmodel->vis, mod_base + l->fileofs, l->filelen);
+
+ loadmodel->vis->numclusters = LittleLong (loadmodel->vis->numclusters);
+ for (i=0 ; i<loadmodel->vis->numclusters ; i++)
+ {
+ loadmodel->vis->bitofs[i][0] = LittleLong (loadmodel->vis->bitofs[i][0]);
+ loadmodel->vis->bitofs[i][1] = LittleLong (loadmodel->vis->bitofs[i][1]);
+ }
+}
+
+
+/*
+=================
+Mod_LoadVertexes
+=================
+*/
+void Mod_LoadVertexes (lump_t *l)
+{
+ dvertex_t *in;
+ mvertex_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Hunk_Alloc ( (count+8)*sizeof(*out)); // extra for skybox
+
+ loadmodel->vertexes = out;
+ loadmodel->numvertexes = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ out->position[0] = LittleFloat (in->point[0]);
+ out->position[1] = LittleFloat (in->point[1]);
+ out->position[2] = LittleFloat (in->point[2]);
+ }
+}
+
+/*
+=================
+Mod_LoadSubmodels
+=================
+*/
+void Mod_LoadSubmodels (lump_t *l)
+{
+ dmodel_t *in;
+ dmodel_t *out;
+ int i, j, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Hunk_Alloc ( count*sizeof(*out));
+
+ loadmodel->submodels = out;
+ loadmodel->numsubmodels = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ for (j=0 ; j<3 ; j++)
+ { // spread the mins / maxs by a pixel
+ out->mins[j] = LittleFloat (in->mins[j]) - 1;
+ out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
+ out->origin[j] = LittleFloat (in->origin[j]);
+ }
+ out->headnode = LittleLong (in->headnode);
+ out->firstface = LittleLong (in->firstface);
+ out->numfaces = LittleLong (in->numfaces);
+ }
+}
+
+/*
+=================
+Mod_LoadEdges
+=================
+*/
+void Mod_LoadEdges (lump_t *l)
+{
+ dedge_t *in;
+ medge_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Hunk_Alloc ( (count + 13) * sizeof(*out)); // extra for skybox
+
+ loadmodel->edges = out;
+ loadmodel->numedges = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ out->v[0] = (unsigned short)LittleShort(in->v[0]);
+ out->v[1] = (unsigned short)LittleShort(in->v[1]);
+ }
+}
+
+/*
+=================
+Mod_LoadTexinfo
+=================
+*/
+void Mod_LoadTexinfo (lump_t *l)
+{
+ texinfo_t *in;
+ mtexinfo_t *out, *step;
+ int i, j, count;
+ float len1, len2;
+ char name[MAX_QPATH];
+ int next;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Hunk_Alloc ( (count+6)*sizeof(*out)); // extra for skybox
+
+ loadmodel->texinfo = out;
+ loadmodel->numtexinfo = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ for (j=0 ; j<8 ; j++)
+ out->vecs[0][j] = LittleFloat (in->vecs[0][j]);
+ len1 = VectorLength (out->vecs[0]);
+ len2 = VectorLength (out->vecs[1]);
+ len1 = (len1 + len2)/2;
+ if (len1 < 0.32)
+ out->mipadjust = 4;
+ else if (len1 < 0.49)
+ out->mipadjust = 3;
+ else if (len1 < 0.99)
+ out->mipadjust = 2;
+ else
+ out->mipadjust = 1;
+ /*
+ if (len1 + len2 < 0.001)
+ out->mipadjust = 1; // don't crash
+ else
+ out->mipadjust = 1 / floor( (len1+len2)/2 + 0.1 );
+ */
+
+ out->flags = LittleLong (in->flags);
+
+ next = LittleLong (in->nexttexinfo);
+ if (next > 0)
+ out->next = loadmodel->texinfo + next;
+
+ Com_sprintf (name, sizeof(name), "textures/%s.wal", in->texture);
+ out->image = R_FindImage (name, it_wall);
+ if (!out->image)
+ {
+ out->image = r_notexture_mip; // texture not found
+ out->flags = 0;
+ }
+ }
+
+ // count animation frames
+ for (i=0 ; i<count ; i++)
+ {
+ out = &loadmodel->texinfo[i];
+ out->numframes = 1;
+ for (step = out->next ; step && step != out ; step=step->next)
+ out->numframes++;
+ }
+}
+
+/*
+================
+CalcSurfaceExtents
+
+Fills in s->texturemins[] and s->extents[]
+================
+*/
+void CalcSurfaceExtents (msurface_t *s)
+{
+ float mins[2], maxs[2], val;
+ int i,j, e;
+ mvertex_t *v;
+ mtexinfo_t *tex;
+ int bmins[2], bmaxs[2];
+
+ mins[0] = mins[1] = 999999;
+ maxs[0] = maxs[1] = -99999;
+
+ tex = s->texinfo;
+
+ for (i=0 ; i<s->numedges ; i++)
+ {
+ e = loadmodel->surfedges[s->firstedge+i];
+ if (e >= 0)
+ v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
+ else
+ v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
+
+ for (j=0 ; j<2 ; j++)
+ {
+ val = v->position[0] * tex->vecs[j][0] +
+ v->position[1] * tex->vecs[j][1] +
+ v->position[2] * tex->vecs[j][2] +
+ tex->vecs[j][3];
+ if (val < mins[j])
+ mins[j] = val;
+ if (val > maxs[j])
+ maxs[j] = val;
+ }
+ }
+
+ for (i=0 ; i<2 ; i++)
+ {
+ bmins[i] = floor(mins[i]/16);
+ bmaxs[i] = ceil(maxs[i]/16);
+
+ s->texturemins[i] = bmins[i] * 16;
+ s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
+ if (s->extents[i] < 16)
+ s->extents[i] = 16; // take at least one cache block
+ if ( !(tex->flags & (SURF_WARP|SURF_SKY)) && s->extents[i] > 256)
+ ri.Sys_Error (ERR_DROP,"Bad surface extents");
+ }
+}
+
+
+/*
+=================
+Mod_LoadFaces
+=================
+*/
+void Mod_LoadFaces (lump_t *l)
+{
+ dface_t *in;
+ msurface_t *out;
+ int i, count, surfnum;
+ int planenum, side;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Hunk_Alloc ( (count+6)*sizeof(*out)); // extra for skybox
+
+ loadmodel->surfaces = out;
+ loadmodel->numsurfaces = count;
+
+ for ( surfnum=0 ; surfnum<count ; surfnum++, in++, out++)
+ {
+ out->firstedge = LittleLong(in->firstedge);
+ out->numedges = LittleShort(in->numedges);
+ if (out->numedges < 3)
+ ri.Sys_Error (ERR_DROP,"Surface with %s edges", out->numedges);
+ out->flags = 0;
+
+ planenum = LittleShort(in->planenum);
+ side = LittleShort(in->side);
+ if (side)
+ out->flags |= SURF_PLANEBACK;
+
+ out->plane = loadmodel->planes + planenum;
+
+ out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo);
+
+ CalcSurfaceExtents (out);
+
+ // lighting info is converted from 24 bit on disk to 8 bit
+
+ for (i=0 ; i<MAXLIGHTMAPS ; i++)
+ out->styles[i] = in->styles[i];
+ i = LittleLong(in->lightofs);
+ if (i == -1)
+ out->samples = NULL;
+ else
+ out->samples = loadmodel->lightdata + i/3;
+
+ // set the drawing flags flag
+
+ if (!out->texinfo->image)
+ continue;
+ if (out->texinfo->flags & SURF_SKY)
+ {
+ out->flags |= SURF_DRAWSKY;
+ continue;
+ }
+
+ if (out->texinfo->flags & SURF_WARP)
+ {
+ out->flags |= SURF_DRAWTURB;
+ for (i=0 ; i<2 ; i++)
+ {
+ out->extents[i] = 16384;
+ out->texturemins[i] = -8192;
+ }
+ continue;
+ }
+//==============
+//PGM
+ // this marks flowing surfaces as turbulent, but with the new
+ // SURF_FLOW flag.
+ if (out->texinfo->flags & SURF_FLOWING)
+ {
+ out->flags |= SURF_DRAWTURB | SURF_FLOW;
+ for (i=0 ; i<2 ; i++)
+ {
+ out->extents[i] = 16384;
+ out->texturemins[i] = -8192;
+ }
+ continue;
+ }
+//PGM
+//==============
+ }
+}
+
+
+/*
+=================
+Mod_SetParent
+=================
+*/
+void Mod_SetParent (mnode_t *node, mnode_t *parent)
+{
+ node->parent = parent;
+ if (node->contents != -1)
+ return;
+ Mod_SetParent (node->children[0], node);
+ Mod_SetParent (node->children[1], node);
+}
+
+/*
+=================
+Mod_LoadNodes
+=================
+*/
+void Mod_LoadNodes (lump_t *l)
+{
+ int i, j, count, p;
+ dnode_t *in;
+ mnode_t *out;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Hunk_Alloc ( count*sizeof(*out));
+
+ loadmodel->nodes = out;
+ loadmodel->numnodes = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ for (j=0 ; j<3 ; j++)
+ {
+ out->minmaxs[j] = LittleShort (in->mins[j]);
+ out->minmaxs[3+j] = LittleShort (in->maxs[j]);
+ }
+
+ p = LittleLong(in->planenum);
+ out->plane = loadmodel->planes + p;
+
+ out->firstsurface = LittleShort (in->firstface);
+ out->numsurfaces = LittleShort (in->numfaces);
+ out->contents = CONTENTS_NODE; // differentiate from leafs
+
+ for (j=0 ; j<2 ; j++)
+ {
+ p = LittleLong (in->children[j]);
+ if (p >= 0)
+ out->children[j] = loadmodel->nodes + p;
+ else
+ out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
+ }
+ }
+
+ Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
+}
+
+/*
+=================
+Mod_LoadLeafs
+=================
+*/
+void Mod_LoadLeafs (lump_t *l)
+{
+ dleaf_t *in;
+ mleaf_t *out;
+ int i, j, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Hunk_Alloc ( count*sizeof(*out));
+
+ loadmodel->leafs = out;
+ loadmodel->numleafs = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ for (j=0 ; j<3 ; j++)
+ {
+ out->minmaxs[j] = LittleShort (in->mins[j]);
+ out->minmaxs[3+j] = LittleShort (in->maxs[j]);
+ }
+
+ out->contents = LittleLong(in->contents);
+ out->cluster = LittleShort(in->cluster);
+ out->area = LittleShort(in->area);
+
+ out->firstmarksurface = loadmodel->marksurfaces +
+ LittleShort(in->firstleafface);
+ out->nummarksurfaces = LittleShort(in->numleaffaces);
+ }
+}
+
+
+/*
+=================
+Mod_LoadMarksurfaces
+=================
+*/
+void Mod_LoadMarksurfaces (lump_t *l)
+{
+ int i, j, count;
+ short *in;
+ msurface_t **out;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Hunk_Alloc ( count*sizeof(*out));
+
+ loadmodel->marksurfaces = out;
+ loadmodel->nummarksurfaces = count;
+
+ for ( i=0 ; i<count ; i++)
+ {
+ j = LittleShort(in[i]);
+ if (j >= loadmodel->numsurfaces)
+ ri.Sys_Error (ERR_DROP,"Mod_ParseMarksurfaces: bad surface number");
+ out[i] = loadmodel->surfaces + j;
+ }
+}
+
+/*
+=================
+Mod_LoadSurfedges
+=================
+*/
+void Mod_LoadSurfedges (lump_t *l)
+{
+ int i, count;
+ int *in, *out;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Hunk_Alloc ( (count+24)*sizeof(*out)); // extra for skybox
+
+ loadmodel->surfedges = out;
+ loadmodel->numsurfedges = count;
+
+ for ( i=0 ; i<count ; i++)
+ out[i] = LittleLong (in[i]);
+}
+
+/*
+=================
+Mod_LoadPlanes
+=================
+*/
+void Mod_LoadPlanes (lump_t *l)
+{
+ int i, j;
+ mplane_t *out;
+ dplane_t *in;
+ int count;
+ int bits;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = Hunk_Alloc ( (count+6)*sizeof(*out)); // extra for skybox
+
+ loadmodel->planes = out;
+ loadmodel->numplanes = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ bits = 0;
+ for (j=0 ; j<3 ; j++)
+ {
+ out->normal[j] = LittleFloat (in->normal[j]);
+ if (out->normal[j] < 0)
+ bits |= 1<<j;
+ }
+
+ out->dist = LittleFloat (in->dist);
+ out->type = LittleLong (in->type);
+ out->signbits = bits;
+ }
+}
+
+
+/*
+=================
+Mod_LoadBrushModel
+=================
+*/
+void Mod_LoadBrushModel (model_t *mod, void *buffer)
+{
+ int i;
+ dheader_t *header;
+ dmodel_t *bm;
+
+ loadmodel->type = mod_brush;
+ if (loadmodel != mod_known)
+ ri.Sys_Error (ERR_DROP, "Loaded a brush model after the world");
+
+ header = (dheader_t *)buffer;
+
+ i = LittleLong (header->version);
+ if (i != BSPVERSION)
+ ri.Sys_Error (ERR_DROP,"Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION);
+
+// swap all the lumps
+ mod_base = (byte *)header;
+
+ for (i=0 ; i<sizeof(dheader_t)/sizeof(int) ; i++)
+ ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
+
+// load into heap
+
+ Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
+ Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
+ Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
+ Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
+ Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
+ Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
+ Mod_LoadFaces (&header->lumps[LUMP_FACES]);
+ Mod_LoadMarksurfaces (&header->lumps[LUMP_LEAFFACES]);
+ Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
+ Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
+ Mod_LoadNodes (&header->lumps[LUMP_NODES]);
+ Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
+ r_numvisleafs = 0;
+ R_NumberLeafs (loadmodel->nodes);
+
+//
+// set up the submodels
+//
+ for (i=0 ; i<mod->numsubmodels ; i++)
+ {
+ model_t *starmod;
+
+ bm = &mod->submodels[i];
+ starmod = &mod_inline[i];
+
+ *starmod = *loadmodel;
+
+ starmod->firstmodelsurface = bm->firstface;
+ starmod->nummodelsurfaces = bm->numfaces;
+ starmod->firstnode = bm->headnode;
+ if (starmod->firstnode >= loadmodel->numnodes)
+ ri.Sys_Error (ERR_DROP, "Inline model %i has bad firstnode", i);
+
+ VectorCopy (bm->maxs, starmod->maxs);
+ VectorCopy (bm->mins, starmod->mins);
+
+ if (i == 0)
+ *loadmodel = *starmod;
+ }
+
+ R_InitSkyBox ();
+}
+
+/*
+==============================================================================
+
+ALIAS MODELS
+
+==============================================================================
+*/
+
+/*
+=================
+Mod_LoadAliasModel
+=================
+*/
+void Mod_LoadAliasModel (model_t *mod, void *buffer)
+{
+ int i, j;
+ dmdl_t *pinmodel, *pheader;
+ dstvert_t *pinst, *poutst;
+ dtriangle_t *pintri, *pouttri;
+ daliasframe_t *pinframe, *poutframe;
+ int *pincmd, *poutcmd;
+ int version;
+
+ pinmodel = (dmdl_t *)buffer;
+
+ version = LittleLong (pinmodel->version);
+ if (version != ALIAS_VERSION)
+ ri.Sys_Error (ERR_DROP, "%s has wrong version number (%i should be %i)",
+ mod->name, version, ALIAS_VERSION);
+
+ pheader = Hunk_Alloc (LittleLong(pinmodel->ofs_end));
+
+ // byte swap the header fields and sanity check
+ for (i=0 ; i<sizeof(dmdl_t)/sizeof(int) ; i++)
+ ((int *)pheader)[i] = LittleLong (((int *)buffer)[i]);
+
+ if (pheader->skinheight > MAX_LBM_HEIGHT)
+ ri.Sys_Error (ERR_DROP, "model %s has a skin taller than %d", mod->name,
+ MAX_LBM_HEIGHT);
+
+ if (pheader->num_xyz <= 0)
+ ri.Sys_Error (ERR_DROP, "model %s has no vertices", mod->name);
+
+ if (pheader->num_xyz > MAX_VERTS)
+ ri.Sys_Error (ERR_DROP, "model %s has too many vertices", mod->name);
+
+ if (pheader->num_st <= 0)
+ ri.Sys_Error (ERR_DROP, "model %s has no st vertices", mod->name);
+
+ if (pheader->num_tris <= 0)
+ ri.Sys_Error (ERR_DROP, "model %s has no triangles", mod->name);
+
+ if (pheader->num_frames <= 0)
+ ri.Sys_Error (ERR_DROP, "model %s has no frames", mod->name);
+
+//
+// load base s and t vertices (not used in gl version)
+//
+ pinst = (dstvert_t *) ((byte *)pinmodel + pheader->ofs_st);
+ poutst = (dstvert_t *) ((byte *)pheader + pheader->ofs_st);
+
+ for (i=0 ; i<pheader->num_st ; i++)
+ {
+ poutst[i].s = LittleShort (pinst[i].s);
+ poutst[i].t = LittleShort (pinst[i].t);
+ }
+
+//
+// load triangle lists
+//
+ pintri = (dtriangle_t *) ((byte *)pinmodel + pheader->ofs_tris);
+ pouttri = (dtriangle_t *) ((byte *)pheader + pheader->ofs_tris);
+
+ for (i=0 ; i<pheader->num_tris ; i++)
+ {
+ for (j=0 ; j<3 ; j++)
+ {
+ pouttri[i].index_xyz[j] = LittleShort (pintri[i].index_xyz[j]);
+ pouttri[i].index_st[j] = LittleShort (pintri[i].index_st[j]);
+ }
+ }
+
+//
+// load the frames
+//
+ for (i=0 ; i<pheader->num_frames ; i++)
+ {
+ pinframe = (daliasframe_t *) ((byte *)pinmodel
+ + pheader->ofs_frames + i * pheader->framesize);
+ poutframe = (daliasframe_t *) ((byte *)pheader
+ + pheader->ofs_frames + i * pheader->framesize);
+
+ memcpy (poutframe->name, pinframe->name, sizeof(poutframe->name));
+ for (j=0 ; j<3 ; j++)
+ {
+ poutframe->scale[j] = LittleFloat (pinframe->scale[j]);
+ poutframe->translate[j] = LittleFloat (pinframe->translate[j]);
+ }
+ // verts are all 8 bit, so no swapping needed
+ memcpy (poutframe->verts, pinframe->verts,
+ pheader->num_xyz*sizeof(dtrivertx_t));
+
+ }
+
+ mod->type = mod_alias;
+
+ //
+ // load the glcmds
+ //
+ pincmd = (int *) ((byte *)pinmodel + pheader->ofs_glcmds);
+ poutcmd = (int *) ((byte *)pheader + pheader->ofs_glcmds);
+ for (i=0 ; i<pheader->num_glcmds ; i++)
+ poutcmd[i] = LittleLong (pincmd[i]);
+
+
+ // register all skins
+ memcpy ((char *)pheader + pheader->ofs_skins, (char *)pinmodel + pheader->ofs_skins,
+ pheader->num_skins*MAX_SKINNAME);
+ for (i=0 ; i<pheader->num_skins ; i++)
+ {
+ mod->skins[i] = R_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME, it_skin);
+ }
+}
+
+/*
+==============================================================================
+
+SPRITE MODELS
+
+==============================================================================
+*/
+
+/*
+=================
+Mod_LoadSpriteModel
+=================
+*/
+void Mod_LoadSpriteModel (model_t *mod, void *buffer)
+{
+ dsprite_t *sprin, *sprout;
+ int i;
+
+ sprin = (dsprite_t *)buffer;
+ sprout = Hunk_Alloc (modfilelen);
+
+ sprout->ident = LittleLong (sprin->ident);
+ sprout->version = LittleLong (sprin->version);
+ sprout->numframes = LittleLong (sprin->numframes);
+
+ if (sprout->version != SPRITE_VERSION)
+ ri.Sys_Error (ERR_DROP, "%s has wrong version number (%i should be %i)",
+ mod->name, sprout->version, SPRITE_VERSION);
+
+ if (sprout->numframes > MAX_MD2SKINS)
+ ri.Sys_Error (ERR_DROP, "%s has too many frames (%i > %i)",
+ mod->name, sprout->numframes, MAX_MD2SKINS);
+
+ // byte swap everything
+ for (i=0 ; i<sprout->numframes ; i++)
+ {
+ sprout->frames[i].width = LittleLong (sprin->frames[i].width);
+ sprout->frames[i].height = LittleLong (sprin->frames[i].height);
+ sprout->frames[i].origin_x = LittleLong (sprin->frames[i].origin_x);
+ sprout->frames[i].origin_y = LittleLong (sprin->frames[i].origin_y);
+ memcpy (sprout->frames[i].name, sprin->frames[i].name, MAX_SKINNAME);
+ mod->skins[i] = R_FindImage (sprout->frames[i].name, it_sprite);
+ }
+
+ mod->type = mod_sprite;
+}
+
+//=============================================================================
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+R_BeginRegistration
+
+Specifies the model that will be used as the world
+@@@@@@@@@@@@@@@@@@@@@
+*/
+void R_BeginRegistration (char *model)
+{
+ char fullname[MAX_QPATH];
+ cvar_t *flushmap;
+
+ registration_sequence++;
+ r_oldviewcluster = -1; // force markleafs
+ Com_sprintf (fullname, sizeof(fullname), "maps/%s.bsp", model);
+
+ D_FlushCaches ();
+ // explicitly free the old map if different
+ // this guarantees that mod_known[0] is the world map
+ flushmap = ri.Cvar_Get ("flushmap", "0", 0);
+ if ( strcmp(mod_known[0].name, fullname) || flushmap->value)
+ Mod_Free (&mod_known[0]);
+ r_worldmodel = R_RegisterModel (fullname);
+ R_NewMap ();
+}
+
+model_t *
+R_RegisterModel(char *name)
+{
+ model_t *mod;
+ int i;
+ dsprite_t *sprout;
+ dmdl_t *pheader;
+
+ mod = Mod_ForName (name, false);
+ if (mod)
+ {
+ mod->registration_sequence = registration_sequence;
+
+ // register any images used by the models
+ if (mod->type == mod_sprite)
+ {
+ sprout = (dsprite_t *)mod->extradata;
+ for (i=0 ; i<sprout->numframes ; i++)
+ mod->skins[i] = R_FindImage (sprout->frames[i].name, it_sprite);
+ }
+ else if (mod->type == mod_alias)
+ {
+ pheader = (dmdl_t *)mod->extradata;
+ for (i=0 ; i<pheader->num_skins ; i++)
+ mod->skins[i] = R_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME, it_skin);
+//PGM
+ mod->numframes = pheader->num_frames;
+//PGM
+ }
+ else if (mod->type == mod_brush)
+ {
+ for (i=0 ; i<mod->numtexinfo ; i++)
+ mod->texinfo[i].image->registration_sequence = registration_sequence;
+ }
+ }
+ return mod;
+}
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+R_EndRegistration
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+void R_EndRegistration (void)
+{
+ int i;
+ model_t *mod;
+
+ for (i=0, mod=mod_known ; i<mod_numknown ; i++, mod++)
+ {
+ if (!mod->name[0])
+ continue;
+ if (mod->registration_sequence != registration_sequence)
+ { // don't need this model
+ Hunk_Free (mod->extradata);
+ memset (mod, 0, sizeof(*mod));
+ }
+ else
+ { // make sure it is paged in
+ Com_PageInMemory (mod->extradata, mod->extradatasize);
+ }
+ }
+
+ R_FreeUnusedImages ();
+}
+
+void
+Mod_Free(model_t *mod)
+{
+ Hunk_Free(mod->extradata);
+ memset(mod, 0, sizeof *mod);
+}
+
+void
+Mod_FreeAll(void)
+{
+ int i;
+
+ for(i=0; i<mod_numknown; i++){
+ if(mod_known[i].extradatasize)
+ Mod_Free(&mod_known[i]);
+ }
+}
--- /dev/null
+++ b/r_part.c
@@ -1,0 +1,204 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+vec3_t r_pright, r_pup, r_ppn;
+
+#define PARTICLE_33 0
+#define PARTICLE_66 1
+#define PARTICLE_OPAQUE 2
+
+typedef struct
+{
+ particle_t *particle;
+ int level;
+ int color;
+} partparms_t;
+
+static partparms_t partparms;
+
+static byte BlendParticle33( int pcolor, int dstcolor )
+{
+ return vid.alphamap[pcolor + dstcolor*256];
+}
+
+static byte BlendParticle66( int pcolor, int dstcolor )
+{
+ return vid.alphamap[pcolor*256+dstcolor];
+}
+
+static byte BlendParticle100( int pcolor, int /*dstcolor*/ )
+{
+ return pcolor;
+}
+
+/*
+** R_DrawParticle
+**
+** Yes, this is amazingly slow, but it's the C reference
+** implementation and should be both robust and vaguely
+** understandable. The only time this path should be
+** executed is if we're debugging on x86 or if we're
+** recompiling and deploying on a non-x86 platform.
+**
+** To minimize error and improve readability I went the
+** function pointer route. This exacts some overhead, but
+** it pays off in clean and easy to understand code.
+*/
+void R_DrawParticle( void )
+{
+ particle_t *pparticle = partparms.particle;
+ int level = partparms.level;
+ vec3_t local, transformed;
+ float zi;
+ byte *pdest;
+ short *pz;
+ int color = pparticle->color;
+ int i, izi, pix, count, u, v;
+
+ /*
+ ** transform the particle
+ */
+ VectorSubtract (pparticle->origin, r_origin, local);
+
+ transformed[0] = DotProduct(local, r_pright);
+ transformed[1] = DotProduct(local, r_pup);
+ transformed[2] = DotProduct(local, r_ppn);
+
+ if (transformed[2] < PARTICLE_Z_CLIP)
+ return;
+
+ /*
+ ** bind the blend function pointer to the appropriate blender
+ */
+ /*
+ byte (*blendparticle)( int, int );
+ if ( level == PARTICLE_33 )
+ blendparticle = BlendParticle33;
+ else if ( level == PARTICLE_66 )
+ blendparticle = BlendParticle66;
+ else
+ blendparticle = BlendParticle100;
+ */
+
+ /*
+ ** project the point
+ */
+ // FIXME: preadjust xcenter and ycenter
+ zi = 1.0 / transformed[2];
+ u = (int)(xcenter + zi * transformed[0] + 0.5);
+ v = (int)(ycenter - zi * transformed[1] + 0.5);
+
+ if ((v > d_vrectbottom_particle) ||
+ (u > d_vrectright_particle) ||
+ (v < d_vrecty) ||
+ (u < d_vrectx))
+ {
+ return;
+ }
+
+ /*
+ ** compute addresses of zbuffer, framebuffer, and
+ ** compute the Z-buffer reference value.
+ */
+ pz = d_pzbuffer + (d_zwidth * v) + u;
+ pdest = d_viewbuffer + d_scantable[v] + u;
+ izi = (int)(zi * 0x8000);
+
+ /*
+ ** determine the screen area covered by the particle,
+ ** which also means clamping to a min and max
+ */
+ pix = izi >> d_pix_shift;
+ if (pix < d_pix_min)
+ pix = d_pix_min;
+ else if (pix > d_pix_max)
+ pix = d_pix_max;
+
+ /*
+ ** render the appropriate pixels
+ */
+ count = pix;
+
+ switch (level) {
+ case PARTICLE_33 :
+ for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth)
+ {
+//FIXME--do it in blocks of 8?
+ for (i=0 ; i<pix ; i++)
+ {
+ if (pz[i] <= izi)
+ {
+ pz[i] = izi;
+ pdest[i] = vid.alphamap[color + ((int)pdest[i]<<8)];
+ }
+ }
+ }
+ break;
+
+ case PARTICLE_66 :
+ for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth)
+ {
+ for (i=0 ; i<pix ; i++)
+ {
+ if (pz[i] <= izi)
+ {
+ pz[i] = izi;
+ pdest[i] = vid.alphamap[(color<<8) + (int)pdest[i]];
+ }
+ }
+ }
+ break;
+
+ default: //100
+ for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth)
+ {
+ for (i=0 ; i<pix ; i++)
+ {
+ if (pz[i] <= izi)
+ {
+ pz[i] = izi;
+ pdest[i] = color;
+ }
+ }
+ }
+ break;
+ }
+}
+
+/*
+** R_DrawParticles
+**
+** Responsible for drawing all of the particles in the particle list
+** throughout the world. Doesn't care if we're using the C path or
+** if we're using the asm path, it simply assigns a function pointer
+** and goes.
+*/
+void R_DrawParticles (void)
+{
+ particle_t *p;
+ int i;
+ extern unsigned long fpu_sp24_cw, fpu_chop_cw;
+
+ VectorScale( vright, xscaleshrink, r_pright );
+ VectorScale( vup, yscaleshrink, r_pup );
+ VectorCopy( vpn, r_ppn );
+
+ for (p=r_newrefdef.particles, i=0 ; i<r_newrefdef.num_particles ; i++,p++)
+ {
+
+ if ( p->alpha > 0.66 )
+ partparms.level = PARTICLE_OPAQUE;
+ else if ( p->alpha > 0.33 )
+ partparms.level = PARTICLE_66;
+ else
+ partparms.level = PARTICLE_33;
+
+ partparms.particle = p;
+ partparms.color = p->color;
+
+ R_DrawParticle();
+ }
+}
--- /dev/null
+++ b/r_poly.c
@@ -1,0 +1,1226 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+#define AFFINE_SPANLET_SIZE 16
+#define AFFINE_SPANLET_SIZE_BITS 4
+
+typedef struct
+{
+ byte *pbase, *pdest;
+ short *pz;
+ fixed16_t s, t;
+ fixed16_t sstep, tstep;
+ int izi, izistep, izistep_times_2;
+ int spancount;
+ unsigned u, v;
+} spanletvars_t;
+
+spanletvars_t s_spanletvars;
+
+static int r_polyblendcolor;
+
+static espan_t *s_polygon_spans;
+
+polydesc_t r_polydesc;
+
+msurface_t *r_alpha_surfaces;
+
+extern int *r_turb_turb;
+
+static int clip_current;
+vec5_t r_clip_verts[2][MAXWORKINGVERTS+2];
+
+static int s_minindex, s_maxindex;
+
+static void R_DrawPoly( qboolean iswater );
+
+/*
+** R_DrawSpanletOpaque
+*/
+void R_DrawSpanletOpaque( void )
+{
+ unsigned btemp;
+
+ do
+ {
+ unsigned ts, tt;
+
+ ts = s_spanletvars.s >> 16;
+ tt = s_spanletvars.t >> 16;
+
+ btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth);
+ if (btemp != 255)
+ {
+ if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
+ {
+ *s_spanletvars.pz = s_spanletvars.izi >> 16;
+ *s_spanletvars.pdest = btemp;
+ }
+ }
+
+ s_spanletvars.izi += s_spanletvars.izistep;
+ s_spanletvars.pdest++;
+ s_spanletvars.pz++;
+ s_spanletvars.s += s_spanletvars.sstep;
+ s_spanletvars.t += s_spanletvars.tstep;
+ } while (--s_spanletvars.spancount > 0);
+}
+
+/*
+** R_DrawSpanletTurbulentStipple33
+*/
+void R_DrawSpanletTurbulentStipple33( void )
+{
+ unsigned btemp;
+ int sturb, tturb;
+ byte *pdest = s_spanletvars.pdest;
+ short *pz = s_spanletvars.pz;
+ int izi = s_spanletvars.izi;
+
+ if ( s_spanletvars.v & 1 )
+ {
+ s_spanletvars.pdest += s_spanletvars.spancount;
+ s_spanletvars.pz += s_spanletvars.spancount;
+
+ if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
+ s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
+ else
+ s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
+
+ if ( s_spanletvars.u & 1 )
+ {
+ izi += s_spanletvars.izistep;
+ s_spanletvars.s += s_spanletvars.sstep;
+ s_spanletvars.t += s_spanletvars.tstep;
+
+ pdest++;
+ pz++;
+ s_spanletvars.spancount--;
+ }
+
+ s_spanletvars.sstep *= 2;
+ s_spanletvars.tstep *= 2;
+
+ while ( s_spanletvars.spancount > 0 )
+ {
+ sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
+ tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
+
+ btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
+
+ if ( *pz <= ( izi >> 16 ) )
+ *pdest = btemp;
+
+ izi += s_spanletvars.izistep_times_2;
+ s_spanletvars.s += s_spanletvars.sstep;
+ s_spanletvars.t += s_spanletvars.tstep;
+
+ pdest += 2;
+ pz += 2;
+
+ s_spanletvars.spancount -= 2;
+ }
+ }
+}
+
+/*
+** R_DrawSpanletTurbulentStipple66
+*/
+void R_DrawSpanletTurbulentStipple66( void )
+{
+ unsigned btemp;
+ int sturb, tturb;
+ byte *pdest = s_spanletvars.pdest;
+ short *pz = s_spanletvars.pz;
+ int izi = s_spanletvars.izi;
+
+ if ( !( s_spanletvars.v & 1 ) )
+ {
+ s_spanletvars.pdest += s_spanletvars.spancount;
+ s_spanletvars.pz += s_spanletvars.spancount;
+
+ if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
+ s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
+ else
+ s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
+
+ if ( s_spanletvars.u & 1 )
+ {
+ izi += s_spanletvars.izistep;
+ s_spanletvars.s += s_spanletvars.sstep;
+ s_spanletvars.t += s_spanletvars.tstep;
+
+ pdest++;
+ pz++;
+ s_spanletvars.spancount--;
+ }
+
+ s_spanletvars.sstep *= 2;
+ s_spanletvars.tstep *= 2;
+
+ while ( s_spanletvars.spancount > 0 )
+ {
+ sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
+ tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
+
+ btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
+
+ if ( *pz <= ( izi >> 16 ) )
+ *pdest = btemp;
+
+ izi += s_spanletvars.izistep_times_2;
+ s_spanletvars.s += s_spanletvars.sstep;
+ s_spanletvars.t += s_spanletvars.tstep;
+
+ pdest += 2;
+ pz += 2;
+
+ s_spanletvars.spancount -= 2;
+ }
+ }
+ else
+ {
+ s_spanletvars.pdest += s_spanletvars.spancount;
+ s_spanletvars.pz += s_spanletvars.spancount;
+
+ if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
+ s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
+ else
+ s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
+
+ while ( s_spanletvars.spancount > 0 )
+ {
+ sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
+ tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
+
+ btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
+
+ if ( *pz <= ( izi >> 16 ) )
+ *pdest = btemp;
+
+ izi += s_spanletvars.izistep;
+ s_spanletvars.s += s_spanletvars.sstep;
+ s_spanletvars.t += s_spanletvars.tstep;
+
+ pdest++;
+ pz++;
+
+ s_spanletvars.spancount--;
+ }
+ }
+}
+
+/*
+** R_DrawSpanletTurbulentBlended
+*/
+void R_DrawSpanletTurbulentBlended66( void )
+{
+ unsigned btemp;
+ int sturb, tturb;
+
+ do
+ {
+ sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
+ tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
+
+ btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
+
+ if ( *s_spanletvars.pz <= ( s_spanletvars.izi >> 16 ) )
+ *s_spanletvars.pdest = vid.alphamap[btemp*256+*s_spanletvars.pdest];
+
+ s_spanletvars.izi += s_spanletvars.izistep;
+ s_spanletvars.pdest++;
+ s_spanletvars.pz++;
+ s_spanletvars.s += s_spanletvars.sstep;
+ s_spanletvars.t += s_spanletvars.tstep;
+
+ } while ( --s_spanletvars.spancount > 0 );
+}
+
+void R_DrawSpanletTurbulentBlended33( void )
+{
+ unsigned btemp;
+ int sturb, tturb;
+
+ do
+ {
+ sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
+ tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
+
+ btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
+
+ if ( *s_spanletvars.pz <= ( s_spanletvars.izi >> 16 ) )
+ *s_spanletvars.pdest = vid.alphamap[btemp+*s_spanletvars.pdest*256];
+
+ s_spanletvars.izi += s_spanletvars.izistep;
+ s_spanletvars.pdest++;
+ s_spanletvars.pz++;
+ s_spanletvars.s += s_spanletvars.sstep;
+ s_spanletvars.t += s_spanletvars.tstep;
+
+ } while ( --s_spanletvars.spancount > 0 );
+}
+
+/*
+** R_DrawSpanlet33
+*/
+void R_DrawSpanlet33( void )
+{
+ unsigned btemp;
+
+ do
+ {
+ unsigned ts, tt;
+
+ ts = s_spanletvars.s >> 16;
+ tt = s_spanletvars.t >> 16;
+
+ btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth);
+
+ if ( btemp != 255 )
+ {
+ if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
+ {
+ *s_spanletvars.pdest = vid.alphamap[btemp+*s_spanletvars.pdest*256];
+ }
+ }
+
+ s_spanletvars.izi += s_spanletvars.izistep;
+ s_spanletvars.pdest++;
+ s_spanletvars.pz++;
+ s_spanletvars.s += s_spanletvars.sstep;
+ s_spanletvars.t += s_spanletvars.tstep;
+ } while (--s_spanletvars.spancount > 0);
+}
+
+void R_DrawSpanletConstant33( void )
+{
+ do
+ {
+ if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
+ {
+ *s_spanletvars.pdest = vid.alphamap[r_polyblendcolor+*s_spanletvars.pdest*256];
+ }
+
+ s_spanletvars.izi += s_spanletvars.izistep;
+ s_spanletvars.pdest++;
+ s_spanletvars.pz++;
+ } while (--s_spanletvars.spancount > 0);
+}
+
+/*
+** R_DrawSpanlet66
+*/
+void R_DrawSpanlet66( void )
+{
+ unsigned btemp;
+
+ do
+ {
+ unsigned ts, tt;
+
+ ts = s_spanletvars.s >> 16;
+ tt = s_spanletvars.t >> 16;
+
+ btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth);
+
+ if ( btemp != 255 )
+ {
+ if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
+ {
+ *s_spanletvars.pdest = vid.alphamap[btemp*256+*s_spanletvars.pdest];
+ }
+ }
+
+ s_spanletvars.izi += s_spanletvars.izistep;
+ s_spanletvars.pdest++;
+ s_spanletvars.pz++;
+ s_spanletvars.s += s_spanletvars.sstep;
+ s_spanletvars.t += s_spanletvars.tstep;
+ } while (--s_spanletvars.spancount > 0);
+}
+
+/*
+** R_DrawSpanlet33Stipple
+*/
+void R_DrawSpanlet33Stipple( void )
+{
+ unsigned btemp;
+ byte *pdest = s_spanletvars.pdest;
+ short *pz = s_spanletvars.pz;
+ int izi = s_spanletvars.izi;
+
+ if ( r_polydesc.stipple_parity ^ ( s_spanletvars.v & 1 ) )
+ {
+ s_spanletvars.pdest += s_spanletvars.spancount;
+ s_spanletvars.pz += s_spanletvars.spancount;
+
+ if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
+ s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
+ else
+ s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
+
+ if ( r_polydesc.stipple_parity ^ ( s_spanletvars.u & 1 ) )
+ {
+ izi += s_spanletvars.izistep;
+ s_spanletvars.s += s_spanletvars.sstep;
+ s_spanletvars.t += s_spanletvars.tstep;
+
+ pdest++;
+ pz++;
+ s_spanletvars.spancount--;
+ }
+
+ s_spanletvars.sstep *= 2;
+ s_spanletvars.tstep *= 2;
+
+ while ( s_spanletvars.spancount > 0 )
+ {
+ unsigned s = s_spanletvars.s >> 16;
+ unsigned t = s_spanletvars.t >> 16;
+
+ btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) );
+
+ if ( btemp != 255 )
+ {
+ if ( *pz <= ( izi >> 16 ) )
+ *pdest = btemp;
+ }
+
+ izi += s_spanletvars.izistep_times_2;
+ s_spanletvars.s += s_spanletvars.sstep;
+ s_spanletvars.t += s_spanletvars.tstep;
+
+ pdest += 2;
+ pz += 2;
+
+ s_spanletvars.spancount -= 2;
+ }
+ }
+}
+
+/*
+** R_DrawSpanlet66Stipple
+*/
+void R_DrawSpanlet66Stipple( void )
+{
+ unsigned btemp;
+ byte *pdest = s_spanletvars.pdest;
+ short *pz = s_spanletvars.pz;
+ int izi = s_spanletvars.izi;
+
+ s_spanletvars.pdest += s_spanletvars.spancount;
+ s_spanletvars.pz += s_spanletvars.spancount;
+
+ if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
+ s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
+ else
+ s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
+
+ if ( r_polydesc.stipple_parity ^ ( s_spanletvars.v & 1 ) )
+ {
+ if ( r_polydesc.stipple_parity ^ ( s_spanletvars.u & 1 ) )
+ {
+ izi += s_spanletvars.izistep;
+ s_spanletvars.s += s_spanletvars.sstep;
+ s_spanletvars.t += s_spanletvars.tstep;
+
+ pdest++;
+ pz++;
+ s_spanletvars.spancount--;
+ }
+
+ s_spanletvars.sstep *= 2;
+ s_spanletvars.tstep *= 2;
+
+ while ( s_spanletvars.spancount > 0 )
+ {
+ unsigned s = s_spanletvars.s >> 16;
+ unsigned t = s_spanletvars.t >> 16;
+
+ btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) );
+
+ if ( btemp != 255 )
+ {
+ if ( *pz <= ( izi >> 16 ) )
+ *pdest = btemp;
+ }
+
+ izi += s_spanletvars.izistep_times_2;
+ s_spanletvars.s += s_spanletvars.sstep;
+ s_spanletvars.t += s_spanletvars.tstep;
+
+ pdest += 2;
+ pz += 2;
+
+ s_spanletvars.spancount -= 2;
+ }
+ }
+ else
+ {
+ while ( s_spanletvars.spancount > 0 )
+ {
+ unsigned s = s_spanletvars.s >> 16;
+ unsigned t = s_spanletvars.t >> 16;
+
+ btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) );
+
+ if ( btemp != 255 )
+ {
+ if ( *pz <= ( izi >> 16 ) )
+ *pdest = btemp;
+ }
+
+ izi += s_spanletvars.izistep;
+ s_spanletvars.s += s_spanletvars.sstep;
+ s_spanletvars.t += s_spanletvars.tstep;
+
+ pdest++;
+ pz++;
+
+ s_spanletvars.spancount--;
+ }
+ }
+}
+
+/*
+** R_ClipPolyFace
+**
+** Clips the winding at clip_verts[clip_current] and changes clip_current
+** Throws out the back side
+*/
+int R_ClipPolyFace (int nump, clipplane_t *pclipplane)
+{
+ int i, outcount;
+ float dists[MAXWORKINGVERTS+3];
+ float frac, clipdist, *pclipnormal;
+ float *in, *instep, *outstep, *vert2;
+
+ clipdist = pclipplane->dist;
+ pclipnormal = pclipplane->normal;
+
+// calc dists
+ if (clip_current)
+ {
+ in = r_clip_verts[1][0];
+ outstep = r_clip_verts[0][0];
+ clip_current = 0;
+ }
+ else
+ {
+ in = r_clip_verts[0][0];
+ outstep = r_clip_verts[1][0];
+ clip_current = 1;
+ }
+
+ instep = in;
+ for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
+ {
+ dists[i] = DotProduct (instep, pclipnormal) - clipdist;
+ }
+
+// handle wraparound case
+ dists[nump] = dists[0];
+ memcpy (instep, in, sizeof (vec5_t));
+
+
+// clip the winding
+ instep = in;
+ outcount = 0;
+
+ for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
+ {
+ if (dists[i] >= 0)
+ {
+ memcpy (outstep, instep, sizeof (vec5_t));
+ outstep += sizeof (vec5_t) / sizeof (float);
+ outcount++;
+ }
+
+ if (dists[i] == 0 || dists[i+1] == 0)
+ continue;
+
+ if ( (dists[i] > 0) == (dists[i+1] > 0) )
+ continue;
+
+ // split it into a new vertex
+ frac = dists[i] / (dists[i] - dists[i+1]);
+
+ vert2 = instep + sizeof (vec5_t) / sizeof (float);
+
+ outstep[0] = instep[0] + frac*(vert2[0] - instep[0]);
+ outstep[1] = instep[1] + frac*(vert2[1] - instep[1]);
+ outstep[2] = instep[2] + frac*(vert2[2] - instep[2]);
+ outstep[3] = instep[3] + frac*(vert2[3] - instep[3]);
+ outstep[4] = instep[4] + frac*(vert2[4] - instep[4]);
+
+ outstep += sizeof (vec5_t) / sizeof (float);
+ outcount++;
+ }
+
+ return outcount;
+}
+
+/*
+** R_PolygonDrawSpans
+*/
+void R_PolygonDrawSpans(espan_t *pspan, qboolean iswater )
+{
+ int count;
+ fixed16_t snext, tnext;
+ float sdivz, tdivz, zi, z, du, dv, spancountminus1;
+ float sdivzspanletstepu, tdivzspanletstepu, zispanletstepu;
+
+ s_spanletvars.pbase = cacheblock;
+
+ if ( iswater )
+ r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
+
+ sdivzspanletstepu = d_sdivzstepu * AFFINE_SPANLET_SIZE;
+ tdivzspanletstepu = d_tdivzstepu * AFFINE_SPANLET_SIZE;
+ zispanletstepu = d_zistepu * AFFINE_SPANLET_SIZE;
+
+// we count on FP exceptions being turned off to avoid range problems
+ s_spanletvars.izistep = (int)(d_zistepu * 0x8000 * 0x10000);
+ s_spanletvars.izistep_times_2 = s_spanletvars.izistep * 2;
+
+ s_spanletvars.pz = 0;
+
+ do
+ {
+ s_spanletvars.pdest = (byte *)d_viewbuffer + ( d_scantable[pspan->v] /*r_screenwidth * pspan->v*/) + pspan->u;
+ s_spanletvars.pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
+ s_spanletvars.u = pspan->u;
+ s_spanletvars.v = pspan->v;
+
+ count = pspan->count;
+
+ if (count <= 0)
+ goto NextSpan;
+
+ // calculate the initial s/z, t/z, 1/z, s, and t and clamp
+ du = (float)pspan->u;
+ dv = (float)pspan->v;
+
+ sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
+ tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
+
+ zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
+ z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
+ // we count on FP exceptions being turned off to avoid range problems
+ s_spanletvars.izi = (int)(zi * 0x8000 * 0x10000);
+
+ s_spanletvars.s = (int)(sdivz * z) + sadjust;
+ s_spanletvars.t = (int)(tdivz * z) + tadjust;
+
+ if ( !iswater )
+ {
+ if (s_spanletvars.s > bbextents)
+ s_spanletvars.s = bbextents;
+ else if (s_spanletvars.s < 0)
+ s_spanletvars.s = 0;
+
+ if (s_spanletvars.t > bbextentt)
+ s_spanletvars.t = bbextentt;
+ else if (s_spanletvars.t < 0)
+ s_spanletvars.t = 0;
+ }
+
+ do
+ {
+ // calculate s and t at the far end of the span
+ if (count >= AFFINE_SPANLET_SIZE )
+ s_spanletvars.spancount = AFFINE_SPANLET_SIZE;
+ else
+ s_spanletvars.spancount = count;
+
+ count -= s_spanletvars.spancount;
+
+ if (count)
+ {
+ // calculate s/z, t/z, zi->fixed s and t at far end of span,
+ // calculate s and t steps across span by shifting
+ sdivz += sdivzspanletstepu;
+ tdivz += tdivzspanletstepu;
+ zi += zispanletstepu;
+ z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
+
+ snext = (int)(sdivz * z) + sadjust;
+ tnext = (int)(tdivz * z) + tadjust;
+
+ if ( !iswater )
+ {
+ if (snext > bbextents)
+ snext = bbextents;
+ else if (snext < AFFINE_SPANLET_SIZE)
+ snext = AFFINE_SPANLET_SIZE; // prevent round-off error on <0 steps from
+ // from causing overstepping & running off the
+ // edge of the texture
+
+ if (tnext > bbextentt)
+ tnext = bbextentt;
+ else if (tnext < AFFINE_SPANLET_SIZE)
+ tnext = AFFINE_SPANLET_SIZE; // guard against round-off error on <0 steps
+ }
+
+ s_spanletvars.sstep = (snext - s_spanletvars.s) >> AFFINE_SPANLET_SIZE_BITS;
+ s_spanletvars.tstep = (tnext - s_spanletvars.t) >> AFFINE_SPANLET_SIZE_BITS;
+ }
+ else
+ {
+ // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
+ // can't step off polygon), clamp, calculate s and t steps across
+ // span by division, biasing steps low so we don't run off the
+ // texture
+ spancountminus1 = (float)(s_spanletvars.spancount - 1);
+ sdivz += d_sdivzstepu * spancountminus1;
+ tdivz += d_tdivzstepu * spancountminus1;
+ zi += d_zistepu * spancountminus1;
+ z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
+ snext = (int)(sdivz * z) + sadjust;
+ tnext = (int)(tdivz * z) + tadjust;
+
+ if ( !iswater )
+ {
+ if (snext > bbextents)
+ snext = bbextents;
+ else if (snext < AFFINE_SPANLET_SIZE)
+ snext = AFFINE_SPANLET_SIZE; // prevent round-off error on <0 steps from
+ // from causing overstepping & running off the
+ // edge of the texture
+
+ if (tnext > bbextentt)
+ tnext = bbextentt;
+ else if (tnext < AFFINE_SPANLET_SIZE)
+ tnext = AFFINE_SPANLET_SIZE; // guard against round-off error on <0 steps
+ }
+
+ if (s_spanletvars.spancount > 1)
+ {
+ s_spanletvars.sstep = (snext - s_spanletvars.s) / (s_spanletvars.spancount - 1);
+ s_spanletvars.tstep = (tnext - s_spanletvars.t) / (s_spanletvars.spancount - 1);
+ }
+ }
+
+ if ( iswater )
+ {
+ s_spanletvars.s = s_spanletvars.s & ((CYCLE<<16)-1);
+ s_spanletvars.t = s_spanletvars.t & ((CYCLE<<16)-1);
+ }
+
+ r_polydesc.drawspanlet();
+
+ s_spanletvars.s = snext;
+ s_spanletvars.t = tnext;
+
+ } while (count > 0);
+
+NextSpan:
+ pspan++;
+
+ } while (pspan->count != DS_SPAN_LIST_END);
+}
+
+/*
+**
+** R_PolygonScanLeftEdge
+**
+** Goes through the polygon and scans the left edge, filling in
+** screen coordinate data for the spans
+*/
+void R_PolygonScanLeftEdge (void)
+{
+ int i, v, itop, ibottom, lmaxindex;
+ emitpoint_t *pvert, *pnext;
+ espan_t *pspan;
+ float du, dv, vtop, vbottom, slope;
+ fixed16_t u, u_step;
+
+ pspan = s_polygon_spans;
+ i = s_minindex;
+ if (i == 0)
+ i = r_polydesc.nump;
+
+ lmaxindex = s_maxindex;
+ if (lmaxindex == 0)
+ lmaxindex = r_polydesc.nump;
+
+ vtop = ceil (r_polydesc.pverts[i].v);
+
+ do
+ {
+ pvert = &r_polydesc.pverts[i];
+ pnext = pvert - 1;
+
+ vbottom = ceil (pnext->v);
+
+ if (vtop < vbottom)
+ {
+ du = pnext->u - pvert->u;
+ dv = pnext->v - pvert->v;
+
+ slope = du / dv;
+ u_step = (int)(slope * 0x10000);
+ // adjust u to ceil the integer portion
+ u = (int)((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) +
+ (0x10000 - 1);
+ itop = (int)vtop;
+ ibottom = (int)vbottom;
+
+ for (v=itop ; v<ibottom ; v++)
+ {
+ pspan->u = u >> 16;
+ pspan->v = v;
+ u += u_step;
+ pspan++;
+ }
+ }
+
+ vtop = vbottom;
+
+ i--;
+ if (i == 0)
+ i = r_polydesc.nump;
+
+ } while (i != lmaxindex);
+}
+
+/*
+** R_PolygonScanRightEdge
+**
+** Goes through the polygon and scans the right edge, filling in
+** count values.
+*/
+void R_PolygonScanRightEdge (void)
+{
+ int i, v, itop, ibottom;
+ emitpoint_t *pvert, *pnext;
+ espan_t *pspan;
+ float du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext;
+ fixed16_t u, u_step;
+
+ pspan = s_polygon_spans;
+ i = s_minindex;
+
+ vvert = r_polydesc.pverts[i].v;
+ if (vvert < r_refdef.fvrecty_adj)
+ vvert = r_refdef.fvrecty_adj;
+ if (vvert > r_refdef.fvrectbottom_adj)
+ vvert = r_refdef.fvrectbottom_adj;
+
+ vtop = ceil (vvert);
+
+ do
+ {
+ pvert = &r_polydesc.pverts[i];
+ pnext = pvert + 1;
+
+ vnext = pnext->v;
+ if (vnext < r_refdef.fvrecty_adj)
+ vnext = r_refdef.fvrecty_adj;
+ if (vnext > r_refdef.fvrectbottom_adj)
+ vnext = r_refdef.fvrectbottom_adj;
+
+ vbottom = ceil (vnext);
+
+ if (vtop < vbottom)
+ {
+ uvert = pvert->u;
+ if (uvert < r_refdef.fvrectx_adj)
+ uvert = r_refdef.fvrectx_adj;
+ if (uvert > r_refdef.fvrectright_adj)
+ uvert = r_refdef.fvrectright_adj;
+
+ unext = pnext->u;
+ if (unext < r_refdef.fvrectx_adj)
+ unext = r_refdef.fvrectx_adj;
+ if (unext > r_refdef.fvrectright_adj)
+ unext = r_refdef.fvrectright_adj;
+
+ du = unext - uvert;
+ dv = vnext - vvert;
+ slope = du / dv;
+ u_step = (int)(slope * 0x10000);
+ // adjust u to ceil the integer portion
+ u = (int)((uvert + (slope * (vtop - vvert))) * 0x10000) +
+ (0x10000 - 1);
+ itop = (int)vtop;
+ ibottom = (int)vbottom;
+
+ for (v=itop ; v<ibottom ; v++)
+ {
+ pspan->count = (u >> 16) - pspan->u;
+ u += u_step;
+ pspan++;
+ }
+ }
+
+ vtop = vbottom;
+ vvert = vnext;
+
+ i++;
+ if (i == r_polydesc.nump)
+ i = 0;
+
+ } while (i != s_maxindex);
+
+ pspan->count = DS_SPAN_LIST_END; // mark the end of the span list
+}
+
+/*
+** R_ClipAndDrawPoly
+*/
+void R_ClipAndDrawPoly( float alpha, qboolean isturbulent, qboolean textured )
+{
+ emitpoint_t outverts[MAXWORKINGVERTS+3], *pout;
+ float *pv;
+ int i, nump;
+ float scale;
+ vec3_t transformed, local;
+
+ if ( !textured )
+ {
+ r_polydesc.drawspanlet = R_DrawSpanletConstant33;
+ }
+ else
+ {
+
+ /*
+ ** choose the correct spanlet routine based on alpha
+ */
+ if ( alpha == 1 )
+ {
+ // isturbulent is ignored because we know that turbulent surfaces
+ // can't be opaque
+ r_polydesc.drawspanlet = R_DrawSpanletOpaque;
+ }
+ else
+ {
+ if ( sw_stipplealpha->value )
+ {
+ if ( isturbulent )
+ {
+ if ( alpha > 0.33 )
+ r_polydesc.drawspanlet = R_DrawSpanletTurbulentStipple66;
+ else
+ r_polydesc.drawspanlet = R_DrawSpanletTurbulentStipple33;
+ }
+ else
+ {
+ if ( alpha > 0.33 )
+ r_polydesc.drawspanlet = R_DrawSpanlet66Stipple;
+ else
+ r_polydesc.drawspanlet = R_DrawSpanlet33Stipple;
+ }
+ }
+ else
+ {
+ if ( isturbulent )
+ {
+ if ( alpha > 0.33 )
+ r_polydesc.drawspanlet = R_DrawSpanletTurbulentBlended66;
+ else
+ r_polydesc.drawspanlet = R_DrawSpanletTurbulentBlended33;
+ }
+ else
+ {
+ if ( alpha > 0.33 )
+ r_polydesc.drawspanlet = R_DrawSpanlet66;
+ else
+ r_polydesc.drawspanlet = R_DrawSpanlet33;
+ }
+ }
+ }
+ }
+
+ // clip to the frustum in worldspace
+ nump = r_polydesc.nump;
+ clip_current = 0;
+
+ for (i=0 ; i<4 ; i++)
+ {
+ nump = R_ClipPolyFace (nump, &view_clipplanes[i]);
+ if (nump < 3)
+ return;
+ if (nump > MAXWORKINGVERTS)
+ ri.Sys_Error(ERR_DROP, "R_ClipAndDrawPoly: too many points: %d", nump );
+ }
+
+// transform vertices into viewspace and project
+ pv = &r_clip_verts[clip_current][0][0];
+
+ for (i=0 ; i<nump ; i++)
+ {
+ VectorSubtract (pv, r_origin, local);
+ TransformVector (local, transformed);
+
+ if (transformed[2] < NEAR_CLIP)
+ transformed[2] = NEAR_CLIP;
+
+ pout = &outverts[i];
+ pout->zi = 1.0 / transformed[2];
+
+ pout->s = pv[3];
+ pout->t = pv[4];
+
+ scale = xscale * pout->zi;
+ pout->u = (xcenter + scale * transformed[0]);
+
+ scale = yscale * pout->zi;
+ pout->v = (ycenter - scale * transformed[1]);
+
+ pv += sizeof (vec5_t) / sizeof (*pv);
+ }
+
+// draw it
+ r_polydesc.nump = nump;
+ r_polydesc.pverts = outverts;
+
+ R_DrawPoly( isturbulent );
+}
+
+/*
+** R_BuildPolygonFromSurface
+*/
+void R_BuildPolygonFromSurface(msurface_t *fa)
+{
+ int i, lindex, lnumverts;
+ medge_t *pedges, *r_pedge;
+ float *vec;
+ vec5_t *pverts;
+ float tmins[2] = { 0, 0 };
+
+ r_polydesc.nump = 0;
+
+ // reconstruct the polygon
+ pedges = currentmodel->edges;
+ lnumverts = fa->numedges;
+
+ pverts = r_clip_verts[0];
+
+ for (i=0 ; i<lnumverts ; i++)
+ {
+ lindex = currentmodel->surfedges[fa->firstedge + i];
+
+ if (lindex > 0)
+ {
+ r_pedge = &pedges[lindex];
+ vec = currentmodel->vertexes[r_pedge->v[0]].position;
+ }
+ else
+ {
+ r_pedge = &pedges[-lindex];
+ vec = currentmodel->vertexes[r_pedge->v[1]].position;
+ }
+
+ VectorCopy (vec, pverts[i] );
+ }
+
+ VectorCopy( fa->texinfo->vecs[0], r_polydesc.vright );
+ VectorCopy( fa->texinfo->vecs[1], r_polydesc.vup );
+ VectorCopy( fa->plane->normal, r_polydesc.vpn );
+ VectorCopy( r_origin, r_polydesc.viewer_position );
+
+ if ( fa->flags & SURF_PLANEBACK )
+ {
+ VectorSubtract( vec3_origin, r_polydesc.vpn, r_polydesc.vpn );
+ }
+
+ if ( fa->texinfo->flags & SURF_WARP )
+ {
+ r_polydesc.pixels = fa->texinfo->image->pixels[0];
+ r_polydesc.pixel_width = fa->texinfo->image->width;
+ r_polydesc.pixel_height = fa->texinfo->image->height;
+ }
+ else
+ {
+ surfcache_t *scache;
+
+ scache = D_CacheSurface( fa, 0 );
+
+ r_polydesc.pixels = scache->data;
+ r_polydesc.pixel_width = scache->width;
+ r_polydesc.pixel_height = scache->height;
+
+ tmins[0] = fa->texturemins[0];
+ tmins[1] = fa->texturemins[1];
+ }
+
+ r_polydesc.dist = DotProduct( r_polydesc.vpn, pverts[0] );
+
+ r_polydesc.s_offset = fa->texinfo->vecs[0][3] - tmins[0];
+ r_polydesc.t_offset = fa->texinfo->vecs[1][3] - tmins[1];
+
+ // scrolling texture addition
+ if (fa->texinfo->flags & SURF_FLOWING)
+ {
+ r_polydesc.s_offset += -128 * ( (r_newrefdef.time*0.25) - (int)(r_newrefdef.time*0.25) );
+ }
+
+ r_polydesc.nump = lnumverts;
+}
+
+/*
+** R_PolygonCalculateGradients
+*/
+void R_PolygonCalculateGradients (void)
+{
+ vec3_t p_normal, p_saxis, p_taxis;
+ float distinv;
+
+ TransformVector (r_polydesc.vpn, p_normal);
+ TransformVector (r_polydesc.vright, p_saxis);
+ TransformVector (r_polydesc.vup, p_taxis);
+
+ distinv = 1.0 / (-(DotProduct (r_polydesc.viewer_position, r_polydesc.vpn)) + r_polydesc.dist );
+
+ d_sdivzstepu = p_saxis[0] * xscaleinv;
+ d_sdivzstepv = -p_saxis[1] * yscaleinv;
+ d_sdivzorigin = p_saxis[2] - xcenter * d_sdivzstepu - ycenter * d_sdivzstepv;
+
+ d_tdivzstepu = p_taxis[0] * xscaleinv;
+ d_tdivzstepv = -p_taxis[1] * yscaleinv;
+ d_tdivzorigin = p_taxis[2] - xcenter * d_tdivzstepu - ycenter * d_tdivzstepv;
+
+ d_zistepu = p_normal[0] * xscaleinv * distinv;
+ d_zistepv = -p_normal[1] * yscaleinv * distinv;
+ d_ziorigin = p_normal[2] * distinv - xcenter * d_zistepu - ycenter * d_zistepv;
+
+ sadjust = (fixed16_t) ( ( DotProduct( r_polydesc.viewer_position, r_polydesc.vright) + r_polydesc.s_offset ) * 0x10000 );
+ tadjust = (fixed16_t) ( ( DotProduct( r_polydesc.viewer_position, r_polydesc.vup ) + r_polydesc.t_offset ) * 0x10000 );
+
+// -1 (-epsilon) so we never wander off the edge of the texture
+ bbextents = (r_polydesc.pixel_width << 16) - 1;
+ bbextentt = (r_polydesc.pixel_height << 16) - 1;
+}
+
+/*
+** R_DrawPoly
+**
+** Polygon drawing function. Uses the polygon described in r_polydesc
+** to calculate edges and gradients, then renders the resultant spans.
+**
+** This should NOT be called externally since it doesn't do clipping!
+*/
+static void R_DrawPoly( qboolean iswater )
+{
+ int i, nump;
+ float ymin, ymax;
+ emitpoint_t *pverts;
+ espan_t spans[MAXHEIGHT+1];
+
+ s_polygon_spans = spans;
+
+// find the top and bottom vertices, and make sure there's at least one scan to
+// draw
+ ymin = 999999.9;
+ ymax = -999999.9;
+ pverts = r_polydesc.pverts;
+
+ for (i=0 ; i<r_polydesc.nump ; i++)
+ {
+ if (pverts->v < ymin)
+ {
+ ymin = pverts->v;
+ s_minindex = i;
+ }
+
+ if (pverts->v > ymax)
+ {
+ ymax = pverts->v;
+ s_maxindex = i;
+ }
+
+ pverts++;
+ }
+
+ ymin = ceil (ymin);
+ ymax = ceil (ymax);
+
+ if (ymin >= ymax)
+ return; // doesn't cross any scans at all
+
+ cachewidth = r_polydesc.pixel_width;
+ cacheblock = r_polydesc.pixels;
+
+// copy the first vertex to the last vertex, so we don't have to deal with
+// wrapping
+ nump = r_polydesc.nump;
+ pverts = r_polydesc.pverts;
+ pverts[nump] = pverts[0];
+
+ R_PolygonCalculateGradients ();
+ R_PolygonScanLeftEdge ();
+ R_PolygonScanRightEdge ();
+
+ R_PolygonDrawSpans( s_polygon_spans, iswater );
+}
+
+/*
+** R_DrawAlphaSurfaces
+*/
+void R_DrawAlphaSurfaces( void )
+{
+ msurface_t *s = r_alpha_surfaces;
+
+ currentmodel = r_worldmodel;
+
+ modelorg[0] = -r_origin[0];
+ modelorg[1] = -r_origin[1];
+ modelorg[2] = -r_origin[2];
+
+ while ( s )
+ {
+ R_BuildPolygonFromSurface( s );
+
+ if (s->texinfo->flags & SURF_TRANS66)
+ R_ClipAndDrawPoly( 0.60f, ( s->texinfo->flags & SURF_WARP) != 0, true );
+ else
+ R_ClipAndDrawPoly( 0.30f, ( s->texinfo->flags & SURF_WARP) != 0, true );
+
+ s = s->nextalphasurface;
+ }
+
+ r_alpha_surfaces = NULL;
+}
+
+/*
+** R_IMFlatShadedQuad
+*/
+void R_IMFlatShadedQuad( vec3_t a, vec3_t b, vec3_t c, vec3_t d, int color, float alpha )
+{
+ vec3_t s0, s1;
+
+ r_polydesc.nump = 4;
+ VectorCopy( r_origin, r_polydesc.viewer_position );
+
+ VectorCopy( a, r_clip_verts[0][0] );
+ VectorCopy( b, r_clip_verts[0][1] );
+ VectorCopy( c, r_clip_verts[0][2] );
+ VectorCopy( d, r_clip_verts[0][3] );
+
+ r_clip_verts[0][0][3] = 0;
+ r_clip_verts[0][1][3] = 0;
+ r_clip_verts[0][2][3] = 0;
+ r_clip_verts[0][3][3] = 0;
+
+ r_clip_verts[0][0][4] = 0;
+ r_clip_verts[0][1][4] = 0;
+ r_clip_verts[0][2][4] = 0;
+ r_clip_verts[0][3][4] = 0;
+
+ VectorSubtract( d, c, s0 );
+ VectorSubtract( c, b, s1 );
+ CrossProduct( s0, s1, r_polydesc.vpn );
+ VectorNormalize( r_polydesc.vpn );
+
+ r_polydesc.dist = DotProduct( r_polydesc.vpn, r_clip_verts[0][0] );
+
+ r_polyblendcolor = color;
+
+ R_ClipAndDrawPoly( alpha, false, false );
+}
+
--- /dev/null
+++ b/r_polyse.c
@@ -1,0 +1,1147 @@
+// d_polyset.c: routines for drawing sets of polygons sharing the same
+// texture (used for Alias models)
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+int rand1k[] = {
+#include "rand1k.h"
+};
+
+#define MASK_1K 0x3FF
+
+int rand1k_index = 0;
+
+// TODO: put in span spilling to shrink list size
+// !!! if this is changed, it must be changed in d_polysa.s too !!!
+#define DPS_MAXSPANS MAXHEIGHT+1
+ // 1 extra for spanpackage that marks end
+
+// !!! if this is changed, it must be changed in asm_draw.h too !!!
+typedef struct {
+ void *pdest;
+ short *pz;
+ int count;
+ byte *ptex;
+ int sfrac, tfrac, light, zi;
+} spanpackage_t;
+
+typedef struct {
+ int isflattop;
+ int numleftedges;
+ int *pleftedgevert0;
+ int *pleftedgevert1;
+ int *pleftedgevert2;
+ int numrightedges;
+ int *prightedgevert0;
+ int *prightedgevert1;
+ int *prightedgevert2;
+} edgetable;
+
+aliastriangleparms_t aliastriangleparms;
+
+int r_p0[6], r_p1[6], r_p2[6];
+
+byte *d_pcolormap;
+
+int d_aflatcolor;
+int d_xdenom;
+
+edgetable *pedgetable;
+
+edgetable edgetables[12] = {
+ {0, 1, r_p0, r_p2, NULL, 2, r_p0, r_p1, r_p2 },
+ {0, 2, r_p1, r_p0, r_p2, 1, r_p1, r_p2, NULL},
+ {1, 1, r_p0, r_p2, NULL, 1, r_p1, r_p2, NULL},
+ {0, 1, r_p1, r_p0, NULL, 2, r_p1, r_p2, r_p0 },
+ {0, 2, r_p0, r_p2, r_p1, 1, r_p0, r_p1, NULL},
+ {0, 1, r_p2, r_p1, NULL, 1, r_p2, r_p0, NULL},
+ {0, 1, r_p2, r_p1, NULL, 2, r_p2, r_p0, r_p1 },
+ {0, 2, r_p2, r_p1, r_p0, 1, r_p2, r_p0, NULL},
+ {0, 1, r_p1, r_p0, NULL, 1, r_p1, r_p2, NULL},
+ {1, 1, r_p2, r_p1, NULL, 1, r_p0, r_p1, NULL},
+ {1, 1, r_p1, r_p0, NULL, 1, r_p2, r_p0, NULL},
+ {0, 1, r_p0, r_p2, NULL, 1, r_p0, r_p1, NULL},
+};
+
+// FIXME: some of these can become statics
+int a_sstepxfrac, a_tstepxfrac, r_lstepx, a_ststepxwhole;
+int r_sstepx, r_tstepx, r_lstepy, r_sstepy, r_tstepy;
+int r_zistepx, r_zistepy;
+int d_aspancount, d_countextrastep;
+
+spanpackage_t *a_spans;
+spanpackage_t *d_pedgespanpackage;
+static int ystart;
+byte *d_pdest, *d_ptex;
+short *d_pz;
+int d_sfrac, d_tfrac, d_light, d_zi;
+int d_ptexextrastep, d_sfracextrastep;
+int d_tfracextrastep, d_lightextrastep, d_pdestextrastep;
+int d_lightbasestep, d_pdestbasestep, d_ptexbasestep;
+int d_sfracbasestep, d_tfracbasestep;
+int d_ziextrastep, d_zibasestep;
+int d_pzextrastep, d_pzbasestep;
+
+typedef struct {
+ int quotient;
+ int remainder;
+} adivtab_t;
+
+static adivtab_t adivtab[32*32] = {
+#include "adivtab.h"
+};
+
+byte *skintable[MAX_LBM_HEIGHT];
+int skinwidth;
+byte *skinstart;
+
+void (*d_pdrawspans)(spanpackage_t *pspanpackage);
+
+void R_PolysetDrawSpans8_33 (spanpackage_t *pspanpackage);
+void R_PolysetDrawSpans8_66 (spanpackage_t *pspanpackage);
+void R_PolysetDrawSpans8_Opaque (spanpackage_t *pspanpackage);
+
+void R_PolysetDrawThreshSpans8 (spanpackage_t *pspanpackage);
+void R_PolysetCalcGradients (int skinwidth);
+void R_DrawNonSubdiv (void);
+void R_PolysetSetEdgeTable (void);
+void R_RasterizeAliasPolySmooth (void);
+void R_PolysetScanLeftEdge(int height);
+void R_PolysetScanLeftEdge_C(int height);
+
+// ======================
+// PGM
+// 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
+byte iractive = 0;
+byte irtable[256] = { 79, 78, 77, 76, 75, 74, 73, 72, // black/white
+ 71, 70, 69, 68, 67, 66, 65, 64,
+ 64, 65, 66, 67, 68, 69, 70, 71, // dark taupe
+ 72, 73, 74, 75, 76, 77, 78, 79,
+
+ 64, 65, 66, 67, 68, 69, 70, 71, // slate grey
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 208, 208, 208, 208, 208, 208, 208, 208, // unused?'
+ 64, 66, 68, 70, 72, 74, 76, 78, // dark yellow
+
+ 64, 65, 66, 67, 68, 69, 70, 71, // dark red
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 64, 65, 66, 67, 68, 69, 70, 71, // grey/tan
+ 72, 73, 74, 75, 76, 77, 78, 79,
+
+ 64, 66, 68, 70, 72, 74, 76, 78, // chocolate
+ 68, 67, 66, 65, 64, 65, 66, 67, // mauve / teal
+ 68, 69, 70, 71, 72, 73, 74, 75,
+ 76, 76, 77, 77, 78, 78, 79, 79,
+
+ 64, 65, 66, 67, 68, 69, 70, 71, // more mauve
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 64, 65, 66, 67, 68, 69, 70, 71, // olive
+ 72, 73, 74, 75, 76, 77, 78, 79,
+
+ 64, 65, 66, 67, 68, 69, 70, 71, // maroon
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 64, 65, 66, 67, 68, 69, 70, 71, // sky blue
+ 72, 73, 74, 75, 76, 77, 78, 79,
+
+ 64, 65, 66, 67, 68, 69, 70, 71, // olive again
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 64, 65, 66, 67, 68, 69, 70, 71, // nuclear green
+ 64, 65, 66, 67, 68, 69, 70, 71, // bright yellow
+
+ 64, 65, 66, 67, 68, 69, 70, 71, // fire colors
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 208, 208, 64, 64, 70, 71, 72, 64, // mishmash1
+ 66, 68, 70, 64, 65, 66, 67, 68}; // mishmash2
+// PGM
+// ======================
+
+/*
+================
+R_PolysetUpdateTables
+================
+*/
+void R_PolysetUpdateTables (void)
+{
+ int i;
+ byte *s;
+
+ if (r_affinetridesc.skinwidth != skinwidth ||
+ r_affinetridesc.pskin != skinstart)
+ {
+ skinwidth = r_affinetridesc.skinwidth;
+ skinstart = r_affinetridesc.pskin;
+ s = skinstart;
+ for (i=0 ; i<MAX_LBM_HEIGHT ; i++, s+=skinwidth)
+ skintable[i] = s;
+ }
+}
+
+
+/*
+================
+R_DrawTriangle
+================
+*/
+void R_DrawTriangle( void )
+{
+ spanpackage_t spans[DPS_MAXSPANS];
+
+ int dv1_ab, dv0_ac;
+ int dv0_ab, dv1_ac;
+
+ /*
+ d_xdenom = ( aliastriangleparms.a->v[1] - aliastriangleparms.b->v[1] ) * ( aliastriangleparms.a->v[0] - aliastriangleparms.c->v[0] ) -
+ ( aliastriangleparms.a->v[0] - aliastriangleparms.b->v[0] ) * ( aliastriangleparms.a->v[1] - aliastriangleparms.c->v[1] );
+ */
+
+ dv0_ab = aliastriangleparms.a->u - aliastriangleparms.b->u;
+ dv1_ab = aliastriangleparms.a->v - aliastriangleparms.b->v;
+
+ if ( !( dv0_ab | dv1_ab ) )
+ return;
+
+ dv0_ac = aliastriangleparms.a->u - aliastriangleparms.c->u;
+ dv1_ac = aliastriangleparms.a->v - aliastriangleparms.c->v;
+
+ if ( !( dv0_ac | dv1_ac ) )
+ return;
+
+ d_xdenom = ( dv0_ac * dv1_ab ) - ( dv0_ab * dv1_ac );
+
+ if ( d_xdenom < 0 )
+ {
+ a_spans = spans;
+
+ r_p0[0] = aliastriangleparms.a->u; // u
+ r_p0[1] = aliastriangleparms.a->v; // v
+ r_p0[2] = aliastriangleparms.a->s; // s
+ r_p0[3] = aliastriangleparms.a->t; // t
+ r_p0[4] = aliastriangleparms.a->l; // light
+ r_p0[5] = aliastriangleparms.a->zi; // iz
+
+ r_p1[0] = aliastriangleparms.b->u;
+ r_p1[1] = aliastriangleparms.b->v;
+ r_p1[2] = aliastriangleparms.b->s;
+ r_p1[3] = aliastriangleparms.b->t;
+ r_p1[4] = aliastriangleparms.b->l;
+ r_p1[5] = aliastriangleparms.b->zi;
+
+ r_p2[0] = aliastriangleparms.c->u;
+ r_p2[1] = aliastriangleparms.c->v;
+ r_p2[2] = aliastriangleparms.c->s;
+ r_p2[3] = aliastriangleparms.c->t;
+ r_p2[4] = aliastriangleparms.c->l;
+ r_p2[5] = aliastriangleparms.c->zi;
+
+ R_PolysetSetEdgeTable ();
+ R_RasterizeAliasPolySmooth ();
+ }
+}
+
+
+/*
+===================
+R_PolysetScanLeftEdge_C
+====================
+*/
+void R_PolysetScanLeftEdge_C(int height)
+{
+ do
+ {
+ d_pedgespanpackage->pdest = d_pdest;
+ d_pedgespanpackage->pz = d_pz;
+ d_pedgespanpackage->count = d_aspancount;
+ d_pedgespanpackage->ptex = d_ptex;
+
+ d_pedgespanpackage->sfrac = d_sfrac;
+ d_pedgespanpackage->tfrac = d_tfrac;
+
+ // FIXME: need to clamp l, s, t, at both ends?
+ d_pedgespanpackage->light = d_light;
+ d_pedgespanpackage->zi = d_zi;
+
+ d_pedgespanpackage++;
+
+ errorterm += erroradjustup;
+ if (errorterm >= 0)
+ {
+ d_pdest += d_pdestextrastep;
+ d_pz += d_pzextrastep;
+ d_aspancount += d_countextrastep;
+ d_ptex += d_ptexextrastep;
+ d_sfrac += d_sfracextrastep;
+ d_ptex += d_sfrac >> 16;
+
+ d_sfrac &= 0xFFFF;
+ d_tfrac += d_tfracextrastep;
+ if (d_tfrac & 0x10000)
+ {
+ d_ptex += r_affinetridesc.skinwidth;
+ d_tfrac &= 0xFFFF;
+ }
+ d_light += d_lightextrastep;
+ d_zi += d_ziextrastep;
+ errorterm -= erroradjustdown;
+ }
+ else
+ {
+ d_pdest += d_pdestbasestep;
+ d_pz += d_pzbasestep;
+ d_aspancount += ubasestep;
+ d_ptex += d_ptexbasestep;
+ d_sfrac += d_sfracbasestep;
+ d_ptex += d_sfrac >> 16;
+ d_sfrac &= 0xFFFF;
+ d_tfrac += d_tfracbasestep;
+ if (d_tfrac & 0x10000)
+ {
+ d_ptex += r_affinetridesc.skinwidth;
+ d_tfrac &= 0xFFFF;
+ }
+ d_light += d_lightbasestep;
+ d_zi += d_zibasestep;
+ }
+ } while (--height);
+}
+
+/*
+===================
+FloorDivMod
+
+Returns mathematically correct (floor-based) quotient and remainder for
+numer and denom, both of which should contain no fractional part. The
+quotient must fit in 32 bits.
+FIXME: GET RID OF THIS! (FloorDivMod)
+====================
+*/
+void FloorDivMod (float numer, float denom, int *quotient,
+ int *rem)
+{
+ int q, r;
+ float x;
+
+ if (numer >= 0.0)
+ {
+
+ x = floor(numer / denom);
+ q = (int)x;
+ r = (int)floor(numer - (x * denom));
+ }
+ else
+ {
+ //
+ // perform operations with positive values, and fix mod to make floor-based
+ //
+ x = floor(-numer / denom);
+ q = -(int)x;
+ r = (int)floor(-numer - (x * denom));
+ if (r != 0)
+ {
+ q--;
+ r = (int)denom - r;
+ }
+ }
+
+ *quotient = q;
+ *rem = r;
+}
+
+
+/*
+===================
+R_PolysetSetUpForLineScan
+====================
+*/
+void R_PolysetSetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv,
+ fixed8_t endvertu, fixed8_t endvertv)
+{
+ float dm, dn;
+ int tm, tn;
+ adivtab_t *ptemp;
+
+// TODO: implement x86 version
+
+ errorterm = -1;
+
+ tm = endvertu - startvertu;
+ tn = endvertv - startvertv;
+
+ if (((tm <= 16) && (tm >= -15)) &&
+ ((tn <= 16) && (tn >= -15)))
+ {
+ ptemp = &adivtab[((tm+15) << 5) + (tn+15)];
+ ubasestep = ptemp->quotient;
+ erroradjustup = ptemp->remainder;
+ erroradjustdown = tn;
+ }
+ else
+ {
+ dm = tm;
+ dn = tn;
+
+ FloorDivMod (dm, dn, &ubasestep, &erroradjustup);
+
+ erroradjustdown = dn;
+ }
+}
+
+
+
+/*
+================
+R_PolysetCalcGradients
+================
+*/
+void R_PolysetCalcGradients (int skinwidth)
+{
+ float xstepdenominv, ystepdenominv, t0, t1;
+ float p01_minus_p21, p11_minus_p21, p00_minus_p20, p10_minus_p20;
+
+ p00_minus_p20 = r_p0[0] - r_p2[0];
+ p01_minus_p21 = r_p0[1] - r_p2[1];
+ p10_minus_p20 = r_p1[0] - r_p2[0];
+ p11_minus_p21 = r_p1[1] - r_p2[1];
+
+ xstepdenominv = 1.0 / (float)d_xdenom;
+
+ ystepdenominv = -xstepdenominv;
+
+// ceil () for light so positive steps are exaggerated, negative steps
+// diminished, pushing us away from underflow toward overflow. Underflow is
+// very visible, overflow is very unlikely, because of ambient lighting
+ t0 = r_p0[4] - r_p2[4];
+ t1 = r_p1[4] - r_p2[4];
+ r_lstepx = (int)
+ ceil((t1 * p01_minus_p21 - t0 * p11_minus_p21) * xstepdenominv);
+ r_lstepy = (int)
+ ceil((t1 * p00_minus_p20 - t0 * p10_minus_p20) * ystepdenominv);
+
+ t0 = r_p0[2] - r_p2[2];
+ t1 = r_p1[2] - r_p2[2];
+ r_sstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
+ xstepdenominv);
+ r_sstepy = (int)((t1 * p00_minus_p20 - t0* p10_minus_p20) *
+ ystepdenominv);
+
+ t0 = r_p0[3] - r_p2[3];
+ t1 = r_p1[3] - r_p2[3];
+ r_tstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
+ xstepdenominv);
+ r_tstepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) *
+ ystepdenominv);
+
+ t0 = r_p0[5] - r_p2[5];
+ t1 = r_p1[5] - r_p2[5];
+ r_zistepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
+ xstepdenominv);
+ r_zistepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) *
+ ystepdenominv);
+
+ a_sstepxfrac = r_sstepx & 0xFFFF;
+ a_tstepxfrac = r_tstepx & 0xFFFF;
+
+ a_ststepxwhole = skinwidth * (r_tstepx >> 16) + (r_sstepx >> 16);
+}
+
+/*
+================
+R_PolysetDrawThreshSpans8
+
+Random fizzle fade rasterizer
+================
+*/
+void R_PolysetDrawThreshSpans8 (spanpackage_t *pspanpackage)
+{
+ int lcount;
+ byte *lpdest;
+ byte *lptex;
+ int lsfrac, ltfrac;
+ int llight;
+ int lzi;
+ short *lpz;
+
+ do
+ {
+ lcount = d_aspancount - pspanpackage->count;
+
+ errorterm += erroradjustup;
+ if (errorterm >= 0)
+ {
+ d_aspancount += d_countextrastep;
+ errorterm -= erroradjustdown;
+ }
+ else
+ {
+ d_aspancount += ubasestep;
+ }
+
+ if (lcount)
+ {
+ lpdest = pspanpackage->pdest;
+ lptex = pspanpackage->ptex;
+ lpz = pspanpackage->pz;
+ lsfrac = pspanpackage->sfrac;
+ ltfrac = pspanpackage->tfrac;
+ llight = pspanpackage->light;
+ lzi = pspanpackage->zi;
+
+ do
+ {
+ if ((lzi >> 16) >= *lpz)
+ {
+ rand1k_index = (rand1k_index + 1) & MASK_1K;
+
+ if (rand1k[rand1k_index] <= r_affinetridesc.vis_thresh)
+ {
+ *lpdest = ((byte *)vid.colormap)[*lptex + (llight & 0xFF00)];
+ *lpz = lzi >> 16;
+ }
+ }
+
+ lpdest++;
+ lzi += r_zistepx;
+ lpz++;
+ llight += r_lstepx;
+ lptex += a_ststepxwhole;
+ lsfrac += a_sstepxfrac;
+ lptex += lsfrac >> 16;
+ lsfrac &= 0xFFFF;
+ ltfrac += a_tstepxfrac;
+ if (ltfrac & 0x10000)
+ {
+ lptex += r_affinetridesc.skinwidth;
+ ltfrac &= 0xFFFF;
+ }
+ } while (--lcount);
+ }
+
+ pspanpackage++;
+ } while (pspanpackage->count != -999999);
+}
+
+
+/*
+================
+R_PolysetDrawSpans8
+================
+*/
+void R_PolysetDrawSpans8_33( spanpackage_t *pspanpackage)
+{
+ int lcount;
+ byte *lpdest;
+ byte *lptex;
+ int lsfrac, ltfrac;
+ int llight;
+ int lzi;
+ short *lpz;
+
+ do
+ {
+ lcount = d_aspancount - pspanpackage->count;
+
+ errorterm += erroradjustup;
+ if (errorterm >= 0)
+ {
+ d_aspancount += d_countextrastep;
+ errorterm -= erroradjustdown;
+ }
+ else
+ {
+ d_aspancount += ubasestep;
+ }
+
+ if (lcount)
+ {
+ lpdest = pspanpackage->pdest;
+ lptex = pspanpackage->ptex;
+ lpz = pspanpackage->pz;
+ lsfrac = pspanpackage->sfrac;
+ ltfrac = pspanpackage->tfrac;
+ llight = pspanpackage->light;
+ lzi = pspanpackage->zi;
+
+ do
+ {
+ if ((lzi >> 16) >= *lpz)
+ {
+ int temp = vid.colormap[*lptex + ( llight & 0xFF00 )];
+
+ *lpdest = vid.alphamap[temp+ *lpdest*256];
+ }
+ lpdest++;
+ lzi += r_zistepx;
+ lpz++;
+ llight += r_lstepx;
+ lptex += a_ststepxwhole;
+ lsfrac += a_sstepxfrac;
+ lptex += lsfrac >> 16;
+ lsfrac &= 0xFFFF;
+ ltfrac += a_tstepxfrac;
+ if (ltfrac & 0x10000)
+ {
+ lptex += r_affinetridesc.skinwidth;
+ ltfrac &= 0xFFFF;
+ }
+ } while (--lcount);
+ }
+
+ pspanpackage++;
+ } while (pspanpackage->count != -999999);
+}
+
+void R_PolysetDrawSpansConstant8_33( spanpackage_t *pspanpackage)
+{
+ int lcount;
+ byte *lpdest;
+ int lzi;
+ short *lpz;
+
+ do
+ {
+ lcount = d_aspancount - pspanpackage->count;
+
+ errorterm += erroradjustup;
+ if (errorterm >= 0)
+ {
+ d_aspancount += d_countextrastep;
+ errorterm -= erroradjustdown;
+ }
+ else
+ {
+ d_aspancount += ubasestep;
+ }
+
+ if (lcount)
+ {
+ lpdest = pspanpackage->pdest;
+ lpz = pspanpackage->pz;
+ lzi = pspanpackage->zi;
+
+ do
+ {
+ if ((lzi >> 16) >= *lpz)
+ {
+ *lpdest = vid.alphamap[r_aliasblendcolor + *lpdest*256];
+ }
+ lpdest++;
+ lzi += r_zistepx;
+ lpz++;
+ } while (--lcount);
+ }
+
+ pspanpackage++;
+ } while (pspanpackage->count != -999999);
+}
+
+void R_PolysetDrawSpans8_66(spanpackage_t *pspanpackage)
+{
+ int lcount;
+ byte *lpdest;
+ byte *lptex;
+ int lsfrac, ltfrac;
+ int llight;
+ int lzi;
+ short *lpz;
+
+ do
+ {
+ lcount = d_aspancount - pspanpackage->count;
+
+ errorterm += erroradjustup;
+ if (errorterm >= 0)
+ {
+ d_aspancount += d_countextrastep;
+ errorterm -= erroradjustdown;
+ }
+ else
+ {
+ d_aspancount += ubasestep;
+ }
+
+ if (lcount)
+ {
+ lpdest = pspanpackage->pdest;
+ lptex = pspanpackage->ptex;
+ lpz = pspanpackage->pz;
+ lsfrac = pspanpackage->sfrac;
+ ltfrac = pspanpackage->tfrac;
+ llight = pspanpackage->light;
+ lzi = pspanpackage->zi;
+
+ do
+ {
+ if ((lzi >> 16) >= *lpz)
+ {
+ int temp = vid.colormap[*lptex + ( llight & 0xFF00 )];
+
+ *lpdest = vid.alphamap[temp*256 + *lpdest];
+ *lpz = lzi >> 16;
+ }
+ lpdest++;
+ lzi += r_zistepx;
+ lpz++;
+ llight += r_lstepx;
+ lptex += a_ststepxwhole;
+ lsfrac += a_sstepxfrac;
+ lptex += lsfrac >> 16;
+ lsfrac &= 0xFFFF;
+ ltfrac += a_tstepxfrac;
+ if (ltfrac & 0x10000)
+ {
+ lptex += r_affinetridesc.skinwidth;
+ ltfrac &= 0xFFFF;
+ }
+ } while (--lcount);
+ }
+
+ pspanpackage++;
+ } while (pspanpackage->count != -999999);
+}
+
+void R_PolysetDrawSpansConstant8_66( spanpackage_t *pspanpackage)
+{
+ int lcount;
+ byte *lpdest;
+ int lzi;
+ short *lpz;
+
+ do
+ {
+ lcount = d_aspancount - pspanpackage->count;
+
+ errorterm += erroradjustup;
+ if (errorterm >= 0)
+ {
+ d_aspancount += d_countextrastep;
+ errorterm -= erroradjustdown;
+ }
+ else
+ {
+ d_aspancount += ubasestep;
+ }
+
+ if (lcount)
+ {
+ lpdest = pspanpackage->pdest;
+ lpz = pspanpackage->pz;
+ lzi = pspanpackage->zi;
+
+ do
+ {
+ if ((lzi >> 16) >= *lpz)
+ {
+ *lpdest = vid.alphamap[r_aliasblendcolor*256 + *lpdest];
+ }
+ lpdest++;
+ lzi += r_zistepx;
+ lpz++;
+ } while (--lcount);
+ }
+
+ pspanpackage++;
+ } while (pspanpackage->count != -999999);
+}
+
+void R_PolysetDrawSpans8_Opaque (spanpackage_t *pspanpackage)
+{
+ int lcount;
+
+ do
+ {
+ lcount = d_aspancount - pspanpackage->count;
+
+ errorterm += erroradjustup;
+ if (errorterm >= 0)
+ {
+ d_aspancount += d_countextrastep;
+ errorterm -= erroradjustdown;
+ }
+ else
+ {
+ d_aspancount += ubasestep;
+ }
+
+ if (lcount)
+ {
+ int lsfrac, ltfrac;
+ byte *lpdest;
+ byte *lptex;
+ int llight;
+ int lzi;
+ short *lpz;
+
+ lpdest = pspanpackage->pdest;
+ lptex = pspanpackage->ptex;
+ lpz = pspanpackage->pz;
+ lsfrac = pspanpackage->sfrac;
+ ltfrac = pspanpackage->tfrac;
+ llight = pspanpackage->light;
+ lzi = pspanpackage->zi;
+
+ do
+ {
+ if ((lzi >> 16) >= *lpz)
+ {
+//PGM
+ if(r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE)
+ *lpdest = ((byte *)vid.colormap)[irtable[*lptex]];
+ else
+ *lpdest = ((byte *)vid.colormap)[*lptex + (llight & 0xFF00)];
+//PGM
+ *lpz = lzi >> 16;
+ }
+ lpdest++;
+ lzi += r_zistepx;
+ lpz++;
+ llight += r_lstepx;
+ lptex += a_ststepxwhole;
+ lsfrac += a_sstepxfrac;
+ lptex += lsfrac >> 16;
+ lsfrac &= 0xFFFF;
+ ltfrac += a_tstepxfrac;
+ if (ltfrac & 0x10000)
+ {
+ lptex += r_affinetridesc.skinwidth;
+ ltfrac &= 0xFFFF;
+ }
+ } while (--lcount);
+ }
+
+ pspanpackage++;
+ } while (pspanpackage->count != -999999);
+}
+
+
+/*
+================
+R_PolysetFillSpans8
+================
+*/
+void R_PolysetFillSpans8 (spanpackage_t *pspanpackage)
+{
+ int color;
+
+// FIXME: do z buffering
+
+ color = d_aflatcolor++;
+
+ while (1)
+ {
+ int lcount;
+ byte *lpdest;
+
+ lcount = pspanpackage->count;
+
+ if (lcount == -1)
+ return;
+
+ if (lcount)
+ {
+ lpdest = pspanpackage->pdest;
+
+ do
+ {
+ *lpdest++ = color;
+ } while (--lcount);
+ }
+
+ pspanpackage++;
+ }
+}
+
+/*
+================
+R_RasterizeAliasPolySmooth
+================
+*/
+void R_RasterizeAliasPolySmooth (void)
+{
+ int initialleftheight, initialrightheight;
+ int *plefttop, *prighttop, *pleftbottom, *prightbottom;
+ int working_lstepx, originalcount;
+
+ plefttop = pedgetable->pleftedgevert0;
+ prighttop = pedgetable->prightedgevert0;
+
+ pleftbottom = pedgetable->pleftedgevert1;
+ prightbottom = pedgetable->prightedgevert1;
+
+ initialleftheight = pleftbottom[1] - plefttop[1];
+ initialrightheight = prightbottom[1] - prighttop[1];
+
+//
+// set the s, t, and light gradients, which are consistent across the triangle
+// because being a triangle, things are affine
+//
+ R_PolysetCalcGradients (r_affinetridesc.skinwidth);
+//
+// rasterize the polygon
+//
+
+//
+// scan out the top (and possibly only) part of the left edge
+//
+ d_pedgespanpackage = a_spans;
+
+ ystart = plefttop[1];
+ d_aspancount = plefttop[0] - prighttop[0];
+
+ d_ptex = (byte *)r_affinetridesc.pskin + (plefttop[2] >> 16) +
+ (plefttop[3] >> 16) * r_affinetridesc.skinwidth;
+
+ d_sfrac = plefttop[2] & 0xFFFF;
+ d_tfrac = plefttop[3] & 0xFFFF;
+
+ d_light = plefttop[4];
+ d_zi = plefttop[5];
+
+ d_pdest = (byte *)d_viewbuffer +
+ ystart * r_screenwidth + plefttop[0];
+ d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0];
+
+ if (initialleftheight == 1)
+ {
+ d_pedgespanpackage->pdest = d_pdest;
+ d_pedgespanpackage->pz = d_pz;
+ d_pedgespanpackage->count = d_aspancount;
+ d_pedgespanpackage->ptex = d_ptex;
+
+ d_pedgespanpackage->sfrac = d_sfrac;
+ d_pedgespanpackage->tfrac = d_tfrac;
+
+ // FIXME: need to clamp l, s, t, at both ends?
+ d_pedgespanpackage->light = d_light;
+ d_pedgespanpackage->zi = d_zi;
+
+ d_pedgespanpackage++;
+ }
+ else
+ {
+ R_PolysetSetUpForLineScan(plefttop[0], plefttop[1],
+ pleftbottom[0], pleftbottom[1]);
+
+ d_pzbasestep = d_zwidth + ubasestep;
+ d_pzextrastep = d_pzbasestep + 1;
+
+ d_pdestbasestep = r_screenwidth + ubasestep;
+ d_pdestextrastep = d_pdestbasestep + 1;
+
+ // TODO: can reuse partial expressions here
+
+ // for negative steps in x along left edge, bias toward overflow rather than
+ // underflow (sort of turning the floor () we did in the gradient calcs into
+ // ceil (), but plus a little bit)
+ if (ubasestep < 0)
+ working_lstepx = r_lstepx - 1;
+ else
+ working_lstepx = r_lstepx;
+
+ d_countextrastep = ubasestep + 1;
+ d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) +
+ ((r_tstepy + r_tstepx * ubasestep) >> 16) *
+ r_affinetridesc.skinwidth;
+
+ d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF;
+ d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF;
+
+ d_lightbasestep = r_lstepy + working_lstepx * ubasestep;
+ d_zibasestep = r_zistepy + r_zistepx * ubasestep;
+
+ d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) +
+ ((r_tstepy + r_tstepx * d_countextrastep) >> 16) *
+ r_affinetridesc.skinwidth;
+
+ d_sfracextrastep = (r_sstepy + r_sstepx*d_countextrastep) & 0xFFFF;
+ d_tfracextrastep = (r_tstepy + r_tstepx*d_countextrastep) & 0xFFFF;
+
+ d_lightextrastep = d_lightbasestep + working_lstepx;
+ d_ziextrastep = d_zibasestep + r_zistepx;
+
+ R_PolysetScanLeftEdge_C(initialleftheight);
+ }
+
+//
+// scan out the bottom part of the left edge, if it exists
+//
+ if (pedgetable->numleftedges == 2)
+ {
+ int height;
+
+ plefttop = pleftbottom;
+ pleftbottom = pedgetable->pleftedgevert2;
+
+ height = pleftbottom[1] - plefttop[1];
+
+// TODO: make this a function; modularize this function in general
+
+ ystart = plefttop[1];
+ d_aspancount = plefttop[0] - prighttop[0];
+ d_ptex = (byte *)r_affinetridesc.pskin + (plefttop[2] >> 16) +
+ (plefttop[3] >> 16) * r_affinetridesc.skinwidth;
+ d_sfrac = 0;
+ d_tfrac = 0;
+ d_light = plefttop[4];
+ d_zi = plefttop[5];
+
+ d_pdest = (byte *)d_viewbuffer + ystart * r_screenwidth + plefttop[0];
+ d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0];
+
+ if (height == 1)
+ {
+ d_pedgespanpackage->pdest = d_pdest;
+ d_pedgespanpackage->pz = d_pz;
+ d_pedgespanpackage->count = d_aspancount;
+ d_pedgespanpackage->ptex = d_ptex;
+
+ d_pedgespanpackage->sfrac = d_sfrac;
+ d_pedgespanpackage->tfrac = d_tfrac;
+
+ // FIXME: need to clamp l, s, t, at both ends?
+ d_pedgespanpackage->light = d_light;
+ d_pedgespanpackage->zi = d_zi;
+ }
+ else
+ {
+ R_PolysetSetUpForLineScan(plefttop[0], plefttop[1],
+ pleftbottom[0], pleftbottom[1]);
+
+ d_pdestbasestep = r_screenwidth + ubasestep;
+ d_pdestextrastep = d_pdestbasestep + 1;
+
+ d_pzbasestep = d_zwidth + ubasestep;
+ d_pzextrastep = d_pzbasestep + 1;
+
+ if (ubasestep < 0)
+ working_lstepx = r_lstepx - 1;
+ else
+ working_lstepx = r_lstepx;
+
+ d_countextrastep = ubasestep + 1;
+ d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) +
+ ((r_tstepy + r_tstepx * ubasestep) >> 16) *
+ r_affinetridesc.skinwidth;
+
+ d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF;
+ d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF;
+
+ d_lightbasestep = r_lstepy + working_lstepx * ubasestep;
+ d_zibasestep = r_zistepy + r_zistepx * ubasestep;
+
+ d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) +
+ ((r_tstepy + r_tstepx * d_countextrastep) >> 16) *
+ r_affinetridesc.skinwidth;
+
+
+ d_sfracextrastep = (r_sstepy+r_sstepx*d_countextrastep) & 0xFFFF;
+ d_tfracextrastep = (r_tstepy+r_tstepx*d_countextrastep) & 0xFFFF;
+
+ d_lightextrastep = d_lightbasestep + working_lstepx;
+ d_ziextrastep = d_zibasestep + r_zistepx;
+
+ R_PolysetScanLeftEdge_C(height);
+ }
+ }
+
+// scan out the top (and possibly only) part of the right edge, updating the
+// count field
+ d_pedgespanpackage = a_spans;
+
+ R_PolysetSetUpForLineScan(prighttop[0], prighttop[1],
+ prightbottom[0], prightbottom[1]);
+ d_aspancount = 0;
+ d_countextrastep = ubasestep + 1;
+ originalcount = a_spans[initialrightheight].count;
+ a_spans[initialrightheight].count = -999999; // mark end of the spanpackages
+ (*d_pdrawspans) (a_spans);
+
+// scan out the bottom part of the right edge, if it exists
+ if (pedgetable->numrightedges == 2)
+ {
+ int height;
+ spanpackage_t *pstart;
+
+ pstart = a_spans + initialrightheight;
+ pstart->count = originalcount;
+
+ d_aspancount = prightbottom[0] - prighttop[0];
+
+ prighttop = prightbottom;
+ prightbottom = pedgetable->prightedgevert2;
+
+ height = prightbottom[1] - prighttop[1];
+
+ R_PolysetSetUpForLineScan(prighttop[0], prighttop[1],
+ prightbottom[0], prightbottom[1]);
+
+ d_countextrastep = ubasestep + 1;
+ a_spans[initialrightheight + height].count = -999999;
+ // mark end of the spanpackages
+ (*d_pdrawspans) (pstart);
+ }
+}
+
+
+/*
+================
+R_PolysetSetEdgeTable
+================
+*/
+void R_PolysetSetEdgeTable (void)
+{
+ int edgetableindex;
+
+ edgetableindex = 0; // assume the vertices are already in
+ // top to bottom order
+
+//
+// determine which edges are right & left, and the order in which
+// to rasterize them
+//
+ if (r_p0[1] >= r_p1[1])
+ {
+ if (r_p0[1] == r_p1[1])
+ {
+ if (r_p0[1] < r_p2[1])
+ pedgetable = &edgetables[2];
+ else
+ pedgetable = &edgetables[5];
+
+ return;
+ }
+ else
+ {
+ edgetableindex = 1;
+ }
+ }
+
+ if (r_p0[1] == r_p2[1])
+ {
+ if (edgetableindex)
+ pedgetable = &edgetables[8];
+ else
+ pedgetable = &edgetables[9];
+
+ return;
+ }
+ else if (r_p1[1] == r_p2[1])
+ {
+ if (edgetableindex)
+ pedgetable = &edgetables[10];
+ else
+ pedgetable = &edgetables[11];
+
+ return;
+ }
+
+ if (r_p0[1] > r_p2[1])
+ edgetableindex += 2;
+
+ if (r_p1[1] > r_p2[1])
+ edgetableindex += 4;
+
+ pedgetable = &edgetables[edgetableindex];
+}
--- /dev/null
+++ b/r_rast.c
@@ -1,0 +1,829 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+#define MAXLEFTCLIPEDGES 100
+
+// !!! if these are changed, they must be changed in asm_draw.h too !!!
+#define FULLY_CLIPPED_CACHED 0x80000000
+#define FRAMECOUNT_MASK 0x7FFFFFFF
+
+unsigned int cacheoffset;
+
+int c_faceclip; // number of faces clipped
+
+
+clipplane_t *entity_clipplanes;
+clipplane_t view_clipplanes[4];
+clipplane_t world_clipplanes[16];
+
+medge_t *r_pedge;
+
+qboolean r_leftclipped, r_rightclipped;
+static qboolean makeleftedge, makerightedge;
+qboolean r_nearzionly;
+
+int sintable[1280];
+int intsintable[1280];
+int blanktable[1280]; // PGM
+
+mvertex_t r_leftenter, r_leftexit;
+mvertex_t r_rightenter, r_rightexit;
+
+typedef struct
+{
+ float u,v;
+ int ceilv;
+} evert_t;
+
+int r_emitted;
+float r_nearzi;
+float r_u1, r_v1, r_lzi1;
+int r_ceilv1;
+
+qboolean r_lastvertvalid;
+int r_skyframe;
+
+msurface_t *r_skyfaces;
+mplane_t r_skyplanes[6];
+mtexinfo_t r_skytexinfo[6];
+mvertex_t *r_skyverts;
+medge_t *r_skyedges;
+int *r_skysurfedges;
+
+// I just copied this data from a box map...
+int skybox_planes[12] = {2,-128, 0,-128, 2,128, 1,128, 0,128, 1,-128};
+
+int box_surfedges[24] = { 1,2,3,4, -1,5,6,7, 8,9,-6,10, -2,-7,-9,11,
+ 12,-3,-11,-8, -12,-10,-5,-4};
+int box_edges[24] = { 1,2, 2,3, 3,4, 4,1, 1,5, 5,6, 6,2, 7,8, 8,6, 5,7, 8,3, 7,4};
+
+int box_faces[6] = {0,0,2,2,2,0};
+
+vec3_t box_vecs[6][2] = {
+ { {0,-1,0}, {-1,0,0} },
+ { {0,1,0}, {0,0,-1} },
+ { {0,-1,0}, {1,0,0} },
+ { {1,0,0}, {0,0,-1} },
+ { {0,-1,0}, {0,0,-1} },
+ { {-1,0,0}, {0,0,-1} }
+};
+
+float box_verts[8][3] = {
+ {-1,-1,-1},
+ {-1,1,-1},
+ {1,1,-1},
+ {1,-1,-1},
+ {-1,-1,1},
+ {-1,1,1},
+ {1,-1,1},
+ {1,1,1}
+};
+
+// down, west, up, north, east, south
+// {"rt", "bk", "lf", "ft", "up", "dn"};
+
+/*
+================
+R_InitSkyBox
+
+================
+*/
+void R_InitSkyBox (void)
+{
+ int i;
+ extern model_t *loadmodel;
+
+ r_skyfaces = loadmodel->surfaces + loadmodel->numsurfaces;
+ loadmodel->numsurfaces += 6;
+ r_skyverts = loadmodel->vertexes + loadmodel->numvertexes;
+ loadmodel->numvertexes += 8;
+ r_skyedges = loadmodel->edges + loadmodel->numedges;
+ loadmodel->numedges += 12;
+ r_skysurfedges = loadmodel->surfedges + loadmodel->numsurfedges;
+ loadmodel->numsurfedges += 24;
+ if (loadmodel->numsurfaces > MAX_MAP_FACES
+ || loadmodel->numvertexes > MAX_MAP_VERTS
+ || loadmodel->numedges > MAX_MAP_EDGES)
+ ri.Sys_Error (ERR_DROP, "InitSkyBox: map overflow");
+
+ memset (r_skyfaces, 0, 6*sizeof(*r_skyfaces));
+ for (i=0 ; i<6 ; i++)
+ {
+ r_skyplanes[i].normal[skybox_planes[i*2]] = 1;
+ r_skyplanes[i].dist = skybox_planes[i*2+1];
+
+ VectorCopy (box_vecs[i][0], r_skytexinfo[i].vecs[0]);
+ VectorCopy (box_vecs[i][1], r_skytexinfo[i].vecs[1]);
+
+ r_skyfaces[i].plane = &r_skyplanes[i];
+ r_skyfaces[i].numedges = 4;
+ r_skyfaces[i].flags = box_faces[i] | SURF_DRAWSKYBOX;
+ r_skyfaces[i].firstedge = loadmodel->numsurfedges-24+i*4;
+ r_skyfaces[i].texinfo = &r_skytexinfo[i];
+ r_skyfaces[i].texturemins[0] = -128;
+ r_skyfaces[i].texturemins[1] = -128;
+ r_skyfaces[i].extents[0] = 256;
+ r_skyfaces[i].extents[1] = 256;
+ }
+
+ for (i=0 ; i<24 ; i++)
+ if (box_surfedges[i] > 0)
+ r_skysurfedges[i] = loadmodel->numedges-13 + box_surfedges[i];
+ else
+ r_skysurfedges[i] = - (loadmodel->numedges-13 + -box_surfedges[i]);
+
+ for(i=0 ; i<12 ; i++)
+ {
+ r_skyedges[i].v[0] = loadmodel->numvertexes-9+box_edges[i*2+0];
+ r_skyedges[i].v[1] = loadmodel->numvertexes-9+box_edges[i*2+1];
+ r_skyedges[i].cachededgeoffset = 0;
+ }
+}
+
+/*
+================
+R_EmitSkyBox
+================
+*/
+void R_EmitSkyBox (void)
+{
+ int i, j;
+ int oldkey;
+
+ if (insubmodel)
+ return; // submodels should never have skies
+ if (r_skyframe == r_framecount)
+ return; // already set this frame
+
+ r_skyframe = r_framecount;
+
+ // set the eight fake vertexes
+ for (i=0 ; i<8 ; i++)
+ for (j=0 ; j<3 ; j++)
+ r_skyverts[i].position[j] = r_origin[j] + box_verts[i][j]*128;
+
+ // set the six fake planes
+ for (i=0 ; i<6 ; i++)
+ if (skybox_planes[i*2+1] > 0)
+ r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]+128;
+ else
+ r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]-128;
+
+ // fix texture offseets
+ for (i=0 ; i<6 ; i++)
+ {
+ r_skytexinfo[i].vecs[0][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[0]);
+ r_skytexinfo[i].vecs[1][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[1]);
+ }
+
+ // emit the six faces
+ oldkey = r_currentkey;
+ r_currentkey = 0x7ffffff0;
+ for (i=0 ; i<6 ; i++)
+ {
+ R_RenderFace (r_skyfaces + i, 15);
+ }
+ r_currentkey = oldkey; // bsp sorting order
+}
+
+
+/*
+================
+R_EmitEdge
+================
+*/
+void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1)
+{
+ edge_t *edge, *pcheck;
+ int u_check;
+ float u, u_step;
+ vec3_t local, transformed;
+ float *world;
+ int v, v2, ceilv0;
+ float scale, lzi0, u0, v0;
+ int side;
+
+ if (r_lastvertvalid)
+ {
+ u0 = r_u1;
+ v0 = r_v1;
+ lzi0 = r_lzi1;
+ ceilv0 = r_ceilv1;
+ }
+ else
+ {
+ world = &pv0->position[0];
+
+ // transform and project
+ VectorSubtract (world, modelorg, local);
+ TransformVector (local, transformed);
+
+ if (transformed[2] < NEAR_CLIP)
+ transformed[2] = NEAR_CLIP;
+
+ lzi0 = 1.0 / transformed[2];
+
+ // FIXME: build x/yscale into transform?
+ scale = xscale * lzi0;
+ u0 = (xcenter + scale*transformed[0]);
+ if (u0 < r_refdef.fvrectx_adj)
+ u0 = r_refdef.fvrectx_adj;
+ if (u0 > r_refdef.fvrectright_adj)
+ u0 = r_refdef.fvrectright_adj;
+
+ scale = yscale * lzi0;
+ v0 = (ycenter - scale*transformed[1]);
+ if (v0 < r_refdef.fvrecty_adj)
+ v0 = r_refdef.fvrecty_adj;
+ if (v0 > r_refdef.fvrectbottom_adj)
+ v0 = r_refdef.fvrectbottom_adj;
+
+ ceilv0 = (int) ceil(v0);
+ }
+
+ world = &pv1->position[0];
+
+// transform and project
+ VectorSubtract (world, modelorg, local);
+ TransformVector (local, transformed);
+
+ if (transformed[2] < NEAR_CLIP)
+ transformed[2] = NEAR_CLIP;
+
+ r_lzi1 = 1.0 / transformed[2];
+
+ scale = xscale * r_lzi1;
+ r_u1 = (xcenter + scale*transformed[0]);
+ if (r_u1 < r_refdef.fvrectx_adj)
+ r_u1 = r_refdef.fvrectx_adj;
+ if (r_u1 > r_refdef.fvrectright_adj)
+ r_u1 = r_refdef.fvrectright_adj;
+
+ scale = yscale * r_lzi1;
+ r_v1 = (ycenter - scale*transformed[1]);
+ if (r_v1 < r_refdef.fvrecty_adj)
+ r_v1 = r_refdef.fvrecty_adj;
+ if (r_v1 > r_refdef.fvrectbottom_adj)
+ r_v1 = r_refdef.fvrectbottom_adj;
+
+ if (r_lzi1 > lzi0)
+ lzi0 = r_lzi1;
+
+ if (lzi0 > r_nearzi) // for mipmap finding
+ r_nearzi = lzi0;
+
+// for right edges, all we want is the effect on 1/z
+ if (r_nearzionly)
+ return;
+
+ r_emitted = 1;
+
+ r_ceilv1 = (int) ceil(r_v1);
+
+
+// create the edge
+ if (ceilv0 == r_ceilv1)
+ {
+ // we cache unclipped horizontal edges as fully clipped
+ if (cacheoffset != 0x7FFFFFFF)
+ {
+ cacheoffset = FULLY_CLIPPED_CACHED |
+ (r_framecount & FRAMECOUNT_MASK);
+ }
+
+ return; // horizontal edge
+ }
+
+ side = ceilv0 > r_ceilv1;
+
+ edge = edge_p++;
+
+ edge->owner = r_pedge;
+
+ edge->nearzi = lzi0;
+
+ if (side == 0)
+ {
+ // trailing edge (go from p1 to p2)
+ v = ceilv0;
+ v2 = r_ceilv1 - 1;
+
+ edge->surfs[0] = surface_p - surfaces;
+ edge->surfs[1] = 0;
+
+ u_step = ((r_u1 - u0) / (r_v1 - v0));
+ u = u0 + ((float)v - v0) * u_step;
+ }
+ else
+ {
+ // leading edge (go from p2 to p1)
+ v2 = ceilv0 - 1;
+ v = r_ceilv1;
+
+ edge->surfs[0] = 0;
+ edge->surfs[1] = surface_p - surfaces;
+
+ u_step = ((u0 - r_u1) / (v0 - r_v1));
+ u = r_u1 + ((float)v - r_v1) * u_step;
+ }
+
+ edge->u_step = u_step*0x100000;
+ edge->u = u*0x100000 + 0xFFFFF;
+
+// we need to do this to avoid stepping off the edges if a very nearly
+// horizontal edge is less than epsilon above a scan, and numeric error causes
+// it to incorrectly extend to the scan, and the extension of the line goes off
+// the edge of the screen
+// FIXME: is this actually needed?
+ if (edge->u < r_refdef.vrect_x_adj_shift20)
+ edge->u = r_refdef.vrect_x_adj_shift20;
+ if (edge->u > r_refdef.vrectright_adj_shift20)
+ edge->u = r_refdef.vrectright_adj_shift20;
+
+//
+// sort the edge in normally
+//
+ u_check = edge->u;
+ if (edge->surfs[0])
+ u_check++; // sort trailers after leaders
+
+ if (!newedges[v] || newedges[v]->u >= u_check)
+ {
+ edge->next = newedges[v];
+ newedges[v] = edge;
+ }
+ else
+ {
+ pcheck = newedges[v];
+ while (pcheck->next && pcheck->next->u < u_check)
+ pcheck = pcheck->next;
+ edge->next = pcheck->next;
+ pcheck->next = edge;
+ }
+
+ edge->nextremove = removeedges[v2];
+ removeedges[v2] = edge;
+}
+
+
+/*
+================
+R_ClipEdge
+================
+*/
+void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip)
+{
+ float d0, d1, f;
+ mvertex_t clipvert;
+
+ if (clip)
+ {
+ do
+ {
+ d0 = DotProduct (pv0->position, clip->normal) - clip->dist;
+ d1 = DotProduct (pv1->position, clip->normal) - clip->dist;
+
+ if (d0 >= 0)
+ {
+ // point 0 is unclipped
+ if (d1 >= 0)
+ {
+ // both points are unclipped
+ continue;
+ }
+
+ // only point 1 is clipped
+
+ // we don't cache clipped edges
+ cacheoffset = 0x7FFFFFFF;
+
+ f = d0 / (d0 - d1);
+ clipvert.position[0] = pv0->position[0] +
+ f * (pv1->position[0] - pv0->position[0]);
+ clipvert.position[1] = pv0->position[1] +
+ f * (pv1->position[1] - pv0->position[1]);
+ clipvert.position[2] = pv0->position[2] +
+ f * (pv1->position[2] - pv0->position[2]);
+
+ if (clip->leftedge)
+ {
+ r_leftclipped = true;
+ r_leftexit = clipvert;
+ }
+ else if (clip->rightedge)
+ {
+ r_rightclipped = true;
+ r_rightexit = clipvert;
+ }
+
+ R_ClipEdge (pv0, &clipvert, clip->next);
+ return;
+ }
+ else
+ {
+ // point 0 is clipped
+ if (d1 < 0)
+ {
+ // both points are clipped
+ // we do cache fully clipped edges
+ if (!r_leftclipped)
+ cacheoffset = FULLY_CLIPPED_CACHED |
+ (r_framecount & FRAMECOUNT_MASK);
+ return;
+ }
+
+ // only point 0 is clipped
+ r_lastvertvalid = false;
+
+ // we don't cache partially clipped edges
+ cacheoffset = 0x7FFFFFFF;
+
+ f = d0 / (d0 - d1);
+ clipvert.position[0] = pv0->position[0] +
+ f * (pv1->position[0] - pv0->position[0]);
+ clipvert.position[1] = pv0->position[1] +
+ f * (pv1->position[1] - pv0->position[1]);
+ clipvert.position[2] = pv0->position[2] +
+ f * (pv1->position[2] - pv0->position[2]);
+
+ if (clip->leftedge)
+ {
+ r_leftclipped = true;
+ r_leftenter = clipvert;
+ }
+ else if (clip->rightedge)
+ {
+ r_rightclipped = true;
+ r_rightenter = clipvert;
+ }
+
+ R_ClipEdge (&clipvert, pv1, clip->next);
+ return;
+ }
+ } while ((clip = clip->next) != NULL);
+ }
+
+// add the edge
+ R_EmitEdge (pv0, pv1);
+}
+
+
+/*
+================
+R_EmitCachedEdge
+================
+*/
+void R_EmitCachedEdge (void)
+{
+ edge_t *pedge_t;
+
+ pedge_t = (edge_t *)((uintptr)r_edges + r_pedge->cachededgeoffset);
+
+ if (!pedge_t->surfs[0])
+ pedge_t->surfs[0] = surface_p - surfaces;
+ else
+ pedge_t->surfs[1] = surface_p - surfaces;
+
+ if (pedge_t->nearzi > r_nearzi) // for mipmap finding
+ r_nearzi = pedge_t->nearzi;
+
+ r_emitted = 1;
+}
+
+
+/*
+================
+R_RenderFace
+================
+*/
+void R_RenderFace (msurface_t *fa, int clipflags)
+{
+ int i, lindex;
+ unsigned mask;
+ mplane_t *pplane;
+ float distinv;
+ vec3_t p_normal;
+ medge_t *pedges, tedge;
+ clipplane_t *pclip;
+
+ // translucent surfaces are not drawn by the edge renderer
+ if (fa->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))
+ {
+ fa->nextalphasurface = r_alpha_surfaces;
+ r_alpha_surfaces = fa;
+ return;
+ }
+
+ // sky surfaces encountered in the world will cause the
+ // environment box surfaces to be emited
+ if ( fa->texinfo->flags & SURF_SKY )
+ {
+ R_EmitSkyBox ();
+ return;
+ }
+
+// skip out if no more surfs
+ if ((surface_p) >= surf_max)
+ {
+ r_outofsurfaces++;
+ return;
+ }
+
+// ditto if not enough edges left, or switch to auxedges if possible
+ if ((edge_p + fa->numedges + 4) >= edge_max)
+ {
+ r_outofedges += fa->numedges;
+ return;
+ }
+
+ c_faceclip++;
+
+// set up clip planes
+ pclip = NULL;
+
+ for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
+ {
+ if (clipflags & mask)
+ {
+ view_clipplanes[i].next = pclip;
+ pclip = &view_clipplanes[i];
+ }
+ }
+
+// push the edges through
+ r_emitted = 0;
+ r_nearzi = 0;
+ r_nearzionly = false;
+ makeleftedge = makerightedge = false;
+ pedges = currentmodel->edges;
+ r_lastvertvalid = false;
+
+ for (i=0 ; i<fa->numedges ; i++)
+ {
+ lindex = currentmodel->surfedges[fa->firstedge + i];
+
+ if (lindex > 0)
+ {
+ r_pedge = &pedges[lindex];
+
+ // if the edge is cached, we can just reuse the edge
+ if (!insubmodel)
+ {
+ if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
+ {
+ if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
+ r_framecount)
+ {
+ r_lastvertvalid = false;
+ continue;
+ }
+ }
+ else
+ {
+ if ((((uintptr)edge_p - (uintptr)r_edges) >
+ r_pedge->cachededgeoffset) &&
+ (((edge_t *)((uintptr)r_edges +
+ r_pedge->cachededgeoffset))->owner == r_pedge))
+ {
+ R_EmitCachedEdge ();
+ r_lastvertvalid = false;
+ continue;
+ }
+ }
+ }
+
+ // assume it's cacheable
+ cacheoffset = (byte *)edge_p - (byte *)r_edges;
+ r_leftclipped = r_rightclipped = false;
+ R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[0]],
+ &r_pcurrentvertbase[r_pedge->v[1]],
+ pclip);
+ r_pedge->cachededgeoffset = cacheoffset;
+
+ if (r_leftclipped)
+ makeleftedge = true;
+ if (r_rightclipped)
+ makerightedge = true;
+ r_lastvertvalid = true;
+ }
+ else
+ {
+ lindex = -lindex;
+ r_pedge = &pedges[lindex];
+ // if the edge is cached, we can just reuse the edge
+ if (!insubmodel)
+ {
+ if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
+ {
+ if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
+ r_framecount)
+ {
+ r_lastvertvalid = false;
+ continue;
+ }
+ }
+ else
+ {
+ // it's cached if the cached edge is valid and is owned
+ // by this medge_t
+ if ((((uintptr)edge_p - (uintptr)r_edges) >
+ r_pedge->cachededgeoffset) &&
+ (((edge_t *)((uintptr)r_edges +
+ r_pedge->cachededgeoffset))->owner == r_pedge))
+ {
+ R_EmitCachedEdge ();
+ r_lastvertvalid = false;
+ continue;
+ }
+ }
+ }
+
+ // assume it's cacheable
+ cacheoffset = (byte *)edge_p - (byte *)r_edges;
+ r_leftclipped = r_rightclipped = false;
+ R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[1]],
+ &r_pcurrentvertbase[r_pedge->v[0]],
+ pclip);
+ r_pedge->cachededgeoffset = cacheoffset;
+
+ if (r_leftclipped)
+ makeleftedge = true;
+ if (r_rightclipped)
+ makerightedge = true;
+ r_lastvertvalid = true;
+ }
+ }
+
+// if there was a clip off the left edge, add that edge too
+// FIXME: faster to do in screen space?
+// FIXME: share clipped edges?
+ if (makeleftedge)
+ {
+ r_pedge = &tedge;
+ r_lastvertvalid = false;
+ R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
+ }
+
+// if there was a clip off the right edge, get the right r_nearzi
+ if (makerightedge)
+ {
+ r_pedge = &tedge;
+ r_lastvertvalid = false;
+ r_nearzionly = true;
+ R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
+ }
+
+// if no edges made it out, return without posting the surface
+ if (!r_emitted)
+ return;
+
+ r_polycount++;
+
+ surface_p->msurf = fa;
+ surface_p->nearzi = r_nearzi;
+ surface_p->flags = fa->flags;
+ surface_p->insubmodel = insubmodel;
+ surface_p->spanstate = 0;
+ surface_p->entity = currententity;
+ surface_p->key = r_currentkey++;
+ surface_p->spans = NULL;
+
+ pplane = fa->plane;
+// FIXME: cache this?
+ TransformVector (pplane->normal, p_normal);
+// FIXME: cache this?
+ distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
+
+ surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
+ surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
+ surface_p->d_ziorigin = p_normal[2] * distinv -
+ xcenter * surface_p->d_zistepu -
+ ycenter * surface_p->d_zistepv;
+
+ surface_p++;
+}
+
+
+/*
+================
+R_RenderBmodelFace
+================
+*/
+void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf)
+{
+ int i;
+ unsigned mask;
+ mplane_t *pplane;
+ float distinv;
+ vec3_t p_normal;
+ medge_t tedge;
+ clipplane_t *pclip;
+
+ if (psurf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))
+ {
+ psurf->nextalphasurface = r_alpha_surfaces;
+ r_alpha_surfaces = psurf;
+ return;
+ }
+
+// skip out if no more surfs
+ if (surface_p >= surf_max)
+ {
+ r_outofsurfaces++;
+ return;
+ }
+
+// ditto if not enough edges left, or switch to auxedges if possible
+ if ((edge_p + psurf->numedges + 4) >= edge_max)
+ {
+ r_outofedges += psurf->numedges;
+ return;
+ }
+
+ c_faceclip++;
+
+// this is a dummy to give the caching mechanism someplace to write to
+ r_pedge = &tedge;
+
+// set up clip planes
+ pclip = NULL;
+
+ for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
+ {
+ if (r_clipflags & mask)
+ {
+ view_clipplanes[i].next = pclip;
+ pclip = &view_clipplanes[i];
+ }
+ }
+
+// push the edges through
+ r_emitted = 0;
+ r_nearzi = 0;
+ r_nearzionly = false;
+ makeleftedge = makerightedge = false;
+// FIXME: keep clipped bmodel edges in clockwise order so last vertex caching
+// can be used?
+ r_lastvertvalid = false;
+
+ for ( ; pedges ; pedges = pedges->pnext)
+ {
+ r_leftclipped = r_rightclipped = false;
+ R_ClipEdge (pedges->v[0], pedges->v[1], pclip);
+
+ if (r_leftclipped)
+ makeleftedge = true;
+ if (r_rightclipped)
+ makerightedge = true;
+ }
+
+// if there was a clip off the left edge, add that edge too
+// FIXME: faster to do in screen space?
+// FIXME: share clipped edges?
+ if (makeleftedge)
+ {
+ r_pedge = &tedge;
+ R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
+ }
+
+// if there was a clip off the right edge, get the right r_nearzi
+ if (makerightedge)
+ {
+ r_pedge = &tedge;
+ r_nearzionly = true;
+ R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
+ }
+
+// if no edges made it out, return without posting the surface
+ if (!r_emitted)
+ return;
+
+ r_polycount++;
+
+ surface_p->msurf = psurf;
+ surface_p->nearzi = r_nearzi;
+ surface_p->flags = psurf->flags;
+ surface_p->insubmodel = true;
+ surface_p->spanstate = 0;
+ surface_p->entity = currententity;
+ surface_p->key = r_currentbkey;
+ surface_p->spans = NULL;
+
+ pplane = psurf->plane;
+// FIXME: cache this?
+ TransformVector (pplane->normal, p_normal);
+// FIXME: cache this?
+ distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
+
+ surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
+ surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
+ surface_p->d_ziorigin = p_normal[2] * distinv -
+ xcenter * surface_p->d_zistepu -
+ ycenter * surface_p->d_zistepv;
+
+ surface_p++;
+}
+
--- /dev/null
+++ b/r_scan.c
@@ -1,0 +1,561 @@
+// Portable C scan-level rasterization code, all pixel depths.
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+unsigned char *r_turb_pbase, *r_turb_pdest;
+fixed16_t r_turb_s, r_turb_t, r_turb_sstep, r_turb_tstep;
+int *r_turb_turb;
+int r_turb_spancount;
+
+void D_DrawTurbulent8Span (void);
+
+
+/*
+=============
+D_WarpScreen
+
+this performs a slight compression of the screen at the same time as
+the sine warp, to keep the edges from wrapping
+=============
+*/
+void D_WarpScreen (void)
+{
+ int w, h;
+ int u,v, u2, v2;
+ byte *dest;
+ int *turb;
+ int *col;
+ byte **row;
+
+ static int cached_width, cached_height;
+ static byte *rowptr[1200+AMP2*2];
+ static int column[1600+AMP2*2];
+
+ //
+ // these are constant over resolutions, and can be saved
+ //
+ w = r_newrefdef.width;
+ h = r_newrefdef.height;
+ if (w != cached_width || h != cached_height)
+ {
+ cached_width = w;
+ cached_height = h;
+ for (v=0 ; v<h+AMP2*2 ; v++)
+ {
+ v2 = (int)((float)v/(h + AMP2 * 2) * r_refdef.vrect.height);
+ rowptr[v] = r_warpbuffer + (WARP_WIDTH * v2);
+ }
+
+ for (u=0 ; u<w+AMP2*2 ; u++)
+ {
+ u2 = (int)((float)u/(w + AMP2 * 2) * r_refdef.vrect.width);
+ column[u] = u2;
+ }
+ }
+
+ turb = intsintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
+ dest = vid.buffer + r_newrefdef.y * vid.rowbytes + r_newrefdef.x;
+
+ for (v=0 ; v<h ; v++, dest += vid.rowbytes)
+ {
+ col = &column[turb[v]];
+ row = &rowptr[v];
+ for (u=0 ; u<w ; u+=4)
+ {
+ dest[u+0] = row[turb[u+0]][col[u+0]];
+ dest[u+1] = row[turb[u+1]][col[u+1]];
+ dest[u+2] = row[turb[u+2]][col[u+2]];
+ dest[u+3] = row[turb[u+3]][col[u+3]];
+ }
+ }
+}
+
+
+/*
+=============
+D_DrawTurbulent8Span
+=============
+*/
+void D_DrawTurbulent8Span (void)
+{
+ int sturb, tturb;
+
+ do
+ {
+ sturb = ((r_turb_s + r_turb_turb[(r_turb_t>>16)&(CYCLE-1)])>>16)&63;
+ tturb = ((r_turb_t + r_turb_turb[(r_turb_s>>16)&(CYCLE-1)])>>16)&63;
+ *r_turb_pdest++ = *(r_turb_pbase + (tturb<<6) + sturb);
+ r_turb_s += r_turb_sstep;
+ r_turb_t += r_turb_tstep;
+ } while (--r_turb_spancount > 0);
+}
+
+
+/*
+=============
+Turbulent8
+=============
+*/
+void Turbulent8 (espan_t *pspan)
+{
+ int count;
+ fixed16_t snext, tnext;
+ float sdivz, tdivz, zi, z, du, dv, spancountminus1;
+ float sdivz16stepu, tdivz16stepu, zi16stepu;
+
+ r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
+
+ r_turb_sstep = 0; // keep compiler happy
+ r_turb_tstep = 0; // ditto
+
+ r_turb_pbase = (unsigned char *)cacheblock;
+
+ sdivz16stepu = d_sdivzstepu * 16;
+ tdivz16stepu = d_tdivzstepu * 16;
+ zi16stepu = d_zistepu * 16;
+
+ do
+ {
+ r_turb_pdest = (unsigned char *)((byte *)d_viewbuffer +
+ (r_screenwidth * pspan->v) + pspan->u);
+
+ count = pspan->count;
+
+ // calculate the initial s/z, t/z, 1/z, s, and t and clamp
+ du = (float)pspan->u;
+ dv = (float)pspan->v;
+
+ sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
+ tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
+ zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
+ z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
+
+ r_turb_s = (int)(sdivz * z) + sadjust;
+ if (r_turb_s > bbextents)
+ r_turb_s = bbextents;
+ else if (r_turb_s < 0)
+ r_turb_s = 0;
+
+ r_turb_t = (int)(tdivz * z) + tadjust;
+ if (r_turb_t > bbextentt)
+ r_turb_t = bbextentt;
+ else if (r_turb_t < 0)
+ r_turb_t = 0;
+
+ do
+ {
+ // calculate s and t at the far end of the span
+ if (count >= 16)
+ r_turb_spancount = 16;
+ else
+ r_turb_spancount = count;
+
+ count -= r_turb_spancount;
+
+ if (count)
+ {
+ // calculate s/z, t/z, zi->fixed s and t at far end of span,
+ // calculate s and t steps across span by shifting
+ sdivz += sdivz16stepu;
+ tdivz += tdivz16stepu;
+ zi += zi16stepu;
+ z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
+
+ snext = (int)(sdivz * z) + sadjust;
+ if (snext > bbextents)
+ snext = bbextents;
+ else if (snext < 16)
+ snext = 16; // prevent round-off error on <0 steps from
+ // from causing overstepping & running off the
+ // edge of the texture
+
+ tnext = (int)(tdivz * z) + tadjust;
+ if (tnext > bbextentt)
+ tnext = bbextentt;
+ else if (tnext < 16)
+ tnext = 16; // guard against round-off error on <0 steps
+
+ r_turb_sstep = (snext - r_turb_s) >> 4;
+ r_turb_tstep = (tnext - r_turb_t) >> 4;
+ }
+ else
+ {
+ // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
+ // can't step off polygon), clamp, calculate s and t steps across
+ // span by division, biasing steps low so we don't run off the
+ // texture
+ spancountminus1 = (float)(r_turb_spancount - 1);
+ sdivz += d_sdivzstepu * spancountminus1;
+ tdivz += d_tdivzstepu * spancountminus1;
+ zi += d_zistepu * spancountminus1;
+ z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
+ snext = (int)(sdivz * z) + sadjust;
+ if (snext > bbextents)
+ snext = bbextents;
+ else if (snext < 16)
+ snext = 16; // prevent round-off error on <0 steps from
+ // from causing overstepping & running off the
+ // edge of the texture
+
+ tnext = (int)(tdivz * z) + tadjust;
+ if (tnext > bbextentt)
+ tnext = bbextentt;
+ else if (tnext < 16)
+ tnext = 16; // guard against round-off error on <0 steps
+
+ if (r_turb_spancount > 1)
+ {
+ r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1);
+ r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1);
+ }
+ }
+
+ r_turb_s = r_turb_s & ((CYCLE<<16)-1);
+ r_turb_t = r_turb_t & ((CYCLE<<16)-1);
+
+ D_DrawTurbulent8Span ();
+
+ r_turb_s = snext;
+ r_turb_t = tnext;
+
+ } while (count > 0);
+
+ } while ((pspan = pspan->pnext) != NULL);
+}
+
+//====================
+//PGM
+/*
+=============
+NonTurbulent8 - this is for drawing scrolling textures. they're warping water textures
+ but the turbulence is automatically 0.
+=============
+*/
+void NonTurbulent8 (espan_t *pspan)
+{
+ int count;
+ fixed16_t snext, tnext;
+ float sdivz, tdivz, zi, z, du, dv, spancountminus1;
+ float sdivz16stepu, tdivz16stepu, zi16stepu;
+
+// r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
+ r_turb_turb = blanktable;
+
+ r_turb_sstep = 0; // keep compiler happy
+ r_turb_tstep = 0; // ditto
+
+ r_turb_pbase = (unsigned char *)cacheblock;
+
+ sdivz16stepu = d_sdivzstepu * 16;
+ tdivz16stepu = d_tdivzstepu * 16;
+ zi16stepu = d_zistepu * 16;
+
+ do
+ {
+ r_turb_pdest = (unsigned char *)((byte *)d_viewbuffer +
+ (r_screenwidth * pspan->v) + pspan->u);
+
+ count = pspan->count;
+
+ // calculate the initial s/z, t/z, 1/z, s, and t and clamp
+ du = (float)pspan->u;
+ dv = (float)pspan->v;
+
+ sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
+ tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
+ zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
+ z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
+
+ r_turb_s = (int)(sdivz * z) + sadjust;
+ if (r_turb_s > bbextents)
+ r_turb_s = bbextents;
+ else if (r_turb_s < 0)
+ r_turb_s = 0;
+
+ r_turb_t = (int)(tdivz * z) + tadjust;
+ if (r_turb_t > bbextentt)
+ r_turb_t = bbextentt;
+ else if (r_turb_t < 0)
+ r_turb_t = 0;
+
+ do
+ {
+ // calculate s and t at the far end of the span
+ if (count >= 16)
+ r_turb_spancount = 16;
+ else
+ r_turb_spancount = count;
+
+ count -= r_turb_spancount;
+
+ if (count)
+ {
+ // calculate s/z, t/z, zi->fixed s and t at far end of span,
+ // calculate s and t steps across span by shifting
+ sdivz += sdivz16stepu;
+ tdivz += tdivz16stepu;
+ zi += zi16stepu;
+ z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
+
+ snext = (int)(sdivz * z) + sadjust;
+ if (snext > bbextents)
+ snext = bbextents;
+ else if (snext < 16)
+ snext = 16; // prevent round-off error on <0 steps from
+ // from causing overstepping & running off the
+ // edge of the texture
+
+ tnext = (int)(tdivz * z) + tadjust;
+ if (tnext > bbextentt)
+ tnext = bbextentt;
+ else if (tnext < 16)
+ tnext = 16; // guard against round-off error on <0 steps
+
+ r_turb_sstep = (snext - r_turb_s) >> 4;
+ r_turb_tstep = (tnext - r_turb_t) >> 4;
+ }
+ else
+ {
+ // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
+ // can't step off polygon), clamp, calculate s and t steps across
+ // span by division, biasing steps low so we don't run off the
+ // texture
+ spancountminus1 = (float)(r_turb_spancount - 1);
+ sdivz += d_sdivzstepu * spancountminus1;
+ tdivz += d_tdivzstepu * spancountminus1;
+ zi += d_zistepu * spancountminus1;
+ z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
+ snext = (int)(sdivz * z) + sadjust;
+ if (snext > bbextents)
+ snext = bbextents;
+ else if (snext < 16)
+ snext = 16; // prevent round-off error on <0 steps from
+ // from causing overstepping & running off the
+ // edge of the texture
+
+ tnext = (int)(tdivz * z) + tadjust;
+ if (tnext > bbextentt)
+ tnext = bbextentt;
+ else if (tnext < 16)
+ tnext = 16; // guard against round-off error on <0 steps
+
+ if (r_turb_spancount > 1)
+ {
+ r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1);
+ r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1);
+ }
+ }
+
+ r_turb_s = r_turb_s & ((CYCLE<<16)-1);
+ r_turb_t = r_turb_t & ((CYCLE<<16)-1);
+
+ D_DrawTurbulent8Span ();
+
+ r_turb_s = snext;
+ r_turb_t = tnext;
+
+ } while (count > 0);
+
+ } while ((pspan = pspan->pnext) != NULL);
+}
+//PGM
+//====================
+
+
+/*
+=============
+D_DrawSpans16
+
+ FIXME: actually make this subdivide by 16 instead of 8!!!
+=============
+*/
+void D_DrawSpans16 (espan_t *pspan)
+{
+ int count, spancount;
+ unsigned char *pbase, *pdest;
+ fixed16_t s, t, snext, tnext, sstep, tstep;
+ float sdivz, tdivz, zi, z, du, dv, spancountminus1;
+ float sdivz8stepu, tdivz8stepu, zi8stepu;
+
+ sstep = 0; // keep compiler happy
+ tstep = 0; // ditto
+
+ pbase = (unsigned char *)cacheblock;
+
+ sdivz8stepu = d_sdivzstepu * 8;
+ tdivz8stepu = d_tdivzstepu * 8;
+ zi8stepu = d_zistepu * 8;
+
+ do
+ {
+ pdest = (unsigned char *)((byte *)d_viewbuffer +
+ (r_screenwidth * pspan->v) + pspan->u);
+
+ count = pspan->count;
+
+ // calculate the initial s/z, t/z, 1/z, s, and t and clamp
+ du = (float)pspan->u;
+ dv = (float)pspan->v;
+
+ sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
+ tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
+ zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
+ z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
+
+ s = (int)(sdivz * z) + sadjust;
+ if (s > bbextents)
+ s = bbextents;
+ else if (s < 0)
+ s = 0;
+
+ t = (int)(tdivz * z) + tadjust;
+ if (t > bbextentt)
+ t = bbextentt;
+ else if (t < 0)
+ t = 0;
+
+ do
+ {
+ // calculate s and t at the far end of the span
+ if (count >= 8)
+ spancount = 8;
+ else
+ spancount = count;
+
+ count -= spancount;
+
+ if (count)
+ {
+ // calculate s/z, t/z, zi->fixed s and t at far end of span,
+ // calculate s and t steps across span by shifting
+ sdivz += sdivz8stepu;
+ tdivz += tdivz8stepu;
+ zi += zi8stepu;
+ z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
+
+ snext = (int)(sdivz * z) + sadjust;
+ if (snext > bbextents)
+ snext = bbextents;
+ else if (snext < 8)
+ snext = 8; // prevent round-off error on <0 steps from
+ // from causing overstepping & running off the
+ // edge of the texture
+
+ tnext = (int)(tdivz * z) + tadjust;
+ if (tnext > bbextentt)
+ tnext = bbextentt;
+ else if (tnext < 8)
+ tnext = 8; // guard against round-off error on <0 steps
+
+ sstep = (snext - s) >> 3;
+ tstep = (tnext - t) >> 3;
+ }
+ else
+ {
+ // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
+ // can't step off polygon), clamp, calculate s and t steps across
+ // span by division, biasing steps low so we don't run off the
+ // texture
+ spancountminus1 = (float)(spancount - 1);
+ sdivz += d_sdivzstepu * spancountminus1;
+ tdivz += d_tdivzstepu * spancountminus1;
+ zi += d_zistepu * spancountminus1;
+ z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
+ snext = (int)(sdivz * z) + sadjust;
+ if (snext > bbextents)
+ snext = bbextents;
+ else if (snext < 8)
+ snext = 8; // prevent round-off error on <0 steps from
+ // from causing overstepping & running off the
+ // edge of the texture
+
+ tnext = (int)(tdivz * z) + tadjust;
+ if (tnext > bbextentt)
+ tnext = bbextentt;
+ else if (tnext < 8)
+ tnext = 8; // guard against round-off error on <0 steps
+
+ if (spancount > 1)
+ {
+ sstep = (snext - s) / (spancount - 1);
+ tstep = (tnext - t) / (spancount - 1);
+ }
+ }
+
+ do
+ {
+ *pdest++ = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
+ s += sstep;
+ t += tstep;
+ } while (--spancount > 0);
+
+ s = snext;
+ t = tnext;
+
+ } while (count > 0);
+
+ } while ((pspan = pspan->pnext) != NULL);
+}
+
+
+/*
+=============
+D_DrawZSpans
+=============
+*/
+void D_DrawZSpans (espan_t *pspan)
+{
+ int count, doublecount, izistep;
+ int izi;
+ short *pdest;
+ unsigned ltemp;
+ float zi;
+ float du, dv;
+
+// FIXME: check for clamping/range problems
+// we count on FP exceptions being turned off to avoid range problems
+ izistep = (int)(d_zistepu * 0x8000 * 0x10000);
+
+ do
+ {
+ pdest = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
+
+ count = pspan->count;
+
+ // calculate the initial 1/z
+ du = (float)pspan->u;
+ dv = (float)pspan->v;
+
+ zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
+ // we count on FP exceptions being turned off to avoid range problems
+ izi = (int)(zi * 0x8000 * 0x10000);
+
+ if ((uintptr)pdest & 0x02)
+ {
+ *pdest++ = (short)(izi >> 16);
+ izi += izistep;
+ count--;
+ }
+
+ if ((doublecount = count >> 1) > 0)
+ {
+ do
+ {
+ ltemp = izi >> 16;
+ izi += izistep;
+ ltemp |= izi & 0xFFFF0000;
+ izi += izistep;
+ *(int *)pdest = ltemp;
+ pdest += 2;
+ } while (--doublecount > 0);
+ }
+
+ if (count & 1)
+ *pdest = (short)(izi >> 16);
+
+ } while ((pspan = pspan->pnext) != NULL);
+}
--- /dev/null
+++ b/r_sprite.c
@@ -1,0 +1,107 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+extern polydesc_t r_polydesc;
+
+void R_BuildPolygonFromSurface(msurface_t *fa);
+void R_PolygonCalculateGradients (void);
+
+extern void R_PolyChooseSpanletRoutine( float alpha, qboolean isturbulent );
+
+extern vec5_t r_clip_verts[2][MAXWORKINGVERTS+2];
+
+extern void R_ClipAndDrawPoly( float alpha, qboolean isturbulent, qboolean textured );
+
+/*
+** R_DrawSprite
+**
+** Draw currententity / currentmodel as a single texture
+** mapped polygon
+*/
+void R_DrawSprite (void)
+{
+ vec5_t *pverts;
+ vec3_t left, up, right, down;
+ dsprite_t *s_psprite;
+ dsprframe_t *s_psprframe;
+
+
+ s_psprite = (dsprite_t *)currentmodel->extradata;
+/*
+ if (currententity->frame >= s_psprite->numframes
+ || currententity->frame < 0)
+ {
+ ri.Con_Printf (PRINT_ALL, "No such sprite frame %i\n",
+ currententity->frame);
+ currententity->frame = 0;
+ }
+*/
+ currententity->frame %= s_psprite->numframes;
+
+ s_psprframe = &s_psprite->frames[currententity->frame];
+
+ r_polydesc.pixels = currentmodel->skins[currententity->frame]->pixels[0];
+ r_polydesc.pixel_width = s_psprframe->width;
+ r_polydesc.pixel_height = s_psprframe->height;
+ r_polydesc.dist = 0;
+
+ // generate the sprite's axes, completely parallel to the viewplane.
+ VectorCopy (vup, r_polydesc.vup);
+ VectorCopy (vright, r_polydesc.vright);
+ VectorCopy (vpn, r_polydesc.vpn);
+
+// build the sprite poster in worldspace
+ VectorScale (r_polydesc.vright,
+ s_psprframe->width - s_psprframe->origin_x, right);
+ VectorScale (r_polydesc.vup,
+ s_psprframe->height - s_psprframe->origin_y, up);
+ VectorScale (r_polydesc.vright,
+ -s_psprframe->origin_x, left);
+ VectorScale (r_polydesc.vup,
+ -s_psprframe->origin_y, down);
+
+ // invert UP vector for sprites
+ VectorInverse( r_polydesc.vup );
+
+ pverts = r_clip_verts[0];
+
+ pverts[0][0] = r_entorigin[0] + up[0] + left[0];
+ pverts[0][1] = r_entorigin[1] + up[1] + left[1];
+ pverts[0][2] = r_entorigin[2] + up[2] + left[2];
+ pverts[0][3] = 0;
+ pverts[0][4] = 0;
+
+ pverts[1][0] = r_entorigin[0] + up[0] + right[0];
+ pverts[1][1] = r_entorigin[1] + up[1] + right[1];
+ pverts[1][2] = r_entorigin[2] + up[2] + right[2];
+ pverts[1][3] = s_psprframe->width;
+ pverts[1][4] = 0;
+
+ pverts[2][0] = r_entorigin[0] + down[0] + right[0];
+ pverts[2][1] = r_entorigin[1] + down[1] + right[1];
+ pverts[2][2] = r_entorigin[2] + down[2] + right[2];
+ pverts[2][3] = s_psprframe->width;
+ pverts[2][4] = s_psprframe->height;
+
+ pverts[3][0] = r_entorigin[0] + down[0] + left[0];
+ pverts[3][1] = r_entorigin[1] + down[1] + left[1];
+ pverts[3][2] = r_entorigin[2] + down[2] + left[2];
+ pverts[3][3] = 0;
+ pverts[3][4] = s_psprframe->height;
+
+ r_polydesc.nump = 4;
+ r_polydesc.s_offset = ( r_polydesc.pixel_width >> 1);
+ r_polydesc.t_offset = ( r_polydesc.pixel_height >> 1);
+ VectorCopy( modelorg, r_polydesc.viewer_position );
+
+ r_polydesc.stipple_parity = 1;
+ if ( currententity->flags & RF_TRANSLUCENT )
+ R_ClipAndDrawPoly ( currententity->alpha, false, true );
+ else
+ R_ClipAndDrawPoly ( 1.0F, false, true );
+ r_polydesc.stipple_parity = 0;
+}
+
--- /dev/null
+++ b/r_surf.c
@@ -1,0 +1,633 @@
+// r_surf.c: surface-related refresh code
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+drawsurf_t r_drawsurf;
+
+int lightleft, sourcesstep, blocksize, sourcetstep;
+int lightdelta, lightdeltastep;
+int lightright, lightleftstep, lightrightstep, blockdivshift;
+unsigned blockdivmask;
+void *prowdestbase;
+unsigned char *pbasesource;
+int surfrowbytes; // used by ASM files
+unsigned *r_lightptr;
+int r_stepback;
+int r_lightwidth;
+int r_numhblocks, r_numvblocks;
+unsigned char *r_source, *r_sourcemax;
+
+void R_DrawSurfaceBlock8_mip0 (void);
+void R_DrawSurfaceBlock8_mip1 (void);
+void R_DrawSurfaceBlock8_mip2 (void);
+void R_DrawSurfaceBlock8_mip3 (void);
+
+static void (*surfmiptable[4])(void) = {
+ R_DrawSurfaceBlock8_mip0,
+ R_DrawSurfaceBlock8_mip1,
+ R_DrawSurfaceBlock8_mip2,
+ R_DrawSurfaceBlock8_mip3
+};
+
+void R_BuildLightMap (void);
+extern unsigned blocklights[1024]; // allow some very large lightmaps
+
+float surfscale;
+qboolean r_cache_thrash; // set if surface cache is thrashing
+
+int sc_size;
+surfcache_t *sc_rover, *sc_base;
+
+/*
+===============
+R_TextureAnimation
+
+Returns the proper texture for a given time and base texture
+===============
+*/
+image_t *R_TextureAnimation (mtexinfo_t *tex)
+{
+ int c;
+
+ if (!tex->next)
+ return tex->image;
+
+ c = currententity->frame % tex->numframes;
+ while (c)
+ {
+ tex = tex->next;
+ c--;
+ }
+
+ return tex->image;
+}
+
+
+/*
+===============
+R_DrawSurface
+===============
+*/
+void R_DrawSurface (void)
+{
+ unsigned char *basetptr;
+ int smax, tmax, twidth;
+ int u;
+ int soffset, basetoffset, texwidth;
+ int horzblockstep;
+ unsigned char *pcolumndest;
+ void (*pblockdrawer)(void);
+ image_t *mt;
+
+ surfrowbytes = r_drawsurf.rowbytes;
+
+ mt = r_drawsurf.image;
+
+ r_source = mt->pixels[r_drawsurf.surfmip];
+
+// the fractional light values should range from 0 to (VID_GRADES - 1) << 16
+// from a source range of 0 - 255
+
+ texwidth = mt->width >> r_drawsurf.surfmip;
+
+ blocksize = 16 >> r_drawsurf.surfmip;
+ blockdivshift = 4 - r_drawsurf.surfmip;
+ blockdivmask = (1 << blockdivshift) - 1;
+
+ r_lightwidth = (r_drawsurf.surf->extents[0]>>4)+1;
+
+ r_numhblocks = r_drawsurf.surfwidth >> blockdivshift;
+ r_numvblocks = r_drawsurf.surfheight >> blockdivshift;
+
+//==============================
+
+ pblockdrawer = surfmiptable[r_drawsurf.surfmip];
+// TODO: only needs to be set when there is a display settings change
+ horzblockstep = blocksize;
+
+ smax = mt->width >> r_drawsurf.surfmip;
+ twidth = texwidth;
+ tmax = mt->height >> r_drawsurf.surfmip;
+ sourcetstep = texwidth;
+ r_stepback = tmax * twidth;
+
+ r_sourcemax = r_source + (tmax * smax);
+
+ soffset = r_drawsurf.surf->texturemins[0];
+ basetoffset = r_drawsurf.surf->texturemins[1];
+
+// << 16 components are to guarantee positive values for %
+ soffset = ((soffset >> r_drawsurf.surfmip) + (smax << 16)) % smax;
+ basetptr = &r_source[((((basetoffset >> r_drawsurf.surfmip)
+ + (tmax << 16)) % tmax) * twidth)];
+
+ pcolumndest = r_drawsurf.surfdat;
+
+ for (u=0 ; u<r_numhblocks; u++)
+ {
+ r_lightptr = blocklights + u;
+
+ prowdestbase = pcolumndest;
+
+ pbasesource = basetptr + soffset;
+
+ (*pblockdrawer)();
+
+ soffset = soffset + blocksize;
+ if (soffset >= smax)
+ soffset = 0;
+
+ pcolumndest += horzblockstep;
+ }
+}
+
+
+//=============================================================================
+
+
+/*
+================
+R_DrawSurfaceBlock8_mip0
+================
+*/
+void R_DrawSurfaceBlock8_mip0 (void)
+{
+ int v, i, b, lightstep, lighttemp, light;
+ unsigned char pix, *psource, *prowdest;
+
+ psource = pbasesource;
+ prowdest = prowdestbase;
+
+ for (v=0 ; v<r_numvblocks ; v++)
+ {
+ // FIXME: make these locals?
+ // FIXME: use delta rather than both right and left, like ASM?
+ lightleft = r_lightptr[0];
+ lightright = r_lightptr[1];
+ r_lightptr += r_lightwidth;
+ lightleftstep = (r_lightptr[0] - lightleft) >> 4;
+ lightrightstep = (r_lightptr[1] - lightright) >> 4;
+
+ for (i=0 ; i<16 ; i++)
+ {
+ lighttemp = lightleft - lightright;
+ lightstep = lighttemp >> 4;
+
+ light = lightright;
+
+ for (b=15; b>=0; b--)
+ {
+ pix = psource[b];
+ prowdest[b] = ((unsigned char *)vid.colormap)
+ [(light & 0xFF00) + pix];
+ light += lightstep;
+ }
+
+ psource += sourcetstep;
+ lightright += lightrightstep;
+ lightleft += lightleftstep;
+ prowdest += surfrowbytes;
+ }
+
+ if (psource >= r_sourcemax)
+ psource -= r_stepback;
+ }
+}
+
+
+/*
+================
+R_DrawSurfaceBlock8_mip1
+================
+*/
+void R_DrawSurfaceBlock8_mip1 (void)
+{
+ int v, i, b, lightstep, lighttemp, light;
+ unsigned char pix, *psource, *prowdest;
+
+ psource = pbasesource;
+ prowdest = prowdestbase;
+
+ for (v=0 ; v<r_numvblocks ; v++)
+ {
+ // FIXME: make these locals?
+ // FIXME: use delta rather than both right and left, like ASM?
+ lightleft = r_lightptr[0];
+ lightright = r_lightptr[1];
+ r_lightptr += r_lightwidth;
+ lightleftstep = (r_lightptr[0] - lightleft) >> 3;
+ lightrightstep = (r_lightptr[1] - lightright) >> 3;
+
+ for (i=0 ; i<8 ; i++)
+ {
+ lighttemp = lightleft - lightright;
+ lightstep = lighttemp >> 3;
+
+ light = lightright;
+
+ for (b=7; b>=0; b--)
+ {
+ pix = psource[b];
+ prowdest[b] = ((unsigned char *)vid.colormap)
+ [(light & 0xFF00) + pix];
+ light += lightstep;
+ }
+
+ psource += sourcetstep;
+ lightright += lightrightstep;
+ lightleft += lightleftstep;
+ prowdest += surfrowbytes;
+ }
+
+ if (psource >= r_sourcemax)
+ psource -= r_stepback;
+ }
+}
+
+
+/*
+================
+R_DrawSurfaceBlock8_mip2
+================
+*/
+void R_DrawSurfaceBlock8_mip2 (void)
+{
+ int v, i, b, lightstep, lighttemp, light;
+ unsigned char pix, *psource, *prowdest;
+
+ psource = pbasesource;
+ prowdest = prowdestbase;
+
+ for (v=0 ; v<r_numvblocks ; v++)
+ {
+ // FIXME: make these locals?
+ // FIXME: use delta rather than both right and left, like ASM?
+ lightleft = r_lightptr[0];
+ lightright = r_lightptr[1];
+ r_lightptr += r_lightwidth;
+ lightleftstep = (r_lightptr[0] - lightleft) >> 2;
+ lightrightstep = (r_lightptr[1] - lightright) >> 2;
+
+ for (i=0 ; i<4 ; i++)
+ {
+ lighttemp = lightleft - lightright;
+ lightstep = lighttemp >> 2;
+
+ light = lightright;
+
+ for (b=3; b>=0; b--)
+ {
+ pix = psource[b];
+ prowdest[b] = ((unsigned char *)vid.colormap)
+ [(light & 0xFF00) + pix];
+ light += lightstep;
+ }
+
+ psource += sourcetstep;
+ lightright += lightrightstep;
+ lightleft += lightleftstep;
+ prowdest += surfrowbytes;
+ }
+
+ if (psource >= r_sourcemax)
+ psource -= r_stepback;
+ }
+}
+
+
+/*
+================
+R_DrawSurfaceBlock8_mip3
+================
+*/
+void R_DrawSurfaceBlock8_mip3 (void)
+{
+ int v, i, b, lightstep, lighttemp, light;
+ unsigned char pix, *psource, *prowdest;
+
+ psource = pbasesource;
+ prowdest = prowdestbase;
+
+ for (v=0 ; v<r_numvblocks ; v++)
+ {
+ // FIXME: make these locals?
+ // FIXME: use delta rather than both right and left, like ASM?
+ lightleft = r_lightptr[0];
+ lightright = r_lightptr[1];
+ r_lightptr += r_lightwidth;
+ lightleftstep = (r_lightptr[0] - lightleft) >> 1;
+ lightrightstep = (r_lightptr[1] - lightright) >> 1;
+
+ for (i=0 ; i<2 ; i++)
+ {
+ lighttemp = lightleft - lightright;
+ lightstep = lighttemp >> 1;
+
+ light = lightright;
+
+ for (b=1; b>=0; b--)
+ {
+ pix = psource[b];
+ prowdest[b] = ((unsigned char *)vid.colormap)
+ [(light & 0xFF00) + pix];
+ light += lightstep;
+ }
+
+ psource += sourcetstep;
+ lightright += lightrightstep;
+ lightleft += lightleftstep;
+ prowdest += surfrowbytes;
+ }
+
+ if (psource >= r_sourcemax)
+ psource -= r_stepback;
+ }
+}
+
+
+//============================================================================
+
+
+/*
+================
+R_InitCaches
+
+================
+*/
+void R_InitCaches (void)
+{
+ int size;
+ int pix;
+
+ // calculate size to allocate
+ if (sw_surfcacheoverride->value)
+ {
+ size = sw_surfcacheoverride->value;
+ }
+ else
+ {
+ size = SURFCACHE_SIZE_AT_320X240;
+
+ pix = vid.width*vid.height;
+ if (pix > 64000)
+ size += (pix-64000)*3;
+ }
+
+ // round up to page size
+ size = (size + 8191) & ~8191;
+
+ ri.Con_Printf (PRINT_ALL,"%ik surface cache\n", size/1024);
+
+ sc_size = size;
+ sc_base = (surfcache_t *)malloc(size);
+ sc_rover = sc_base;
+
+ sc_base->next = NULL;
+ sc_base->owner = NULL;
+ sc_base->size = sc_size;
+}
+
+
+/*
+==================
+D_FlushCaches
+==================
+*/
+void D_FlushCaches (void)
+{
+ surfcache_t *c;
+
+ if (!sc_base)
+ return;
+
+ for (c = sc_base ; c ; c = c->next)
+ {
+ if (c->owner)
+ *c->owner = NULL;
+ }
+
+ sc_rover = sc_base;
+ sc_base->next = NULL;
+ sc_base->owner = NULL;
+ sc_base->size = sc_size;
+}
+
+/*
+=================
+D_SCAlloc
+=================
+*/
+surfcache_t *D_SCAlloc (int width, int size)
+{
+ surfcache_t *new;
+ qboolean wrapped_this_time;
+
+ if ((width < 0) || (width > 256))
+ ri.Sys_Error (ERR_FATAL,"D_SCAlloc: bad cache width %d\n", width);
+
+ if ((size <= 0) || (size > 0x10000))
+ ri.Sys_Error (ERR_FATAL,"D_SCAlloc: bad cache size %d\n", size);
+
+ size = (int)(uintptr)&((surfcache_t *)0)->data[size];
+ size = (size + 3) & ~3;
+ if (size > sc_size)
+ ri.Sys_Error (ERR_FATAL,"D_SCAlloc: %i > cache size of %i",size, sc_size);
+
+// if there is not size bytes after the rover, reset to the start
+ wrapped_this_time = false;
+
+ if ( !sc_rover || (byte *)sc_rover - (byte *)sc_base > sc_size - size)
+ {
+ if (sc_rover)
+ {
+ wrapped_this_time = true;
+ }
+ sc_rover = sc_base;
+ }
+
+// colect and free surfcache_t blocks until the rover block is large enough
+ new = sc_rover;
+ if (sc_rover->owner)
+ *sc_rover->owner = NULL;
+
+ while (new->size < size)
+ {
+ // free another
+ sc_rover = sc_rover->next;
+ if (!sc_rover)
+ ri.Sys_Error (ERR_FATAL,"D_SCAlloc: hit the end of memory");
+ if (sc_rover->owner)
+ *sc_rover->owner = NULL;
+
+ new->size += sc_rover->size;
+ new->next = sc_rover->next;
+ }
+
+// create a fragment out of any leftovers
+ if (new->size - size > 256)
+ {
+ sc_rover = (surfcache_t *)( (byte *)new + size);
+ sc_rover->size = new->size - size;
+ sc_rover->next = new->next;
+ sc_rover->width = 0;
+ sc_rover->owner = NULL;
+ new->next = sc_rover;
+ new->size = size;
+ }
+ else
+ sc_rover = new->next;
+
+ new->width = width;
+// DEBUG
+ if (width > 0)
+ new->height = (size - sizeof(*new) + sizeof(new->data)) / width;
+
+ new->owner = NULL; // should be set properly after return
+
+ if (d_roverwrapped)
+ {
+ if (wrapped_this_time || (sc_rover >= d_initial_rover))
+ r_cache_thrash = true;
+ }
+ else if (wrapped_this_time)
+ {
+ d_roverwrapped = true;
+ }
+
+ return new;
+}
+
+
+/*
+=================
+D_SCDump
+=================
+*/
+void D_SCDump (void)
+{
+ surfcache_t *test;
+
+ for (test = sc_base ; test ; test = test->next)
+ {
+ if (test == sc_rover)
+ ri.Con_Printf (PRINT_ALL,"ROVER:\n");
+ ri.Con_Printf (PRINT_ALL,"%p : %i bytes %i width\n",test, test->size, test->width);
+ }
+}
+
+//=============================================================================
+
+// if the num is not a power of 2, assume it will not repeat
+
+int MaskForNum (int num)
+{
+ if (num==128)
+ return 127;
+ if (num==64)
+ return 63;
+ if (num==32)
+ return 31;
+ if (num==16)
+ return 15;
+ return 255;
+}
+
+int D_log2 (int num)
+{
+ int c;
+
+ c = 0;
+
+ while (num>>=1)
+ c++;
+ return c;
+}
+
+//=============================================================================
+
+/*
+================
+D_CacheSurface
+================
+*/
+surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel)
+{
+ surfcache_t *cache;
+
+//
+// if the surface is animating or flashing, flush the cache
+//
+ r_drawsurf.image = R_TextureAnimation (surface->texinfo);
+ r_drawsurf.lightadj[0] = r_newrefdef.lightstyles[surface->styles[0]].white*128;
+ r_drawsurf.lightadj[1] = r_newrefdef.lightstyles[surface->styles[1]].white*128;
+ r_drawsurf.lightadj[2] = r_newrefdef.lightstyles[surface->styles[2]].white*128;
+ r_drawsurf.lightadj[3] = r_newrefdef.lightstyles[surface->styles[3]].white*128;
+
+//
+// see if the cache holds apropriate data
+//
+ cache = surface->cachespots[miplevel];
+
+ if (cache && !cache->dlight && surface->dlightframe != r_framecount
+ && cache->image == r_drawsurf.image
+ && cache->lightadj[0] == r_drawsurf.lightadj[0]
+ && cache->lightadj[1] == r_drawsurf.lightadj[1]
+ && cache->lightadj[2] == r_drawsurf.lightadj[2]
+ && cache->lightadj[3] == r_drawsurf.lightadj[3] )
+ return cache;
+
+//
+// determine shape of surface
+//
+ surfscale = 1.0 / (1<<miplevel);
+ r_drawsurf.surfmip = miplevel;
+ r_drawsurf.surfwidth = surface->extents[0] >> miplevel;
+ r_drawsurf.rowbytes = r_drawsurf.surfwidth;
+ r_drawsurf.surfheight = surface->extents[1] >> miplevel;
+
+//
+// allocate memory if needed
+//
+ if (!cache) // if a texture just animated, don't reallocate it
+ {
+ cache = D_SCAlloc (r_drawsurf.surfwidth,
+ r_drawsurf.surfwidth * r_drawsurf.surfheight);
+ surface->cachespots[miplevel] = cache;
+ cache->owner = &surface->cachespots[miplevel];
+ cache->mipscale = surfscale;
+ }
+
+ if (surface->dlightframe == r_framecount)
+ cache->dlight = 1;
+ else
+ cache->dlight = 0;
+
+ r_drawsurf.surfdat = (pixel_t *)cache->data;
+
+ cache->image = r_drawsurf.image;
+ cache->lightadj[0] = r_drawsurf.lightadj[0];
+ cache->lightadj[1] = r_drawsurf.lightadj[1];
+ cache->lightadj[2] = r_drawsurf.lightadj[2];
+ cache->lightadj[3] = r_drawsurf.lightadj[3];
+
+//
+// draw and light the surface texture
+//
+ r_drawsurf.surf = surface;
+
+ c_surf++;
+
+ // calculate the lightings
+ R_BuildLightMap ();
+
+ // rasterize the surface into the cache
+ R_DrawSurface ();
+
+ return cache;
+}
+
+
--- /dev/null
+++ b/rand1k.h
@@ -1,0 +1,104 @@
+// 1K random numbers in the range 0-255
+0, 144, 49, 207, 149, 122, 89, 229, 210, 191,
+44, 219, 181, 131, 77, 3, 23, 93, 37, 42,
+253, 114, 30, 1, 2, 96, 136, 146, 154, 155,
+42, 169, 115, 90, 14, 155, 200, 205, 133, 77,
+224, 186, 244, 236, 138, 36, 118, 60, 220, 53,
+199, 215, 255, 255, 156, 100, 68, 76, 215, 6,
+96, 23, 173, 14, 2, 235, 70, 69, 150, 176,
+214, 185, 124, 52, 190, 119, 117, 242, 190, 27,
+153, 98, 188, 155, 146, 92, 38, 57, 108, 205,
+132, 253, 192, 88, 43, 168, 125, 16, 179, 129,
+37, 243, 36, 231, 177, 77, 109, 18, 247, 174,
+39, 224, 210, 149, 48, 45, 209, 121, 39, 129,
+187, 103, 71, 145, 174, 193, 184, 121, 31, 94,
+213, 8, 132, 169, 109, 26, 243, 235, 140, 88,
+120, 95, 216, 81, 116, 69, 251, 76, 189, 145,
+50, 194, 214, 101, 128, 227, 7, 254, 146, 12,
+136, 49, 215, 160, 168, 50, 215, 31, 28, 190,
+80, 240, 73, 86, 35, 187, 213, 181, 153, 191,
+64, 36, 0, 15, 206, 218, 53, 29, 141, 3,
+29, 116, 192, 175, 139, 18, 111, 51, 178, 74,
+111, 59, 147, 136, 160, 41, 129, 246, 178, 236,
+48, 86, 45, 254, 117, 255, 24, 160, 24, 112,
+238, 12, 229, 74, 58, 196, 105, 51, 160, 154,
+115, 119, 153, 162, 218, 212, 159, 184, 144, 96,
+47, 188, 142, 231, 62, 48, 154, 178, 149, 89,
+126, 20, 189, 156, 158, 176, 205, 38, 147, 222,
+233, 157, 186, 11, 170, 249, 80, 145, 78, 44,
+27, 222, 217, 190, 39, 83, 20, 19, 164, 209,
+139, 114, 104, 76, 119, 128, 39, 82, 188, 80,
+211, 245, 223, 185, 76, 241, 32, 16, 200, 134,
+156, 244, 18, 224, 167, 82, 26, 129, 58, 74,
+235, 141, 169, 29, 126, 97, 127, 203, 130, 97,
+176, 136, 155, 101, 1, 181, 25, 159, 220, 125,
+191, 127, 97, 201, 141, 91, 244, 161, 45, 95,
+33, 190, 243, 156, 7, 84, 14, 163, 33, 216,
+221, 152, 184, 218, 3, 32, 181, 157, 55, 16,
+43, 159, 87, 81, 94, 169, 205, 206, 134, 156,
+204, 230, 37, 161, 103, 64, 34, 218, 16, 109,
+146, 77, 140, 57, 79, 28, 206, 34, 72, 201,
+229, 202, 190, 157, 92, 219, 58, 221, 58, 63,
+138, 252, 13, 20, 134, 109, 24, 66, 228, 59,
+37, 32, 238, 20, 12, 15, 86, 234, 102, 110,
+242, 214, 136, 215, 177, 101, 66, 1, 134, 244,
+102, 61, 149, 65, 175, 241, 111, 227, 1, 240,
+153, 201, 147, 36, 56, 98, 1, 106, 21, 168,
+218, 16, 207, 169, 177, 205, 135, 175, 36, 176,
+186, 199, 7, 222, 164, 180, 21, 141, 242, 15,
+70, 37, 251, 158, 74, 236, 94, 177, 55, 39,
+61, 133, 230, 27, 231, 113, 20, 200, 43, 249,
+198, 222, 53, 116, 0, 192, 29, 103, 79, 254,
+9, 64, 48, 63, 39, 158, 226, 240, 50, 199,
+165, 168, 232, 116, 235, 170, 38, 162, 145, 108,
+241, 138, 148, 137, 65, 101, 89, 9, 203, 50,
+17, 99, 151, 18, 50, 39, 164, 116, 154, 178,
+112, 175, 101, 213, 151, 51, 243, 224, 100, 252,
+47, 229, 147, 113, 160, 181, 12, 73, 66, 104,
+229, 181, 186, 229, 100, 101, 231, 79, 99, 146,
+90, 187, 190, 188, 189, 35, 51, 69, 174, 233,
+94, 132, 28, 232, 51, 132, 167, 112, 176, 23,
+20, 19, 7, 90, 78, 178, 36, 101, 17, 172,
+185, 50, 177, 157, 167, 139, 25, 139, 12, 249,
+118, 248, 186, 135, 174, 177, 95, 99, 12, 207,
+43, 15, 79, 200, 54, 82, 124, 2, 112, 130,
+155, 194, 102, 89, 215, 241, 159, 255, 13, 144,
+221, 99, 78, 72, 6, 156, 100, 4, 7, 116,
+219, 239, 102, 186, 156, 206, 224, 149, 152, 20,
+203, 118, 151, 150, 145, 208, 172, 87, 2, 68,
+87, 59, 197, 95, 222, 29, 185, 161, 228, 46,
+137, 230, 199, 247, 50, 230, 204, 244, 217, 227,
+160, 47, 157, 67, 64, 187, 201, 43, 182, 123,
+20, 206, 218, 31, 78, 146, 121, 195, 49, 186,
+254, 3, 165, 177, 44, 18, 70, 173, 214, 142,
+95, 199, 59, 163, 59, 52, 248, 72, 5, 196,
+38, 12, 2, 89, 164, 87, 106, 106, 23, 139,
+179, 86, 168, 224, 137, 145, 13, 119, 66, 109,
+221, 124, 22, 144, 181, 199, 221, 217, 75, 221,
+165, 191, 212, 195, 223, 232, 233, 133, 112, 27,
+90, 210, 109, 43, 0, 168, 198, 16, 22, 98,
+175, 206, 39, 36, 12, 88, 4, 250, 165, 13,
+234, 163, 110, 5, 62, 100, 167, 200, 5, 211,
+35, 162, 140, 251, 118, 54, 76, 200, 87, 123,
+155, 26, 252, 193, 38, 116, 182, 255, 198, 164,
+159, 242, 176, 74, 145, 74, 140, 182, 63, 139,
+126, 243, 171, 195, 159, 114, 204, 190, 253, 52,
+161, 232, 151, 235, 129, 125, 115, 227, 240, 46,
+64, 51, 187, 240, 160, 10, 164, 8, 142, 139,
+114, 15, 254, 32, 153, 12, 44, 169, 85, 80,
+167, 105, 109, 56, 173, 42, 127, 129, 205, 111,
+1, 86, 96, 32, 211, 187, 228, 164, 166, 131,
+187, 188, 245, 119, 92, 28, 231, 210, 116, 27,
+222, 194, 10, 106, 239, 17, 42, 54, 29, 151,
+30, 158, 148, 176, 187, 234, 171, 76, 207, 96,
+255, 197, 52, 43, 99, 46, 148, 50, 245, 48,
+97, 77, 30, 50, 11, 197, 194, 225, 0, 114,
+109, 205, 118, 126, 191, 61, 143, 23, 236, 228,
+219, 15, 125, 161, 191, 193, 65, 232, 202, 51,
+141, 13, 133, 202, 180, 6, 187, 141, 234, 224,
+204, 78, 101, 123, 13, 166, 0, 196, 193, 56,
+39, 14, 171, 8, 88, 178, 204, 111, 251, 162,
+75, 122, 223, 20, 25, 36, 36, 235, 79, 95,
+208, 11, 208, 61, 229, 65, 68, 53, 58, 216,
+223, 227, 216, 155, 10, 44, 47, 91, 115, 47,
+228, 159, 139, 233
--- a/ref/adivtab.h
+++ /dev/null
@@ -1,1058 +1,0 @@
-// table of quotients and remainders for [-15...16] / [-15...16]
-
-// numerator = -15
-{1, 0},
-{1, -1},
-{1, -2},
-{1, -3},
-{1, -4},
-{1, -5},
-{1, -6},
-{1, -7},
-{2, -1},
-{2, -3},
-{3, 0},
-{3, -3},
-{5, 0},
-{7, -1},
-{15, 0},
-{0, 0},
-{-15, 0},
-{-8, 1},
-{-5, 0},
-{-4, 1},
-{-3, 0},
-{-3, 3},
-{-3, 6},
-{-2, 1},
-{-2, 3},
-{-2, 5},
-{-2, 7},
-{-2, 9},
-{-2, 11},
-{-2, 13},
-{-1, 0},
-{-1, 1},
-// numerator = -14
-{0, -14},
-{1, 0},
-{1, -1},
-{1, -2},
-{1, -3},
-{1, -4},
-{1, -5},
-{1, -6},
-{2, 0},
-{2, -2},
-{2, -4},
-{3, -2},
-{4, -2},
-{7, 0},
-{14, 0},
-{0, 0},
-{-14, 0},
-{-7, 0},
-{-5, 1},
-{-4, 2},
-{-3, 1},
-{-3, 4},
-{-2, 0},
-{-2, 2},
-{-2, 4},
-{-2, 6},
-{-2, 8},
-{-2, 10},
-{-2, 12},
-{-1, 0},
-{-1, 1},
-{-1, 2},
-// numerator = -13
-{0, -13},
-{0, -13},
-{1, 0},
-{1, -1},
-{1, -2},
-{1, -3},
-{1, -4},
-{1, -5},
-{1, -6},
-{2, -1},
-{2, -3},
-{3, -1},
-{4, -1},
-{6, -1},
-{13, 0},
-{0, 0},
-{-13, 0},
-{-7, 1},
-{-5, 2},
-{-4, 3},
-{-3, 2},
-{-3, 5},
-{-2, 1},
-{-2, 3},
-{-2, 5},
-{-2, 7},
-{-2, 9},
-{-2, 11},
-{-1, 0},
-{-1, 1},
-{-1, 2},
-{-1, 3},
-// numerator = -12
-{0, -12},
-{0, -12},
-{0, -12},
-{1, 0},
-{1, -1},
-{1, -2},
-{1, -3},
-{1, -4},
-{1, -5},
-{2, 0},
-{2, -2},
-{3, 0},
-{4, 0},
-{6, 0},
-{12, 0},
-{0, 0},
-{-12, 0},
-{-6, 0},
-{-4, 0},
-{-3, 0},
-{-3, 3},
-{-2, 0},
-{-2, 2},
-{-2, 4},
-{-2, 6},
-{-2, 8},
-{-2, 10},
-{-1, 0},
-{-1, 1},
-{-1, 2},
-{-1, 3},
-{-1, 4},
-// numerator = -11
-{0, -11},
-{0, -11},
-{0, -11},
-{0, -11},
-{1, 0},
-{1, -1},
-{1, -2},
-{1, -3},
-{1, -4},
-{1, -5},
-{2, -1},
-{2, -3},
-{3, -2},
-{5, -1},
-{11, 0},
-{0, 0},
-{-11, 0},
-{-6, 1},
-{-4, 1},
-{-3, 1},
-{-3, 4},
-{-2, 1},
-{-2, 3},
-{-2, 5},
-{-2, 7},
-{-2, 9},
-{-1, 0},
-{-1, 1},
-{-1, 2},
-{-1, 3},
-{-1, 4},
-{-1, 5},
-// numerator = -10
-{0, -10},
-{0, -10},
-{0, -10},
-{0, -10},
-{0, -10},
-{1, 0},
-{1, -1},
-{1, -2},
-{1, -3},
-{1, -4},
-{2, 0},
-{2, -2},
-{3, -1},
-{5, 0},
-{10, 0},
-{0, 0},
-{-10, 0},
-{-5, 0},
-{-4, 2},
-{-3, 2},
-{-2, 0},
-{-2, 2},
-{-2, 4},
-{-2, 6},
-{-2, 8},
-{-1, 0},
-{-1, 1},
-{-1, 2},
-{-1, 3},
-{-1, 4},
-{-1, 5},
-{-1, 6},
-// numerator = -9
-{0, -9},
-{0, -9},
-{0, -9},
-{0, -9},
-{0, -9},
-{0, -9},
-{1, 0},
-{1, -1},
-{1, -2},
-{1, -3},
-{1, -4},
-{2, -1},
-{3, 0},
-{4, -1},
-{9, 0},
-{0, 0},
-{-9, 0},
-{-5, 1},
-{-3, 0},
-{-3, 3},
-{-2, 1},
-{-2, 3},
-{-2, 5},
-{-2, 7},
-{-1, 0},
-{-1, 1},
-{-1, 2},
-{-1, 3},
-{-1, 4},
-{-1, 5},
-{-1, 6},
-{-1, 7},
-// numerator = -8
-{0, -8},
-{0, -8},
-{0, -8},
-{0, -8},
-{0, -8},
-{0, -8},
-{0, -8},
-{1, 0},
-{1, -1},
-{1, -2},
-{1, -3},
-{2, 0},
-{2, -2},
-{4, 0},
-{8, 0},
-{0, 0},
-{-8, 0},
-{-4, 0},
-{-3, 1},
-{-2, 0},
-{-2, 2},
-{-2, 4},
-{-2, 6},
-{-1, 0},
-{-1, 1},
-{-1, 2},
-{-1, 3},
-{-1, 4},
-{-1, 5},
-{-1, 6},
-{-1, 7},
-{-1, 8},
-// numerator = -7
-{0, -7},
-{0, -7},
-{0, -7},
-{0, -7},
-{0, -7},
-{0, -7},
-{0, -7},
-{0, -7},
-{1, 0},
-{1, -1},
-{1, -2},
-{1, -3},
-{2, -1},
-{3, -1},
-{7, 0},
-{0, 0},
-{-7, 0},
-{-4, 1},
-{-3, 2},
-{-2, 1},
-{-2, 3},
-{-2, 5},
-{-1, 0},
-{-1, 1},
-{-1, 2},
-{-1, 3},
-{-1, 4},
-{-1, 5},
-{-1, 6},
-{-1, 7},
-{-1, 8},
-{-1, 9},
-// numerator = -6
-{0, -6},
-{0, -6},
-{0, -6},
-{0, -6},
-{0, -6},
-{0, -6},
-{0, -6},
-{0, -6},
-{0, -6},
-{1, 0},
-{1, -1},
-{1, -2},
-{2, 0},
-{3, 0},
-{6, 0},
-{0, 0},
-{-6, 0},
-{-3, 0},
-{-2, 0},
-{-2, 2},
-{-2, 4},
-{-1, 0},
-{-1, 1},
-{-1, 2},
-{-1, 3},
-{-1, 4},
-{-1, 5},
-{-1, 6},
-{-1, 7},
-{-1, 8},
-{-1, 9},
-{-1, 10},
-// numerator = -5
-{0, -5},
-{0, -5},
-{0, -5},
-{0, -5},
-{0, -5},
-{0, -5},
-{0, -5},
-{0, -5},
-{0, -5},
-{0, -5},
-{1, 0},
-{1, -1},
-{1, -2},
-{2, -1},
-{5, 0},
-{0, 0},
-{-5, 0},
-{-3, 1},
-{-2, 1},
-{-2, 3},
-{-1, 0},
-{-1, 1},
-{-1, 2},
-{-1, 3},
-{-1, 4},
-{-1, 5},
-{-1, 6},
-{-1, 7},
-{-1, 8},
-{-1, 9},
-{-1, 10},
-{-1, 11},
-// numerator = -4
-{0, -4},
-{0, -4},
-{0, -4},
-{0, -4},
-{0, -4},
-{0, -4},
-{0, -4},
-{0, -4},
-{0, -4},
-{0, -4},
-{0, -4},
-{1, 0},
-{1, -1},
-{2, 0},
-{4, 0},
-{0, 0},
-{-4, 0},
-{-2, 0},
-{-2, 2},
-{-1, 0},
-{-1, 1},
-{-1, 2},
-{-1, 3},
-{-1, 4},
-{-1, 5},
-{-1, 6},
-{-1, 7},
-{-1, 8},
-{-1, 9},
-{-1, 10},
-{-1, 11},
-{-1, 12},
-// numerator = -3
-{0, -3},
-{0, -3},
-{0, -3},
-{0, -3},
-{0, -3},
-{0, -3},
-{0, -3},
-{0, -3},
-{0, -3},
-{0, -3},
-{0, -3},
-{0, -3},
-{1, 0},
-{1, -1},
-{3, 0},
-{0, 0},
-{-3, 0},
-{-2, 1},
-{-1, 0},
-{-1, 1},
-{-1, 2},
-{-1, 3},
-{-1, 4},
-{-1, 5},
-{-1, 6},
-{-1, 7},
-{-1, 8},
-{-1, 9},
-{-1, 10},
-{-1, 11},
-{-1, 12},
-{-1, 13},
-// numerator = -2
-{0, -2},
-{0, -2},
-{0, -2},
-{0, -2},
-{0, -2},
-{0, -2},
-{0, -2},
-{0, -2},
-{0, -2},
-{0, -2},
-{0, -2},
-{0, -2},
-{0, -2},
-{1, 0},
-{2, 0},
-{0, 0},
-{-2, 0},
-{-1, 0},
-{-1, 1},
-{-1, 2},
-{-1, 3},
-{-1, 4},
-{-1, 5},
-{-1, 6},
-{-1, 7},
-{-1, 8},
-{-1, 9},
-{-1, 10},
-{-1, 11},
-{-1, 12},
-{-1, 13},
-{-1, 14},
-// numerator = -1
-{0, -1},
-{0, -1},
-{0, -1},
-{0, -1},
-{0, -1},
-{0, -1},
-{0, -1},
-{0, -1},
-{0, -1},
-{0, -1},
-{0, -1},
-{0, -1},
-{0, -1},
-{0, -1},
-{1, 0},
-{0, 0},
-{-1, 0},
-{-1, 1},
-{-1, 2},
-{-1, 3},
-{-1, 4},
-{-1, 5},
-{-1, 6},
-{-1, 7},
-{-1, 8},
-{-1, 9},
-{-1, 10},
-{-1, 11},
-{-1, 12},
-{-1, 13},
-{-1, 14},
-{-1, 15},
-// numerator = 0
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-{0, 0},
-// numerator = 1
-{-1, -14},
-{-1, -13},
-{-1, -12},
-{-1, -11},
-{-1, -10},
-{-1, -9},
-{-1, -8},
-{-1, -7},
-{-1, -6},
-{-1, -5},
-{-1, -4},
-{-1, -3},
-{-1, -2},
-{-1, -1},
-{-1, 0},
-{0, 0},
-{1, 0},
-{0, 1},
-{0, 1},
-{0, 1},
-{0, 1},
-{0, 1},
-{0, 1},
-{0, 1},
-{0, 1},
-{0, 1},
-{0, 1},
-{0, 1},
-{0, 1},
-{0, 1},
-{0, 1},
-{0, 1},
-// numerator = 2
-{-1, -13},
-{-1, -12},
-{-1, -11},
-{-1, -10},
-{-1, -9},
-{-1, -8},
-{-1, -7},
-{-1, -6},
-{-1, -5},
-{-1, -4},
-{-1, -3},
-{-1, -2},
-{-1, -1},
-{-1, 0},
-{-2, 0},
-{0, 0},
-{2, 0},
-{1, 0},
-{0, 2},
-{0, 2},
-{0, 2},
-{0, 2},
-{0, 2},
-{0, 2},
-{0, 2},
-{0, 2},
-{0, 2},
-{0, 2},
-{0, 2},
-{0, 2},
-{0, 2},
-{0, 2},
-// numerator = 3
-{-1, -12},
-{-1, -11},
-{-1, -10},
-{-1, -9},
-{-1, -8},
-{-1, -7},
-{-1, -6},
-{-1, -5},
-{-1, -4},
-{-1, -3},
-{-1, -2},
-{-1, -1},
-{-1, 0},
-{-2, -1},
-{-3, 0},
-{0, 0},
-{3, 0},
-{1, 1},
-{1, 0},
-{0, 3},
-{0, 3},
-{0, 3},
-{0, 3},
-{0, 3},
-{0, 3},
-{0, 3},
-{0, 3},
-{0, 3},
-{0, 3},
-{0, 3},
-{0, 3},
-{0, 3},
-// numerator = 4
-{-1, -11},
-{-1, -10},
-{-1, -9},
-{-1, -8},
-{-1, -7},
-{-1, -6},
-{-1, -5},
-{-1, -4},
-{-1, -3},
-{-1, -2},
-{-1, -1},
-{-1, 0},
-{-2, -2},
-{-2, 0},
-{-4, 0},
-{0, 0},
-{4, 0},
-{2, 0},
-{1, 1},
-{1, 0},
-{0, 4},
-{0, 4},
-{0, 4},
-{0, 4},
-{0, 4},
-{0, 4},
-{0, 4},
-{0, 4},
-{0, 4},
-{0, 4},
-{0, 4},
-{0, 4},
-// numerator = 5
-{-1, -10},
-{-1, -9},
-{-1, -8},
-{-1, -7},
-{-1, -6},
-{-1, -5},
-{-1, -4},
-{-1, -3},
-{-1, -2},
-{-1, -1},
-{-1, 0},
-{-2, -3},
-{-2, -1},
-{-3, -1},
-{-5, 0},
-{0, 0},
-{5, 0},
-{2, 1},
-{1, 2},
-{1, 1},
-{1, 0},
-{0, 5},
-{0, 5},
-{0, 5},
-{0, 5},
-{0, 5},
-{0, 5},
-{0, 5},
-{0, 5},
-{0, 5},
-{0, 5},
-{0, 5},
-// numerator = 6
-{-1, -9},
-{-1, -8},
-{-1, -7},
-{-1, -6},
-{-1, -5},
-{-1, -4},
-{-1, -3},
-{-1, -2},
-{-1, -1},
-{-1, 0},
-{-2, -4},
-{-2, -2},
-{-2, 0},
-{-3, 0},
-{-6, 0},
-{0, 0},
-{6, 0},
-{3, 0},
-{2, 0},
-{1, 2},
-{1, 1},
-{1, 0},
-{0, 6},
-{0, 6},
-{0, 6},
-{0, 6},
-{0, 6},
-{0, 6},
-{0, 6},
-{0, 6},
-{0, 6},
-{0, 6},
-// numerator = 7
-{-1, -8},
-{-1, -7},
-{-1, -6},
-{-1, -5},
-{-1, -4},
-{-1, -3},
-{-1, -2},
-{-1, -1},
-{-1, 0},
-{-2, -5},
-{-2, -3},
-{-2, -1},
-{-3, -2},
-{-4, -1},
-{-7, 0},
-{0, 0},
-{7, 0},
-{3, 1},
-{2, 1},
-{1, 3},
-{1, 2},
-{1, 1},
-{1, 0},
-{0, 7},
-{0, 7},
-{0, 7},
-{0, 7},
-{0, 7},
-{0, 7},
-{0, 7},
-{0, 7},
-{0, 7},
-// numerator = 8
-{-1, -7},
-{-1, -6},
-{-1, -5},
-{-1, -4},
-{-1, -3},
-{-1, -2},
-{-1, -1},
-{-1, 0},
-{-2, -6},
-{-2, -4},
-{-2, -2},
-{-2, 0},
-{-3, -1},
-{-4, 0},
-{-8, 0},
-{0, 0},
-{8, 0},
-{4, 0},
-{2, 2},
-{2, 0},
-{1, 3},
-{1, 2},
-{1, 1},
-{1, 0},
-{0, 8},
-{0, 8},
-{0, 8},
-{0, 8},
-{0, 8},
-{0, 8},
-{0, 8},
-{0, 8},
-// numerator = 9
-{-1, -6},
-{-1, -5},
-{-1, -4},
-{-1, -3},
-{-1, -2},
-{-1, -1},
-{-1, 0},
-{-2, -7},
-{-2, -5},
-{-2, -3},
-{-2, -1},
-{-3, -3},
-{-3, 0},
-{-5, -1},
-{-9, 0},
-{0, 0},
-{9, 0},
-{4, 1},
-{3, 0},
-{2, 1},
-{1, 4},
-{1, 3},
-{1, 2},
-{1, 1},
-{1, 0},
-{0, 9},
-{0, 9},
-{0, 9},
-{0, 9},
-{0, 9},
-{0, 9},
-{0, 9},
-// numerator = 10
-{-1, -5},
-{-1, -4},
-{-1, -3},
-{-1, -2},
-{-1, -1},
-{-1, 0},
-{-2, -8},
-{-2, -6},
-{-2, -4},
-{-2, -2},
-{-2, 0},
-{-3, -2},
-{-4, -2},
-{-5, 0},
-{-10, 0},
-{0, 0},
-{10, 0},
-{5, 0},
-{3, 1},
-{2, 2},
-{2, 0},
-{1, 4},
-{1, 3},
-{1, 2},
-{1, 1},
-{1, 0},
-{0, 10},
-{0, 10},
-{0, 10},
-{0, 10},
-{0, 10},
-{0, 10},
-// numerator = 11
-{-1, -4},
-{-1, -3},
-{-1, -2},
-{-1, -1},
-{-1, 0},
-{-2, -9},
-{-2, -7},
-{-2, -5},
-{-2, -3},
-{-2, -1},
-{-3, -4},
-{-3, -1},
-{-4, -1},
-{-6, -1},
-{-11, 0},
-{0, 0},
-{11, 0},
-{5, 1},
-{3, 2},
-{2, 3},
-{2, 1},
-{1, 5},
-{1, 4},
-{1, 3},
-{1, 2},
-{1, 1},
-{1, 0},
-{0, 11},
-{0, 11},
-{0, 11},
-{0, 11},
-{0, 11},
-// numerator = 12
-{-1, -3},
-{-1, -2},
-{-1, -1},
-{-1, 0},
-{-2, -10},
-{-2, -8},
-{-2, -6},
-{-2, -4},
-{-2, -2},
-{-2, 0},
-{-3, -3},
-{-3, 0},
-{-4, 0},
-{-6, 0},
-{-12, 0},
-{0, 0},
-{12, 0},
-{6, 0},
-{4, 0},
-{3, 0},
-{2, 2},
-{2, 0},
-{1, 5},
-{1, 4},
-{1, 3},
-{1, 2},
-{1, 1},
-{1, 0},
-{0, 12},
-{0, 12},
-{0, 12},
-{0, 12},
-// numerator = 13
-{-1, -2},
-{-1, -1},
-{-1, 0},
-{-2, -11},
-{-2, -9},
-{-2, -7},
-{-2, -5},
-{-2, -3},
-{-2, -1},
-{-3, -5},
-{-3, -2},
-{-4, -3},
-{-5, -2},
-{-7, -1},
-{-13, 0},
-{0, 0},
-{13, 0},
-{6, 1},
-{4, 1},
-{3, 1},
-{2, 3},
-{2, 1},
-{1, 6},
-{1, 5},
-{1, 4},
-{1, 3},
-{1, 2},
-{1, 1},
-{1, 0},
-{0, 13},
-{0, 13},
-{0, 13},
-// numerator = 14
-{-1, -1},
-{-1, 0},
-{-2, -12},
-{-2, -10},
-{-2, -8},
-{-2, -6},
-{-2, -4},
-{-2, -2},
-{-2, 0},
-{-3, -4},
-{-3, -1},
-{-4, -2},
-{-5, -1},
-{-7, 0},
-{-14, 0},
-{0, 0},
-{14, 0},
-{7, 0},
-{4, 2},
-{3, 2},
-{2, 4},
-{2, 2},
-{2, 0},
-{1, 6},
-{1, 5},
-{1, 4},
-{1, 3},
-{1, 2},
-{1, 1},
-{1, 0},
-{0, 14},
-{0, 14},
-// numerator = 15
-{-1, 0},
-{-2, -13},
-{-2, -11},
-{-2, -9},
-{-2, -7},
-{-2, -5},
-{-2, -3},
-{-2, -1},
-{-3, -6},
-{-3, -3},
-{-3, 0},
-{-4, -1},
-{-5, 0},
-{-8, -1},
-{-15, 0},
-{0, 0},
-{15, 0},
-{7, 1},
-{5, 0},
-{3, 3},
-{3, 0},
-{2, 3},
-{2, 1},
-{1, 7},
-{1, 6},
-{1, 5},
-{1, 4},
-{1, 3},
-{1, 2},
-{1, 1},
-{1, 0},
-{0, 15},
-// numerator = 16
-{-2, -14},
-{-2, -12},
-{-2, -10},
-{-2, -8},
-{-2, -6},
-{-2, -4},
-{-2, -2},
-{-2, 0},
-{-3, -5},
-{-3, -2},
-{-4, -4},
-{-4, 0},
-{-6, -2},
-{-8, 0},
-{-16, 0},
-{0, 0},
-{16, 0},
-{8, 0},
-{5, 1},
-{4, 0},
-{3, 1},
-{2, 4},
-{2, 2},
-{2, 0},
-{1, 7},
-{1, 6},
-{1, 5},
-{1, 4},
-{1, 3},
-{1, 2},
-{1, 1},
-{1, 0},
--- a/ref/r_aclip.c
+++ /dev/null
@@ -1,303 +1,0 @@
-// r_aclip.c: clip routines for drawing Alias models directly to the screen
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-static finalvert_t fv[2][8];
-
-void R_AliasProjectAndClipTestFinalVert (finalvert_t *fv);
-void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1,
- finalvert_t *out);
-void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1,
- finalvert_t *out);
-void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1,
- finalvert_t *out);
-void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1,
- finalvert_t *out);
-
-
-/*
-================
-R_Alias_clip_z
-
-pfv0 is the unclipped vertex, pfv1 is the z-clipped vertex
-================
-*/
-void R_Alias_clip_z (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
-{
- float scale;
-
- scale = (ALIAS_Z_CLIP_PLANE - pfv0->xyz[2]) /
- (pfv1->xyz[2] - pfv0->xyz[2]);
-
- out->xyz[0] = pfv0->xyz[0] + (pfv1->xyz[0] - pfv0->xyz[0]) * scale;
- out->xyz[1] = pfv0->xyz[1] + (pfv1->xyz[1] - pfv0->xyz[1]) * scale;
- out->xyz[2] = ALIAS_Z_CLIP_PLANE;
-
- out->s = pfv0->s + (pfv1->s - pfv0->s) * scale;
- out->t = pfv0->t + (pfv1->t - pfv0->t) * scale;
- out->l = pfv0->l + (pfv1->l - pfv0->l) * scale;
-
- R_AliasProjectAndClipTestFinalVert (out);
-}
-
-
-void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
-{
- float scale;
-
- if (pfv0->v >= pfv1->v )
- {
- scale = (float)(r_refdef.aliasvrect.x - pfv0->u) /
- (pfv1->u - pfv0->u);
- out->u = pfv0->u + ( pfv1->u - pfv0->u ) * scale + 0.5;
- out->v = pfv0->v + ( pfv1->v - pfv0->v ) * scale + 0.5;
- out->s = pfv0->s + ( pfv1->s - pfv0->s ) * scale + 0.5;
- out->t = pfv0->t + ( pfv1->t - pfv0->t ) * scale + 0.5;
- out->l = pfv0->l + ( pfv1->l - pfv0->l ) * scale + 0.5;
- out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
- }
- else
- {
- scale = (float)(r_refdef.aliasvrect.x - pfv1->u) /
- (pfv0->u - pfv1->u);
- out->u = pfv1->u + ( pfv0->u - pfv1->u ) * scale + 0.5;
- out->v = pfv1->v + ( pfv0->v - pfv1->v ) * scale + 0.5;
- out->s = pfv1->s + ( pfv0->s - pfv1->s ) * scale + 0.5;
- out->t = pfv1->t + ( pfv0->t - pfv1->t ) * scale + 0.5;
- out->l = pfv1->l + ( pfv0->l - pfv1->l ) * scale + 0.5;
- out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
- }
-}
-
-
-void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
-{
- float scale;
-
- if ( pfv0->v >= pfv1->v )
- {
- scale = (float)(r_refdef.aliasvrectright - pfv0->u ) /
- (pfv1->u - pfv0->u );
- out->u = pfv0->u + ( pfv1->u - pfv0->u ) * scale + 0.5;
- out->v = pfv0->v + ( pfv1->v - pfv0->v ) * scale + 0.5;
- out->s = pfv0->s + ( pfv1->s - pfv0->s ) * scale + 0.5;
- out->t = pfv0->t + ( pfv1->t - pfv0->t ) * scale + 0.5;
- out->l = pfv0->l + ( pfv1->l - pfv0->l ) * scale + 0.5;
- out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
- }
- else
- {
- scale = (float)(r_refdef.aliasvrectright - pfv1->u ) /
- (pfv0->u - pfv1->u );
- out->u = pfv1->u + ( pfv0->u - pfv1->u ) * scale + 0.5;
- out->v = pfv1->v + ( pfv0->v - pfv1->v ) * scale + 0.5;
- out->s = pfv1->s + ( pfv0->s - pfv1->s ) * scale + 0.5;
- out->t = pfv1->t + ( pfv0->t - pfv1->t ) * scale + 0.5;
- out->l = pfv1->l + ( pfv0->l - pfv1->l ) * scale + 0.5;
- out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
- }
-}
-
-
-void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
-{
- float scale;
-
- if (pfv0->v >= pfv1->v)
- {
- scale = (float)(r_refdef.aliasvrect.y - pfv0->v) /
- (pfv1->v - pfv0->v);
- out->u = pfv0->u + ( pfv1->u - pfv0->u ) * scale + 0.5;
- out->v = pfv0->v + ( pfv1->v - pfv0->v ) * scale + 0.5;
- out->s = pfv0->s + ( pfv1->s - pfv0->s ) * scale + 0.5;
- out->t = pfv0->t + ( pfv1->t - pfv0->t ) * scale + 0.5;
- out->l = pfv0->l + ( pfv1->l - pfv0->l ) * scale + 0.5;
- out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
- }
- else
- {
- scale = (float)(r_refdef.aliasvrect.y - pfv1->v) /
- (pfv0->v - pfv1->v);
- out->u = pfv1->u + ( pfv0->u - pfv1->u ) * scale + 0.5;
- out->v = pfv1->v + ( pfv0->v - pfv1->v ) * scale + 0.5;
- out->s = pfv1->s + ( pfv0->s - pfv1->s ) * scale + 0.5;
- out->t = pfv1->t + ( pfv0->t - pfv1->t ) * scale + 0.5;
- out->l = pfv1->l + ( pfv0->l - pfv1->l ) * scale + 0.5;
- out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
- }
-}
-
-
-void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1,
- finalvert_t *out)
-{
- float scale;
-
- if (pfv0->v >= pfv1->v)
- {
- scale = (float)(r_refdef.aliasvrectbottom - pfv0->v) /
- (pfv1->v - pfv0->v);
-
- out->u = pfv0->u + ( pfv1->u - pfv0->u ) * scale + 0.5;
- out->v = pfv0->v + ( pfv1->v - pfv0->v ) * scale + 0.5;
- out->s = pfv0->s + ( pfv1->s - pfv0->s ) * scale + 0.5;
- out->t = pfv0->t + ( pfv1->t - pfv0->t ) * scale + 0.5;
- out->l = pfv0->l + ( pfv1->l - pfv0->l ) * scale + 0.5;
- out->zi = pfv0->zi + ( pfv1->zi - pfv0->zi) * scale + 0.5;
- }
- else
- {
- scale = (float)(r_refdef.aliasvrectbottom - pfv1->v) /
- (pfv0->v - pfv1->v);
-
- out->u = pfv1->u + ( pfv0->u - pfv1->u ) * scale + 0.5;
- out->v = pfv1->v + ( pfv0->v - pfv1->v ) * scale + 0.5;
- out->s = pfv1->s + ( pfv0->s - pfv1->s ) * scale + 0.5;
- out->t = pfv1->t + ( pfv0->t - pfv1->t ) * scale + 0.5;
- out->l = pfv1->l + ( pfv0->l - pfv1->l ) * scale + 0.5;
- out->zi = pfv1->zi + ( pfv0->zi - pfv1->zi) * scale + 0.5;
- }
-}
-
-
-int R_AliasClip (finalvert_t *in, finalvert_t *out, int flag, int count,
- void(*clip)(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) )
-{
- int i,j,k;
- int flags, oldflags;
-
- j = count-1;
- k = 0;
- for (i=0 ; i<count ; j = i, i++)
- {
- oldflags = in[j].flags & flag;
- flags = in[i].flags & flag;
-
- if (flags && oldflags)
- continue;
- if (oldflags ^ flags)
- {
- clip (&in[j], &in[i], &out[k]);
- out[k].flags = 0;
- if (out[k].u < r_refdef.aliasvrect.x)
- out[k].flags |= ALIAS_LEFT_CLIP;
- if (out[k].v < r_refdef.aliasvrect.y)
- out[k].flags |= ALIAS_TOP_CLIP;
- if (out[k].u > r_refdef.aliasvrectright)
- out[k].flags |= ALIAS_RIGHT_CLIP;
- if (out[k].v > r_refdef.aliasvrectbottom)
- out[k].flags |= ALIAS_BOTTOM_CLIP;
- k++;
- }
- if (!flags)
- {
- out[k] = in[i];
- k++;
- }
- }
-
- return k;
-}
-
-
-/*
-================
-R_AliasClipTriangle
-================
-*/
-void R_AliasClipTriangle (finalvert_t *index0, finalvert_t *index1, finalvert_t *index2)
-{
- int i, k, pingpong;
- unsigned clipflags;
-
-// copy vertexes and fix seam texture coordinates
- fv[0][0] = *index0;
- fv[0][1] = *index1;
- fv[0][2] = *index2;
-
-// clip
- clipflags = fv[0][0].flags | fv[0][1].flags | fv[0][2].flags;
-
- if (clipflags & ALIAS_Z_CLIP)
- {
- k = R_AliasClip (fv[0], fv[1], ALIAS_Z_CLIP, 3, R_Alias_clip_z);
- if (k == 0)
- return;
-
- pingpong = 1;
- clipflags = fv[1][0].flags | fv[1][1].flags | fv[1][2].flags;
- }
- else
- {
- pingpong = 0;
- k = 3;
- }
-
- if (clipflags & ALIAS_LEFT_CLIP)
- {
- k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
- ALIAS_LEFT_CLIP, k, R_Alias_clip_left);
- if (k == 0)
- return;
-
- pingpong ^= 1;
- }
-
- if (clipflags & ALIAS_RIGHT_CLIP)
- {
- k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
- ALIAS_RIGHT_CLIP, k, R_Alias_clip_right);
- if (k == 0)
- return;
-
- pingpong ^= 1;
- }
-
- if (clipflags & ALIAS_BOTTOM_CLIP)
- {
- k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
- ALIAS_BOTTOM_CLIP, k, R_Alias_clip_bottom);
- if (k == 0)
- return;
-
- pingpong ^= 1;
- }
-
- if (clipflags & ALIAS_TOP_CLIP)
- {
- k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
- ALIAS_TOP_CLIP, k, R_Alias_clip_top);
- if (k == 0)
- return;
-
- pingpong ^= 1;
- }
-
- for (i=0 ; i<k ; i++)
- {
- if (fv[pingpong][i].u < r_refdef.aliasvrect.x)
- fv[pingpong][i].u = r_refdef.aliasvrect.x;
- else if (fv[pingpong][i].u > r_refdef.aliasvrectright)
- fv[pingpong][i].u = r_refdef.aliasvrectright;
-
- if (fv[pingpong][i].v < r_refdef.aliasvrect.y)
- fv[pingpong][i].v = r_refdef.aliasvrect.y;
- else if (fv[pingpong][i].v > r_refdef.aliasvrectbottom)
- fv[pingpong][i].v = r_refdef.aliasvrectbottom;
-
- fv[pingpong][i].flags = 0;
- }
-
-// draw triangles
- for (i=1 ; i<k-1 ; i++)
- {
- aliastriangleparms.a = &fv[pingpong][0];
- aliastriangleparms.b = &fv[pingpong][i];
- aliastriangleparms.c = &fv[pingpong][i+1];
- R_DrawTriangle();
- }
-}
-
--- a/ref/r_alias.c
+++ /dev/null
@@ -1,860 +1,0 @@
-// r_alias.c: routines for setting up to draw alias models
-
-/*
-** use a real variable to control lerping
-*/
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-#define LIGHT_MIN 5 // lowest light value we'll allow, to avoid the
- // need for inner-loop light clamping
-
-//PGM
-extern byte iractive;
-//PGM
-
-int r_amodels_drawn;
-
-affinetridesc_t r_affinetridesc;
-
-vec3_t r_plightvec;
-vec3_t r_lerped[1024];
-vec3_t r_lerp_frontv, r_lerp_backv, r_lerp_move;
-
-int r_ambientlight;
-int r_aliasblendcolor;
-float r_shadelight;
-
-
-daliasframe_t *r_thisframe, *r_lastframe;
-dmdl_t *s_pmdl;
-
-float aliastransform[3][4];
-float aliasworldtransform[3][4];
-float aliasoldworldtransform[3][4];
-
-static float s_ziscale;
-static vec3_t s_alias_forward, s_alias_right, s_alias_up;
-
-
-float r_avertexnormals[NUMVERTEXNORMALS][3] = {
-#include "../anorms.h"
-};
-
-
-void R_AliasSetUpLerpData( dmdl_t *pmdl, float backlerp );
-void R_AliasSetUpTransform (void);
-void R_AliasTransformVector (vec3_t in, vec3_t out, float m[3][4] );
-void R_AliasProjectAndClipTestFinalVert (finalvert_t *fv);
-
-void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv );
-
-void R_AliasLerpFrames( dmdl_t *paliashdr, float backlerp );
-
-/*
-================
-R_AliasCheckBBox
-================
-*/
-typedef struct {
- int index0;
- int index1;
-} aedge_t;
-
-static aedge_t aedges[12] = {
-{0, 1}, {1, 2}, {2, 3}, {3, 0},
-{4, 5}, {5, 6}, {6, 7}, {7, 4},
-{0, 5}, {1, 4}, {2, 7}, {3, 6}
-};
-
-#define BBOX_TRIVIAL_ACCEPT 0
-#define BBOX_MUST_CLIP_XY 1
-#define BBOX_MUST_CLIP_Z 2
-#define BBOX_TRIVIAL_REJECT 8
-
-/*
-** R_AliasCheckFrameBBox
-**
-** Checks a specific alias frame bounding box
-*/
-unsigned long R_AliasCheckFrameBBox( daliasframe_t *frame, float worldxf[3][4] )
-{
- unsigned long aggregate_and_clipcode = ~0U,
- aggregate_or_clipcode = 0;
- int i;
- vec3_t mins, maxs;
- vec3_t transformed_min, transformed_max;
- qboolean zclipped = false, zfullyclipped = true;
- //float minz = 9999.0F;
-
- /*
- ** get the exact frame bounding box
- */
- for (i=0 ; i<3 ; i++)
- {
- mins[i] = frame->translate[i];
- maxs[i] = mins[i] + frame->scale[i]*255;
- }
-
- /*
- ** transform the min and max values into view space
- */
- R_AliasTransformVector( mins, transformed_min, aliastransform );
- R_AliasTransformVector( maxs, transformed_max, aliastransform );
-
- if ( transformed_min[2] >= ALIAS_Z_CLIP_PLANE )
- zfullyclipped = false;
- if ( transformed_max[2] >= ALIAS_Z_CLIP_PLANE )
- zfullyclipped = false;
-
- if ( zfullyclipped )
- {
- return BBOX_TRIVIAL_REJECT;
- }
- if ( zclipped )
- {
- return ( BBOX_MUST_CLIP_XY | BBOX_MUST_CLIP_Z );
- }
-
- /*
- ** build a transformed bounding box from the given min and max
- */
- for ( i = 0; i < 8; i++ )
- {
- int j;
- vec3_t tmp, transformed;
- unsigned long clipcode = 0;
-
- if ( i & 1 )
- tmp[0] = mins[0];
- else
- tmp[0] = maxs[0];
-
- if ( i & 2 )
- tmp[1] = mins[1];
- else
- tmp[1] = maxs[1];
-
- if ( i & 4 )
- tmp[2] = mins[2];
- else
- tmp[2] = maxs[2];
-
- R_AliasTransformVector( tmp, transformed, worldxf );
-
- for ( j = 0; j < 4; j++ )
- {
- float dp = DotProduct( transformed, view_clipplanes[j].normal );
-
- if ( ( dp - view_clipplanes[j].dist ) < 0.0F )
- clipcode |= 1 << j;
- }
-
- aggregate_and_clipcode &= clipcode;
- aggregate_or_clipcode |= clipcode;
- }
-
- if ( aggregate_and_clipcode )
- {
- return BBOX_TRIVIAL_REJECT;
- }
- if ( !aggregate_or_clipcode )
- {
- return BBOX_TRIVIAL_ACCEPT;
- }
-
- return BBOX_MUST_CLIP_XY;
-}
-
-qboolean R_AliasCheckBBox (void)
-{
- unsigned long ccodes[2] = { 0, 0 };
-
- ccodes[0] = R_AliasCheckFrameBBox( r_thisframe, aliasworldtransform );
-
- /*
- ** non-lerping model
- */
- if ( currententity->backlerp == 0 )
- {
- if ( ccodes[0] == BBOX_TRIVIAL_ACCEPT )
- return BBOX_TRIVIAL_ACCEPT;
- else if ( ccodes[0] & BBOX_TRIVIAL_REJECT )
- return BBOX_TRIVIAL_REJECT;
- else
- return ( ccodes[0] & ~BBOX_TRIVIAL_REJECT );
- }
-
- ccodes[1] = R_AliasCheckFrameBBox( r_lastframe, aliasoldworldtransform );
-
- if ( ( ccodes[0] | ccodes[1] ) == BBOX_TRIVIAL_ACCEPT )
- return BBOX_TRIVIAL_ACCEPT;
- else if ( ( ccodes[0] & ccodes[1] ) & BBOX_TRIVIAL_REJECT )
- return BBOX_TRIVIAL_REJECT;
- else
- return ( ccodes[0] | ccodes[1] ) & ~BBOX_TRIVIAL_REJECT;
-}
-
-
-/*
-================
-R_AliasTransformVector
-================
-*/
-void R_AliasTransformVector(vec3_t in, vec3_t out, float xf[3][4] )
-{
- out[0] = DotProduct(in, xf[0]) + xf[0][3];
- out[1] = DotProduct(in, xf[1]) + xf[1][3];
- out[2] = DotProduct(in, xf[2]) + xf[2][3];
-}
-
-
-/*
-================
-R_AliasPreparePoints
-
-General clipped case
-================
-*/
-typedef struct
-{
- int num_points;
- dtrivertx_t *last_verts; // verts from the last frame
- dtrivertx_t *this_verts; // verts from this frame
- finalvert_t *dest_verts; // destination for transformed verts
-} aliasbatchedtransformdata_t;
-
-aliasbatchedtransformdata_t aliasbatchedtransformdata;
-
-void R_AliasPreparePoints (void)
-{
- int i;
- dstvert_t *pstverts;
- dtriangle_t *ptri;
- finalvert_t *pfv[3];
- finalvert_t finalverts[MAXALIASVERTS +
- ((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 3];
- finalvert_t *pfinalverts;
-
-//PGM
- iractive = (r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE);
-// iractive = 0;
-// if(r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE)
-// iractive = 1;
-//PGM
-
- // put work vertexes on stack, cache aligned
- pfinalverts = (finalvert_t *)
- (((uintptr)&finalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
-
- aliasbatchedtransformdata.num_points = s_pmdl->num_xyz;
- aliasbatchedtransformdata.last_verts = r_lastframe->verts;
- aliasbatchedtransformdata.this_verts = r_thisframe->verts;
- aliasbatchedtransformdata.dest_verts = pfinalverts;
-
- R_AliasTransformFinalVerts( aliasbatchedtransformdata.num_points,
- aliasbatchedtransformdata.dest_verts,
- aliasbatchedtransformdata.last_verts,
- aliasbatchedtransformdata.this_verts );
-
-// clip and draw all triangles
-//
- pstverts = (dstvert_t *)((byte *)s_pmdl + s_pmdl->ofs_st);
- ptri = (dtriangle_t *)((byte *)s_pmdl + s_pmdl->ofs_tris);
-
- if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
- {
- for (i=0 ; i<s_pmdl->num_tris ; i++, ptri++)
- {
- pfv[0] = &pfinalverts[ptri->index_xyz[0]];
- pfv[1] = &pfinalverts[ptri->index_xyz[1]];
- pfv[2] = &pfinalverts[ptri->index_xyz[2]];
-
- if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags )
- continue; // completely clipped
-
- // insert s/t coordinates
- pfv[0]->s = pstverts[ptri->index_st[0]].s << 16;
- pfv[0]->t = pstverts[ptri->index_st[0]].t << 16;
-
- pfv[1]->s = pstverts[ptri->index_st[1]].s << 16;
- pfv[1]->t = pstverts[ptri->index_st[1]].t << 16;
-
- pfv[2]->s = pstverts[ptri->index_st[2]].s << 16;
- pfv[2]->t = pstverts[ptri->index_st[2]].t << 16;
-
- if ( ! (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) )
- { // totally unclipped
- aliastriangleparms.a = pfv[2];
- aliastriangleparms.b = pfv[1];
- aliastriangleparms.c = pfv[0];
-
- R_DrawTriangle();
- }
- else
- {
- R_AliasClipTriangle (pfv[2], pfv[1], pfv[0]);
- }
- }
- }
- else
- {
- for (i=0 ; i<s_pmdl->num_tris ; i++, ptri++)
- {
- pfv[0] = &pfinalverts[ptri->index_xyz[0]];
- pfv[1] = &pfinalverts[ptri->index_xyz[1]];
- pfv[2] = &pfinalverts[ptri->index_xyz[2]];
-
- if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags )
- continue; // completely clipped
-
- // insert s/t coordinates
- pfv[0]->s = pstverts[ptri->index_st[0]].s << 16;
- pfv[0]->t = pstverts[ptri->index_st[0]].t << 16;
-
- pfv[1]->s = pstverts[ptri->index_st[1]].s << 16;
- pfv[1]->t = pstverts[ptri->index_st[1]].t << 16;
-
- pfv[2]->s = pstverts[ptri->index_st[2]].s << 16;
- pfv[2]->t = pstverts[ptri->index_st[2]].t << 16;
-
- if ( ! (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) )
- { // totally unclipped
- aliastriangleparms.a = pfv[0];
- aliastriangleparms.b = pfv[1];
- aliastriangleparms.c = pfv[2];
-
- R_DrawTriangle();
- }
- else
- { // partially clipped
- R_AliasClipTriangle (pfv[0], pfv[1], pfv[2]);
- }
- }
- }
-}
-
-
-/*
-================
-R_AliasSetUpTransform
-================
-*/
-void R_AliasSetUpTransform (void)
-{
- int i;
- static float viewmatrix[3][4];
- vec3_t angles;
-
-// TODO: should really be stored with the entity instead of being reconstructed
-// TODO: should use a look-up table
-// TODO: could cache lazily, stored in the entity
-//
- angles[ROLL] = currententity->angles[ROLL];
- angles[PITCH] = currententity->angles[PITCH];
- angles[YAW] = currententity->angles[YAW];
- AngleVectors( angles, s_alias_forward, s_alias_right, s_alias_up );
-
-// TODO: can do this with simple matrix rearrangement
-
- memset( aliasworldtransform, 0, sizeof( aliasworldtransform ) );
- memset( aliasoldworldtransform, 0, sizeof( aliasworldtransform ) );
-
- for (i=0 ; i<3 ; i++)
- {
- aliasoldworldtransform[i][0] = aliasworldtransform[i][0] = s_alias_forward[i];
- aliasoldworldtransform[i][0] = aliasworldtransform[i][1] = -s_alias_right[i];
- aliasoldworldtransform[i][0] = aliasworldtransform[i][2] = s_alias_up[i];
- }
-
- aliasworldtransform[0][3] = currententity->origin[0]-r_origin[0];
- aliasworldtransform[1][3] = currententity->origin[1]-r_origin[1];
- aliasworldtransform[2][3] = currententity->origin[2]-r_origin[2];
-
- aliasoldworldtransform[0][3] = currententity->oldorigin[0]-r_origin[0];
- aliasoldworldtransform[1][3] = currententity->oldorigin[1]-r_origin[1];
- aliasoldworldtransform[2][3] = currententity->oldorigin[2]-r_origin[2];
-
-// FIXME: can do more efficiently than full concatenation
-// memcpy( rotationmatrix, t2matrix, sizeof( rotationmatrix ) );
-
-// R_ConcatTransforms (t2matrix, tmatrix, rotationmatrix);
-
-// TODO: should be global, set when vright, etc., set
- VectorCopy (vright, viewmatrix[0]);
- VectorCopy (vup, viewmatrix[1]);
- VectorInverse (viewmatrix[1]);
- VectorCopy (vpn, viewmatrix[2]);
-
- viewmatrix[0][3] = 0;
- viewmatrix[1][3] = 0;
- viewmatrix[2][3] = 0;
-
-// memcpy( aliasworldtransform, rotationmatrix, sizeof( aliastransform ) );
-
- R_ConcatTransforms (viewmatrix, aliasworldtransform, aliastransform);
-
- aliasworldtransform[0][3] = currententity->origin[0];
- aliasworldtransform[1][3] = currententity->origin[1];
- aliasworldtransform[2][3] = currententity->origin[2];
-
- aliasoldworldtransform[0][3] = currententity->oldorigin[0];
- aliasoldworldtransform[1][3] = currententity->oldorigin[1];
- aliasoldworldtransform[2][3] = currententity->oldorigin[2];
-}
-
-
-/*
-================
-R_AliasTransformFinalVerts
-================
-*/
-void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv )
-{
- int i;
-
- for ( i = 0; i < numpoints; i++, fv++, oldv++, newv++ )
- {
- int temp;
- float lightcos, *plightnormal;
- vec3_t lerped_vert;
-
- lerped_vert[0] = r_lerp_move[0] + oldv->v[0]*r_lerp_backv[0] + newv->v[0]*r_lerp_frontv[0];
- lerped_vert[1] = r_lerp_move[1] + oldv->v[1]*r_lerp_backv[1] + newv->v[1]*r_lerp_frontv[1];
- lerped_vert[2] = r_lerp_move[2] + oldv->v[2]*r_lerp_backv[2] + newv->v[2]*r_lerp_frontv[2];
-
- plightnormal = r_avertexnormals[newv->lightnormalindex];
-
- // PMM - added double damage shell
- if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
- {
- lerped_vert[0] += plightnormal[0] * POWERSUIT_SCALE;
- lerped_vert[1] += plightnormal[1] * POWERSUIT_SCALE;
- lerped_vert[2] += plightnormal[2] * POWERSUIT_SCALE;
- }
-
- fv->xyz[0] = DotProduct(lerped_vert, aliastransform[0]) + aliastransform[0][3];
- fv->xyz[1] = DotProduct(lerped_vert, aliastransform[1]) + aliastransform[1][3];
- fv->xyz[2] = DotProduct(lerped_vert, aliastransform[2]) + aliastransform[2][3];
-
- fv->flags = 0;
-
- // lighting
- lightcos = DotProduct (plightnormal, r_plightvec);
- temp = r_ambientlight;
-
- if (lightcos < 0)
- {
- temp += (int)(r_shadelight * lightcos);
-
- // clamp; because we limited the minimum ambient and shading light, we
- // don't have to clamp low light, just bright
- if (temp < 0)
- temp = 0;
- }
-
- fv->l = temp;
-
- if ( fv->xyz[2] < ALIAS_Z_CLIP_PLANE )
- {
- fv->flags |= ALIAS_Z_CLIP;
- }
- else
- {
- R_AliasProjectAndClipTestFinalVert( fv );
- }
- }
-}
-
-/*
-================
-R_AliasProjectAndClipTestFinalVert
-================
-*/
-void R_AliasProjectAndClipTestFinalVert( finalvert_t *fv )
-{
- float zi;
- float x, y, z;
-
- // project points
- x = fv->xyz[0];
- y = fv->xyz[1];
- z = fv->xyz[2];
- zi = 1.0 / z;
-
- fv->zi = zi * s_ziscale;
-
- fv->u = (x * aliasxscale * zi) + aliasxcenter;
- fv->v = (y * aliasyscale * zi) + aliasycenter;
-
- if (fv->u < r_refdef.aliasvrect.x)
- fv->flags |= ALIAS_LEFT_CLIP;
- if (fv->v < r_refdef.aliasvrect.y)
- fv->flags |= ALIAS_TOP_CLIP;
- if (fv->u > r_refdef.aliasvrectright)
- fv->flags |= ALIAS_RIGHT_CLIP;
- if (fv->v > r_refdef.aliasvrectbottom)
- fv->flags |= ALIAS_BOTTOM_CLIP;
-}
-
-/*
-===============
-R_AliasSetupSkin
-===============
-*/
-static qboolean R_AliasSetupSkin (void)
-{
- int skinnum;
- image_t *pskindesc;
-
- if (currententity->skin)
- pskindesc = currententity->skin;
- else
- {
- skinnum = currententity->skinnum;
- if ((skinnum >= s_pmdl->num_skins) || (skinnum < 0))
- {
- ri.Con_Printf (PRINT_ALL, "R_AliasSetupSkin %s: no such skin # %d\n",
- currentmodel->name, skinnum);
- skinnum = 0;
- }
-
- pskindesc = currentmodel->skins[skinnum];
- }
-
- if ( !pskindesc )
- return false;
-
- r_affinetridesc.pskin = pskindesc->pixels[0];
- r_affinetridesc.skinwidth = pskindesc->width;
- r_affinetridesc.skinheight = pskindesc->height;
-
- R_PolysetUpdateTables (); // FIXME: precalc edge lookups
-
- return true;
-}
-
-
-/*
-================
-R_AliasSetupLighting
-
- FIXME: put lighting into tables
-================
-*/
-void R_AliasSetupLighting (void)
-{
- alight_t lighting;
- float lightvec[3] = {-1, 0, 0};
- vec3_t light;
- int i, j;
-
- // all components of light should be identical in software
- if ( currententity->flags & RF_FULLBRIGHT )
- {
- for (i=0 ; i<3 ; i++)
- light[i] = 1.0;
- }
- else
- {
- R_LightPoint (currententity->origin, light);
- }
-
- // save off light value for server to look at (BIG HACK!)
- if ( currententity->flags & RF_WEAPONMODEL )
- r_lightlevel->value = 150.0 * light[0];
-
-
- if ( currententity->flags & RF_MINLIGHT )
- {
- for (i=0 ; i<3 ; i++)
- if (light[i] < 0.1)
- light[i] = 0.1;
- }
-
- if ( currententity->flags & RF_GLOW )
- { // bonus items will pulse with time
- float scale;
- float min;
-
- scale = 0.1 * sin(r_newrefdef.time*7);
- for (i=0 ; i<3 ; i++)
- {
- min = light[i] * 0.8;
- light[i] += scale;
- if (light[i] < min)
- light[i] = min;
- }
- }
-
- j = (light[0] + light[1] + light[2])*0.3333*255;
-
- lighting.ambientlight = j;
- lighting.shadelight = j;
-
- lighting.plightvec = lightvec;
-
-// clamp lighting so it doesn't overbright as much
- if (lighting.ambientlight > 128)
- lighting.ambientlight = 128;
- if (lighting.ambientlight + lighting.shadelight > 192)
- lighting.shadelight = 192 - lighting.ambientlight;
-
-// guarantee that no vertex will ever be lit below LIGHT_MIN, so we don't have
-// to clamp off the bottom
- r_ambientlight = lighting.ambientlight;
-
- if (r_ambientlight < LIGHT_MIN)
- r_ambientlight = LIGHT_MIN;
-
- r_ambientlight = (255 - r_ambientlight) << VID_CBITS;
-
- if (r_ambientlight < LIGHT_MIN)
- r_ambientlight = LIGHT_MIN;
-
- r_shadelight = lighting.shadelight;
-
- if (r_shadelight < 0)
- r_shadelight = 0;
-
- r_shadelight *= VID_GRADES;
-
-// rotate the lighting vector into the model's frame of reference
- r_plightvec[0] = DotProduct( lighting.plightvec, s_alias_forward );
- r_plightvec[1] = -DotProduct( lighting.plightvec, s_alias_right );
- r_plightvec[2] = DotProduct( lighting.plightvec, s_alias_up );
-}
-
-
-/*
-=================
-R_AliasSetupFrames
-
-=================
-*/
-void R_AliasSetupFrames( dmdl_t *pmdl )
-{
- int thisframe = currententity->frame;
- int lastframe = currententity->oldframe;
-
- if ( ( thisframe >= pmdl->num_frames ) || ( thisframe < 0 ) )
- {
- ri.Con_Printf (PRINT_ALL, "R_AliasSetupFrames %s: no such thisframe %d\n",
- currentmodel->name, thisframe);
- thisframe = 0;
- }
- if ( ( lastframe >= pmdl->num_frames ) || ( lastframe < 0 ) )
- {
- ri.Con_Printf (PRINT_ALL, "R_AliasSetupFrames %s: no such lastframe %d\n",
- currentmodel->name, lastframe);
- lastframe = 0;
- }
-
- r_thisframe = (daliasframe_t *)((byte *)pmdl + pmdl->ofs_frames
- + thisframe * pmdl->framesize);
-
- r_lastframe = (daliasframe_t *)((byte *)pmdl + pmdl->ofs_frames
- + lastframe * pmdl->framesize);
-}
-
-/*
-** R_AliasSetUpLerpData
-**
-** Precomputes lerp coefficients used for the whole frame.
-*/
-void R_AliasSetUpLerpData( dmdl_t */*pmdl*/, float backlerp )
-{
- float frontlerp;
- vec3_t translation, vectors[3];
- int i;
-
- frontlerp = 1.0F - backlerp;
-
- /*
- ** convert entity's angles into discrete vectors for R, U, and F
- */
- AngleVectors (currententity->angles, vectors[0], vectors[1], vectors[2]);
-
- /*
- ** translation is the vector from last position to this position
- */
- VectorSubtract (currententity->oldorigin, currententity->origin, translation);
-
- /*
- ** move should be the delta back to the previous frame * backlerp
- */
- r_lerp_move[0] = DotProduct(translation, vectors[0]); // forward
- r_lerp_move[1] = -DotProduct(translation, vectors[1]); // left
- r_lerp_move[2] = DotProduct(translation, vectors[2]); // up
-
- VectorAdd( r_lerp_move, r_lastframe->translate, r_lerp_move );
-
- for (i=0 ; i<3 ; i++)
- {
- r_lerp_move[i] = backlerp*r_lerp_move[i] + frontlerp * r_thisframe->translate[i];
- }
-
- for (i=0 ; i<3 ; i++)
- {
- r_lerp_frontv[i] = frontlerp * r_thisframe->scale[i];
- r_lerp_backv[i] = backlerp * r_lastframe->scale[i];
- }
-}
-
-/*
-================
-R_AliasDrawModel
-================
-*/
-void R_AliasDrawModel (void)
-{
- extern void (*d_pdrawspans)(void *);
- extern void R_PolysetDrawSpans8_Opaque( void * );
- extern void R_PolysetDrawSpans8_33( void * );
- extern void R_PolysetDrawSpans8_66( void * );
- extern void R_PolysetDrawSpansConstant8_33( void * );
- extern void R_PolysetDrawSpansConstant8_66( void * );
-
- s_pmdl = (dmdl_t *)currentmodel->extradata;
-
- if ( r_lerpmodels->value == 0 )
- currententity->backlerp = 0;
-
- if ( currententity->flags & RF_WEAPONMODEL )
- {
- if ( r_lefthand->value == 1.0F )
- aliasxscale = -aliasxscale;
- else if ( r_lefthand->value == 2.0F )
- return;
- }
-
- /*
- ** we have to set our frame pointers and transformations before
- ** doing any real work
- */
- R_AliasSetupFrames( s_pmdl );
- R_AliasSetUpTransform();
-
- // see if the bounding box lets us trivially reject, also sets
- // trivial accept status
- if ( R_AliasCheckBBox() == BBOX_TRIVIAL_REJECT )
- {
- if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
- {
- aliasxscale = -aliasxscale;
- }
- return;
- }
-
- // set up the skin and verify it exists
- if ( !R_AliasSetupSkin () )
- {
- ri.Con_Printf( PRINT_ALL, "R_AliasDrawModel %s: NULL skin found\n",
- currentmodel->name);
- return;
- }
-
- r_amodels_drawn++;
- R_AliasSetupLighting ();
-
- /*
- ** select the proper span routine based on translucency
- */
- // PMM - added double damage shell
- // PMM - reordered to handle blending
- if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
- {
- int color;
-
- // PMM - added double
- color = currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM);
- // PMM - reordered, old code first
-/*
- if ( color == RF_SHELL_RED )
- r_aliasblendcolor = SHELL_RED_COLOR;
- else if ( color == RF_SHELL_GREEN )
- r_aliasblendcolor = SHELL_GREEN_COLOR;
- else if ( color == RF_SHELL_BLUE )
- r_aliasblendcolor = SHELL_BLUE_COLOR;
- else if ( color == (RF_SHELL_RED | RF_SHELL_GREEN) )
- r_aliasblendcolor = SHELL_RG_COLOR;
- else if ( color == (RF_SHELL_RED | RF_SHELL_BLUE) )
- r_aliasblendcolor = SHELL_RB_COLOR;
- else if ( color == (RF_SHELL_BLUE | RF_SHELL_GREEN) )
- r_aliasblendcolor = SHELL_BG_COLOR;
- // PMM - added this .. it's yellowish
- else if ( color == (RF_SHELL_DOUBLE) )
- r_aliasblendcolor = SHELL_DOUBLE_COLOR;
- else if ( color == (RF_SHELL_HALF_DAM) )
- r_aliasblendcolor = SHELL_HALF_DAM_COLOR;
- // pmm
- else
- r_aliasblendcolor = SHELL_WHITE_COLOR;
-*/
- if ( color & RF_SHELL_RED )
- {
- if ( ( color & RF_SHELL_BLUE) && ( color & RF_SHELL_GREEN) )
- r_aliasblendcolor = SHELL_WHITE_COLOR;
- else if ( color & (RF_SHELL_BLUE | RF_SHELL_DOUBLE))
- r_aliasblendcolor = SHELL_RB_COLOR;
- else
- r_aliasblendcolor = SHELL_RED_COLOR;
- }
- else if ( color & RF_SHELL_BLUE)
- {
- if ( color & RF_SHELL_DOUBLE )
- r_aliasblendcolor = SHELL_CYAN_COLOR;
- else
- r_aliasblendcolor = SHELL_BLUE_COLOR;
- }
- else if ( color & (RF_SHELL_DOUBLE) )
- r_aliasblendcolor = SHELL_DOUBLE_COLOR;
- else if ( color & (RF_SHELL_HALF_DAM) )
- r_aliasblendcolor = SHELL_HALF_DAM_COLOR;
- else if ( color & RF_SHELL_GREEN )
- r_aliasblendcolor = SHELL_GREEN_COLOR;
- else
- r_aliasblendcolor = SHELL_WHITE_COLOR;
-
-
- if ( currententity->alpha > 0.33 )
- d_pdrawspans = R_PolysetDrawSpansConstant8_66;
- else
- d_pdrawspans = R_PolysetDrawSpansConstant8_33;
- }
- else if ( currententity->flags & RF_TRANSLUCENT )
- {
- if ( currententity->alpha > 0.66 )
- d_pdrawspans = R_PolysetDrawSpans8_Opaque;
- else if ( currententity->alpha > 0.33 )
- d_pdrawspans = R_PolysetDrawSpans8_66;
- else
- d_pdrawspans = R_PolysetDrawSpans8_33;
- }
- else
- {
- d_pdrawspans = R_PolysetDrawSpans8_Opaque;
- }
-
- /*
- ** compute this_frame and old_frame addresses
- */
- R_AliasSetUpLerpData( s_pmdl, currententity->backlerp );
-
- if (currententity->flags & RF_DEPTHHACK)
- s_ziscale = (float)0x8000 * (float)0x10000 * 3.0;
- else
- s_ziscale = (float)0x8000 * (float)0x10000;
-
- R_AliasPreparePoints ();
-
- if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
- {
- aliasxscale = -aliasxscale;
- }
-}
-
-
-
--- a/ref/r_bsp.c
+++ /dev/null
@@ -1,619 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-//
-// current entity info
-//
-qboolean insubmodel;
-entity_t *currententity;
-vec3_t modelorg; // modelorg is the viewpoint reletive to
- // the currently rendering entity
-vec3_t r_entorigin; // the currently rendering entity in world
- // coordinates
-
-float entity_rotation[3][3];
-
-int r_currentbkey;
-
-typedef enum {touchessolid, drawnode, nodrawnode} solidstate_t;
-
-#define MAX_BMODEL_VERTS 500 // 6K
-#define MAX_BMODEL_EDGES 1000 // 12K
-
-static mvertex_t *pbverts;
-static bedge_t *pbedges;
-static int numbverts, numbedges;
-
-static mvertex_t *pfrontenter, *pfrontexit;
-
-static qboolean makeclippededge;
-
-
-//===========================================================================
-
-/*
-================
-R_EntityRotate
-================
-*/
-void R_EntityRotate (vec3_t vec)
-{
- vec3_t tvec;
-
- VectorCopy (vec, tvec);
- vec[0] = DotProduct (entity_rotation[0], tvec);
- vec[1] = DotProduct (entity_rotation[1], tvec);
- vec[2] = DotProduct (entity_rotation[2], tvec);
-}
-
-
-/*
-================
-R_RotateBmodel
-================
-*/
-void R_RotateBmodel (void)
-{
- float angle, s, c, temp1[3][3], temp2[3][3], temp3[3][3];
-
-// TODO: should use a look-up table
-// TODO: should really be stored with the entity instead of being reconstructed
-// TODO: could cache lazily, stored in the entity
-// TODO: share work with R_SetUpAliasTransform
-
-// yaw
- angle = currententity->angles[YAW];
- angle = angle * M_PI*2 / 360;
- s = sin(angle);
- c = cos(angle);
-
- temp1[0][0] = c;
- temp1[0][1] = s;
- temp1[0][2] = 0;
- temp1[1][0] = -s;
- temp1[1][1] = c;
- temp1[1][2] = 0;
- temp1[2][0] = 0;
- temp1[2][1] = 0;
- temp1[2][2] = 1;
-
-
-// pitch
- angle = currententity->angles[PITCH];
- angle = angle * M_PI*2 / 360;
- s = sin(angle);
- c = cos(angle);
-
- temp2[0][0] = c;
- temp2[0][1] = 0;
- temp2[0][2] = -s;
- temp2[1][0] = 0;
- temp2[1][1] = 1;
- temp2[1][2] = 0;
- temp2[2][0] = s;
- temp2[2][1] = 0;
- temp2[2][2] = c;
-
- R_ConcatRotations (temp2, temp1, temp3);
-
-// roll
- angle = currententity->angles[ROLL];
- angle = angle * M_PI*2 / 360;
- s = sin(angle);
- c = cos(angle);
-
- temp1[0][0] = 1;
- temp1[0][1] = 0;
- temp1[0][2] = 0;
- temp1[1][0] = 0;
- temp1[1][1] = c;
- temp1[1][2] = s;
- temp1[2][0] = 0;
- temp1[2][1] = -s;
- temp1[2][2] = c;
-
- R_ConcatRotations (temp1, temp3, entity_rotation);
-
-//
-// rotate modelorg and the transformation matrix
-//
- R_EntityRotate (modelorg);
- R_EntityRotate (vpn);
- R_EntityRotate (vright);
- R_EntityRotate (vup);
-
- R_TransformFrustum ();
-}
-
-
-/*
-================
-R_RecursiveClipBPoly
-
-Clip a bmodel poly down the world bsp tree
-================
-*/
-void R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf)
-{
- bedge_t *psideedges[2], *pnextedge, *ptedge;
- int i, side, lastside;
- float dist, frac, lastdist;
- mplane_t *splitplane, tplane;
- mvertex_t *pvert, *plastvert, *ptvert;
- mnode_t *pn;
- int area;
-
- psideedges[0] = psideedges[1] = NULL;
-
- makeclippededge = false;
-
-// transform the BSP plane into model space
-// FIXME: cache these?
- splitplane = pnode->plane;
- tplane.dist = splitplane->dist -
- DotProduct(r_entorigin, splitplane->normal);
- tplane.normal[0] = DotProduct (entity_rotation[0], splitplane->normal);
- tplane.normal[1] = DotProduct (entity_rotation[1], splitplane->normal);
- tplane.normal[2] = DotProduct (entity_rotation[2], splitplane->normal);
-
-// clip edges to BSP plane
- for ( ; pedges ; pedges = pnextedge)
- {
- pnextedge = pedges->pnext;
-
- // set the status for the last point as the previous point
- // FIXME: cache this stuff somehow?
- plastvert = pedges->v[0];
- lastdist = DotProduct (plastvert->position, tplane.normal) -
- tplane.dist;
-
- if (lastdist > 0)
- lastside = 0;
- else
- lastside = 1;
-
- pvert = pedges->v[1];
-
- dist = DotProduct (pvert->position, tplane.normal) - tplane.dist;
-
- if (dist > 0)
- side = 0;
- else
- side = 1;
-
- if (side != lastside)
- {
- // clipped
- if (numbverts >= MAX_BMODEL_VERTS)
- return;
-
- // generate the clipped vertex
- frac = lastdist / (lastdist - dist);
- ptvert = &pbverts[numbverts++];
- ptvert->position[0] = plastvert->position[0] +
- frac * (pvert->position[0] -
- plastvert->position[0]);
- ptvert->position[1] = plastvert->position[1] +
- frac * (pvert->position[1] -
- plastvert->position[1]);
- ptvert->position[2] = plastvert->position[2] +
- frac * (pvert->position[2] -
- plastvert->position[2]);
-
- // split into two edges, one on each side, and remember entering
- // and exiting points
- // FIXME: share the clip edge by having a winding direction flag?
- if (numbedges >= (MAX_BMODEL_EDGES - 1))
- {
- ri.Con_Printf (PRINT_ALL,"Out of edges for bmodel\n");
- return;
- }
-
- ptedge = &pbedges[numbedges];
- ptedge->pnext = psideedges[lastside];
- psideedges[lastside] = ptedge;
- ptedge->v[0] = plastvert;
- ptedge->v[1] = ptvert;
-
- ptedge = &pbedges[numbedges + 1];
- ptedge->pnext = psideedges[side];
- psideedges[side] = ptedge;
- ptedge->v[0] = ptvert;
- ptedge->v[1] = pvert;
-
- numbedges += 2;
-
- if (side == 0)
- {
- // entering for front, exiting for back
- pfrontenter = ptvert;
- makeclippededge = true;
- }
- else
- {
- pfrontexit = ptvert;
- makeclippededge = true;
- }
- }
- else
- {
- // add the edge to the appropriate side
- pedges->pnext = psideedges[side];
- psideedges[side] = pedges;
- }
- }
-
-// if anything was clipped, reconstitute and add the edges along the clip
-// plane to both sides (but in opposite directions)
- if (makeclippededge)
- {
- if (numbedges >= (MAX_BMODEL_EDGES - 2))
- {
- ri.Con_Printf (PRINT_ALL,"Out of edges for bmodel\n");
- return;
- }
-
- ptedge = &pbedges[numbedges];
- ptedge->pnext = psideedges[0];
- psideedges[0] = ptedge;
- ptedge->v[0] = pfrontexit;
- ptedge->v[1] = pfrontenter;
-
- ptedge = &pbedges[numbedges + 1];
- ptedge->pnext = psideedges[1];
- psideedges[1] = ptedge;
- ptedge->v[0] = pfrontenter;
- ptedge->v[1] = pfrontexit;
-
- numbedges += 2;
- }
-
-// draw or recurse further
- for (i=0 ; i<2 ; i++)
- {
- if (psideedges[i])
- {
- // draw if we've reached a non-solid leaf, done if all that's left is a
- // solid leaf, and continue down the tree if it's not a leaf
- pn = pnode->children[i];
-
- // we're done with this branch if the node or leaf isn't in the PVS
- if (pn->visframe == r_visframecount)
- {
- if (pn->contents != CONTENTS_NODE)
- {
- if (pn->contents != CONTENTS_SOLID)
- {
- if (r_newrefdef.areabits)
- {
- area = ((mleaf_t *)pn)->area;
- if (! (r_newrefdef.areabits[area>>3] & (1<<(area&7)) ) )
- continue; // not visible
- }
-
- r_currentbkey = ((mleaf_t *)pn)->key;
- R_RenderBmodelFace (psideedges[i], psurf);
- }
- }
- else
- {
- R_RecursiveClipBPoly (psideedges[i], pnode->children[i],
- psurf);
- }
- }
- }
- }
-}
-
-
-/*
-================
-R_DrawSolidClippedSubmodelPolygons
-
-Bmodel crosses multiple leafs
-================
-*/
-void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel, mnode_t *topnode)
-{
- int i, j, lindex;
- vec_t dot;
- msurface_t *psurf;
- int numsurfaces;
- mplane_t *pplane;
- mvertex_t bverts[MAX_BMODEL_VERTS];
- bedge_t bedges[MAX_BMODEL_EDGES], *pbedge;
- medge_t *pedge, *pedges;
-
-// FIXME: use bounding-box-based frustum clipping info?
-
- psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
- numsurfaces = pmodel->nummodelsurfaces;
- pedges = pmodel->edges;
-
- for (i=0 ; i<numsurfaces ; i++, psurf++)
- {
- // find which side of the node we are on
- pplane = psurf->plane;
-
- dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
-
- // draw the polygon
- if (( !(psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
- ((psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
- continue;
-
- // FIXME: use bounding-box-based frustum clipping info?
-
- // copy the edges to bedges, flipping if necessary so always
- // clockwise winding
- // FIXME: if edges and vertices get caches, these assignments must move
- // outside the loop, and overflow checking must be done here
- pbverts = bverts;
- pbedges = bedges;
- numbverts = numbedges = 0;
- pbedge = &bedges[numbedges];
- numbedges += psurf->numedges;
-
- for (j=0 ; j<psurf->numedges ; j++)
- {
- lindex = pmodel->surfedges[psurf->firstedge+j];
-
- if (lindex > 0)
- {
- pedge = &pedges[lindex];
- pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]];
- pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]];
- }
- else
- {
- lindex = -lindex;
- pedge = &pedges[lindex];
- pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]];
- pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]];
- }
-
- pbedge[j].pnext = &pbedge[j+1];
- }
-
- pbedge[j-1].pnext = NULL; // mark end of edges
-
- if ( !( psurf->texinfo->flags & ( SURF_TRANS66 | SURF_TRANS33 ) ) )
- R_RecursiveClipBPoly (pbedge, topnode, psurf);
- else
- R_RenderBmodelFace( pbedge, psurf );
- }
-}
-
-
-/*
-================
-R_DrawSubmodelPolygons
-
-All in one leaf
-================
-*/
-void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags, mnode_t *topnode)
-{
- int i;
- vec_t dot;
- msurface_t *psurf;
- int numsurfaces;
- mplane_t *pplane;
-
-// FIXME: use bounding-box-based frustum clipping info?
-
- psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
- numsurfaces = pmodel->nummodelsurfaces;
-
- for (i=0 ; i<numsurfaces ; i++, psurf++)
- {
- // find which side of the node we are on
- pplane = psurf->plane;
-
- dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
-
- // draw the polygon
- if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
- (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
- {
- r_currentkey = ((mleaf_t *)topnode)->key;
-
- // FIXME: use bounding-box-based frustum clipping info?
- R_RenderFace (psurf, clipflags);
- }
- }
-}
-
-
-int c_drawnode;
-
-/*
-================
-R_RecursiveWorldNode
-================
-*/
-void R_RecursiveWorldNode (mnode_t *node, int clipflags)
-{
- int i, c, side, *pindex;
- vec3_t acceptpt, rejectpt;
- mplane_t *plane;
- msurface_t *surf, **mark;
- float d, dot;
- mleaf_t *pleaf;
-
- if (node->contents == CONTENTS_SOLID)
- return; // solid
-
- if (node->visframe != r_visframecount)
- return;
-
-// cull the clipping planes if not trivial accept
-// FIXME: the compiler is doing a lousy job of optimizing here; it could be
-// twice as fast in ASM
- if (clipflags)
- {
- for (i=0 ; i<4 ; i++)
- {
- if (! (clipflags & (1<<i)) )
- continue; // don't need to clip against it
-
- // generate accept and reject points
- // FIXME: do with fast look-ups or integer tests based on the sign bit
- // of the floating point values
-
- pindex = pfrustum_indexes[i];
-
- rejectpt[0] = (float)node->minmaxs[pindex[0]];
- rejectpt[1] = (float)node->minmaxs[pindex[1]];
- rejectpt[2] = (float)node->minmaxs[pindex[2]];
-
- d = DotProduct (rejectpt, view_clipplanes[i].normal);
- d -= view_clipplanes[i].dist;
- if (d <= 0)
- return;
- acceptpt[0] = (float)node->minmaxs[pindex[3+0]];
- acceptpt[1] = (float)node->minmaxs[pindex[3+1]];
- acceptpt[2] = (float)node->minmaxs[pindex[3+2]];
-
- d = DotProduct (acceptpt, view_clipplanes[i].normal);
- d -= view_clipplanes[i].dist;
-
- if (d >= 0)
- clipflags &= ~(1<<i); // node is entirely on screen
- }
- }
-
-c_drawnode++;
-
-// if a leaf node, draw stuff
- if (node->contents != -1)
- {
- pleaf = (mleaf_t *)node;
-
- // check for door connected areas
- if (r_newrefdef.areabits)
- {
- if (! (r_newrefdef.areabits[pleaf->area>>3] & (1<<(pleaf->area&7)) ) )
- return; // not visible
- }
-
- mark = pleaf->firstmarksurface;
- c = pleaf->nummarksurfaces;
-
- if (c)
- {
- do
- {
- (*mark)->visframe = r_framecount;
- mark++;
- } while (--c);
- }
-
- pleaf->key = r_currentkey;
- r_currentkey++; // all bmodels in a leaf share the same key
- }
- else
- {
- // node is just a decision point, so go down the apropriate sides
-
- // find which side of the node we are on
- plane = node->plane;
-
- switch (plane->type)
- {
- case PLANE_X:
- dot = modelorg[0] - plane->dist;
- break;
- case PLANE_Y:
- dot = modelorg[1] - plane->dist;
- break;
- case PLANE_Z:
- dot = modelorg[2] - plane->dist;
- break;
- default:
- dot = DotProduct (modelorg, plane->normal) - plane->dist;
- break;
- }
-
- if (dot >= 0)
- side = 0;
- else
- side = 1;
-
- // recurse down the children, front side first
- R_RecursiveWorldNode (node->children[side], clipflags);
-
- // draw stuff
- c = node->numsurfaces;
-
- if (c)
- {
- surf = r_worldmodel->surfaces + node->firstsurface;
-
- if (dot < -BACKFACE_EPSILON)
- {
- do
- {
- if ((surf->flags & SURF_PLANEBACK) &&
- (surf->visframe == r_framecount))
- {
- R_RenderFace (surf, clipflags);
- }
-
- surf++;
- } while (--c);
- }
- else if (dot > BACKFACE_EPSILON)
- {
- do
- {
- if (!(surf->flags & SURF_PLANEBACK) &&
- (surf->visframe == r_framecount))
- {
- R_RenderFace (surf, clipflags);
- }
-
- surf++;
- } while (--c);
- }
-
- // all surfaces on the same node share the same sequence number
- r_currentkey++;
- }
-
- // recurse down the back side
- R_RecursiveWorldNode (node->children[!side], clipflags);
- }
-}
-
-
-
-/*
-================
-R_RenderWorld
-================
-*/
-void R_RenderWorld (void)
-{
-
- if (!r_drawworld->value)
- return;
- if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
- return;
-
- c_drawnode=0;
-
- // auto cycle the world frame for texture animation
- r_worldentity.frame = (int)(r_newrefdef.time*2);
- currententity = &r_worldentity;
-
- VectorCopy (r_origin, modelorg);
- currentmodel = r_worldmodel;
- r_pcurrentvertbase = currentmodel->vertexes;
-
- R_RecursiveWorldNode (currentmodel->nodes, 15);
-}
-
-
--- a/ref/r_draw.c
+++ /dev/null
@@ -1,426 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-
-image_t *draw_chars; // 8*8 graphic characters
-
-//=============================================================================
-
-/*
-================
-Draw_FindPic
-================
-*/
-image_t *Draw_FindPic (char *name)
-{
- image_t *image;
- char fullname[MAX_QPATH];
-
- if (name[0] != '/' && name[0] != '\\')
- {
- Com_sprintf (fullname, sizeof(fullname), "pics/%s.pcx", name);
- image = R_FindImage (fullname, it_pic);
- }
- else
- image = R_FindImage (name+1, it_pic);
-
- return image;
-}
-
-
-
-/*
-===============
-Draw_InitLocal
-===============
-*/
-void Draw_InitLocal (void)
-{
- draw_chars = Draw_FindPic ("conchars");
-}
-
-
-
-/*
-================
-Draw_Char
-
-Draws one 8*8 graphics character
-It can be clipped to the top of the screen to allow the console to be
-smoothly scrolled off.
-================
-*/
-void Draw_Char (int x, int y, int num)
-{
- byte *dest;
- byte *source;
- int drawline;
- int row, col;
-
- num &= 255;
-
- if (num == 32 || num == 32+128)
- return;
-
- if (y <= -8)
- return; // totally off screen
-
-// if ( ( y + 8 ) >= vid.height )
- if ( ( y + 8 ) > vid.height ) // PGM - status text was missing in sw...
- return;
-
-#ifdef PARANOID
- if (y > vid.height - 8 || x < 0 || x > vid.width - 8)
- ri.Sys_Error (ERR_FATAL,"Con_DrawCharacter: (%i, %i)", x, y);
- if (num < 0 || num > 255)
- ri.Sys_Error (ERR_FATAL,"Con_DrawCharacter: char %i", num);
-#endif
-
- row = num>>4;
- col = num&15;
- source = draw_chars->pixels[0] + (row<<10) + (col<<3);
-
- if (y < 0)
- { // clipped
- drawline = 8 + y;
- source -= 128*y;
- y = 0;
- }
- else
- drawline = 8;
-
-
- dest = vid.buffer + y*vid.rowbytes + x;
-
- while (drawline--)
- {
- if (source[0] != TRANSPARENT_COLOR)
- dest[0] = source[0];
- if (source[1] != TRANSPARENT_COLOR)
- dest[1] = source[1];
- if (source[2] != TRANSPARENT_COLOR)
- dest[2] = source[2];
- if (source[3] != TRANSPARENT_COLOR)
- dest[3] = source[3];
- if (source[4] != TRANSPARENT_COLOR)
- dest[4] = source[4];
- if (source[5] != TRANSPARENT_COLOR)
- dest[5] = source[5];
- if (source[6] != TRANSPARENT_COLOR)
- dest[6] = source[6];
- if (source[7] != TRANSPARENT_COLOR)
- dest[7] = source[7];
- source += 128;
- dest += vid.rowbytes;
- }
-}
-
-/*
-=============
-Draw_GetPicSize
-=============
-*/
-void Draw_GetPicSize (int *w, int *h, char *pic)
-{
- image_t *gl;
-
- gl = Draw_FindPic (pic);
- if (!gl)
- {
- *w = *h = -1;
- return;
- }
- *w = gl->width;
- *h = gl->height;
-}
-
-/*
-=============
-Draw_StretchPicImplementation
-=============
-*/
-void Draw_StretchPicImplementation (int x, int y, int w, int h, image_t *pic)
-{
- byte *dest, *source;
- int v, u, sv;
- int height;
- int f, fstep;
- int skip;
-
- if ((x < 0) ||
- (x + w > vid.width) ||
- (y + h > vid.height))
- {
- ri.Sys_Error (ERR_FATAL,"Draw_Pic: bad coordinates");
- }
-
- height = h;
- if (y < 0)
- {
- skip = -y;
- height += y;
- y = 0;
- }
- else
- skip = 0;
-
- dest = vid.buffer + y * vid.rowbytes + x;
-
- for (v=0 ; v<height ; v++, dest += vid.rowbytes)
- {
- sv = (skip + v)*pic->height/h;
- source = pic->pixels[0] + sv*pic->width;
- if (w == pic->width)
- memcpy (dest, source, w);
- else
- {
- f = 0;
- fstep = pic->width*0x10000/w;
- for (u=0 ; u<w ; u+=4)
- {
- dest[u] = source[f>>16];
- f += fstep;
- dest[u+1] = source[f>>16];
- f += fstep;
- dest[u+2] = source[f>>16];
- f += fstep;
- dest[u+3] = source[f>>16];
- f += fstep;
- }
- }
- }
-}
-
-/*
-=============
-Draw_StretchPic
-=============
-*/
-void Draw_StretchPic (int x, int y, int w, int h, char *name)
-{
- image_t *pic;
-
- pic = Draw_FindPic (name);
- if (!pic)
- {
- ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", name);
- return;
- }
- Draw_StretchPicImplementation (x, y, w, h, pic);
-}
-
-/*
-=============
-Draw_StretchRaw
-=============
-*/
-void Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data)
-{
- image_t pic;
-
- pic.pixels[0] = data;
- pic.width = cols;
- pic.height = rows;
- Draw_StretchPicImplementation (x, y, w, h, &pic);
-}
-
-/*
-=============
-Draw_Pic
-=============
-*/
-void Draw_Pic (int x, int y, char *name)
-{
- image_t *pic;
- byte *dest, *source;
- int v, u;
- int tbyte;
- int height;
-
- pic = Draw_FindPic (name);
- if (!pic)
- {
- ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", name);
- return;
- }
-
- if ((x < 0) ||
- (x + pic->width > vid.width) ||
- (y + pic->height > vid.height))
- return; // ri.Sys_Error (ERR_FATAL,"Draw_Pic: bad coordinates");
-
- height = pic->height;
- source = pic->pixels[0];
- if (y < 0)
- {
- height += y;
- source += pic->width*-y;
- y = 0;
- }
-
- dest = vid.buffer + y * vid.rowbytes + x;
-
- if (!pic->transparent)
- {
- for (v=0 ; v<height ; v++)
- {
- memcpy (dest, source, pic->width);
- dest += vid.rowbytes;
- source += pic->width;
- }
- }
- else
- {
- if (pic->width & 7)
- { // general
- for (v=0 ; v<height ; v++)
- {
- for (u=0 ; u<pic->width ; u++)
- if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
- dest[u] = tbyte;
-
- dest += vid.rowbytes;
- source += pic->width;
- }
- }
- else
- { // unwound
- for (v=0 ; v<height ; v++)
- {
- for (u=0 ; u<pic->width ; u+=8)
- {
- if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
- dest[u] = tbyte;
- if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR)
- dest[u+1] = tbyte;
- if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR)
- dest[u+2] = tbyte;
- if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR)
- dest[u+3] = tbyte;
- if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR)
- dest[u+4] = tbyte;
- if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR)
- dest[u+5] = tbyte;
- if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR)
- dest[u+6] = tbyte;
- if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR)
- dest[u+7] = tbyte;
- }
- dest += vid.rowbytes;
- source += pic->width;
- }
- }
- }
-}
-
-/*
-=============
-Draw_TileClear
-
-This repeats a 64*64 tile graphic to fill the screen around a sized down
-refresh window.
-=============
-*/
-void Draw_TileClear (int x, int y, int w, int h, char *name)
-{
- int i, j;
- byte *psrc;
- byte *pdest;
- image_t *pic;
- int x2;
-
- if (x < 0)
- {
- w += x;
- x = 0;
- }
- if (y < 0)
- {
- h += y;
- y = 0;
- }
- if (x + w > vid.width)
- w = vid.width - x;
- if (y + h > vid.height)
- h = vid.height - y;
- if (w <= 0 || h <= 0)
- return;
-
- pic = Draw_FindPic (name);
- if (!pic)
- {
- ri.Con_Printf (PRINT_ALL, "Can't find pic: %s\n", name);
- return;
- }
- x2 = x + w;
- pdest = vid.buffer + y*vid.rowbytes;
- for (i=0 ; i<h ; i++, pdest += vid.rowbytes)
- {
- psrc = pic->pixels[0] + pic->width * ((i+y)&63);
- for (j=x ; j<x2 ; j++)
- pdest[j] = psrc[j&63];
- }
-}
-
-
-/*
-=============
-Draw_Fill
-
-Fills a box of pixels with a single color
-=============
-*/
-void Draw_Fill (int x, int y, int w, int h, int c)
-{
- byte *dest;
- int u, v;
-
- if (x+w > vid.width)
- w = vid.width - x;
- if (y+h > vid.height)
- h = vid.height - y;
- if (x < 0)
- {
- w += x;
- x = 0;
- }
- if (y < 0)
- {
- h += y;
- y = 0;
- }
- if (w < 0 || h < 0)
- return;
- dest = vid.buffer + y*vid.rowbytes + x;
- for (v=0 ; v<h ; v++, dest += vid.rowbytes)
- for (u=0 ; u<w ; u++)
- dest[u] = c;
-}
-//=============================================================================
-
-/*
-================
-Draw_FadeScreen
-
-================
-*/
-void Draw_FadeScreen (void)
-{
- int x,y;
- byte *pbuf;
- int t;
-
- for (y=0 ; y<vid.height ; y++)
- {
- pbuf = (byte *)(vid.buffer + vid.rowbytes*y);
- t = (y & 1) << 1;
-
- for (x=0 ; x<vid.width ; x++)
- {
- if ((x & 3) != t)
- pbuf[x] = 0;
- }
- }
-}
--- a/ref/r_edge.c
+++ /dev/null
@@ -1,1084 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-void R_SurfacePatch (void)
-{
-}
-
-void R_EdgeCodeStart (void)
-{
-}
-
-void R_EdgeCodeEnd (void)
-{
-}
-
-
-/*
-the complex cases add new polys on most lines, so dont optimize for keeping them the same
-have multiple free span lists to try to get better coherence?
-low depth complexity -- 1 to 3 or so
-
-have a sentinal at both ends?
-*/
-
-
-edge_t *auxedges;
-edge_t *r_edges, *edge_p, *edge_max;
-
-surf_t *surfaces, *surface_p, *surf_max;
-
-// surfaces are generated in back to front order by the bsp, so if a surf
-// pointer is greater than another one, it should be drawn in front
-// surfaces[1] is the background, and is used as the active surface stack
-
-edge_t *newedges[MAXHEIGHT];
-edge_t *removeedges[MAXHEIGHT];
-
-espan_t *span_p, *max_span_p;
-
-int r_currentkey;
-
-int current_iv;
-
-int edge_head_u_shift20, edge_tail_u_shift20;
-
-static void (*pdrawfunc)(void);
-
-edge_t edge_head;
-edge_t edge_tail;
-edge_t edge_aftertail;
-edge_t edge_sentinel;
-
-float fv;
-
-static int miplevel;
-
-float scale_for_mip;
-int ubasestep, errorterm, erroradjustup, erroradjustdown;
-
-// FIXME: should go away
-extern void R_RotateBmodel (void);
-extern void R_TransformFrustum (void);
-
-
-
-void R_GenerateSpans (void);
-void R_GenerateSpansBackward (void);
-
-void R_LeadingEdge (edge_t *edge);
-void R_LeadingEdgeBackwards (edge_t *edge);
-void R_TrailingEdge (surf_t *surf, edge_t *edge);
-
-
-/*
-===============================================================================
-
-EDGE SCANNING
-
-===============================================================================
-*/
-
-/*
-==============
-R_BeginEdgeFrame
-==============
-*/
-void R_BeginEdgeFrame (void)
-{
- int v;
-
- edge_p = r_edges;
- edge_max = &r_edges[r_numallocatededges];
-
- surface_p = &surfaces[2]; // background is surface 1,
- // surface 0 is a dummy
- surfaces[1].spans = NULL; // no background spans yet
- surfaces[1].flags = SURF_DRAWBACKGROUND;
-
-// put the background behind everything in the world
- if (sw_draworder->value)
- {
- pdrawfunc = R_GenerateSpansBackward;
- surfaces[1].key = 0;
- r_currentkey = 1;
- }
- else
- {
- pdrawfunc = R_GenerateSpans;
- surfaces[1].key = 0x7FFfFFFF;
- r_currentkey = 0;
- }
-
-// FIXME: set with memset
- for (v=r_refdef.vrect.y ; v<r_refdef.vrectbottom ; v++)
- {
- newedges[v] = removeedges[v] = NULL;
- }
-}
-
-/*
-==============
-R_InsertNewEdges
-
-Adds the edges in the linked list edgestoadd, adding them to the edges in the
-linked list edgelist. edgestoadd is assumed to be sorted on u, and non-empty (this is actually newedges[v]). edgelist is assumed to be sorted on u, with a
-sentinel at the end (actually, this is the active edge table starting at
-edge_head.next).
-==============
-*/
-void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist)
-{
- edge_t *next_edge;
-
- do
- {
- next_edge = edgestoadd->next;
-edgesearch:
- if (edgelist->u >= edgestoadd->u)
- goto addedge;
- edgelist=edgelist->next;
- if (edgelist->u >= edgestoadd->u)
- goto addedge;
- edgelist=edgelist->next;
- if (edgelist->u >= edgestoadd->u)
- goto addedge;
- edgelist=edgelist->next;
- if (edgelist->u >= edgestoadd->u)
- goto addedge;
- edgelist=edgelist->next;
- goto edgesearch;
-
- // insert edgestoadd before edgelist
-addedge:
- edgestoadd->next = edgelist;
- edgestoadd->prev = edgelist->prev;
- edgelist->prev->next = edgestoadd;
- edgelist->prev = edgestoadd;
- } while ((edgestoadd = next_edge) != NULL);
-}
-
-
-/*
-==============
-R_RemoveEdges
-==============
-*/
-void R_RemoveEdges (edge_t *pedge)
-{
-
- do
- {
- pedge->next->prev = pedge->prev;
- pedge->prev->next = pedge->next;
- } while ((pedge = pedge->nextremove) != NULL);
-}
-
-
-/*
-==============
-R_StepActiveU
-==============
-*/
-void R_StepActiveU (edge_t *pedge)
-{
- edge_t *pnext_edge, *pwedge;
-
- while (1)
- {
-nextedge:
- pedge->u += pedge->u_step;
- if (pedge->u < pedge->prev->u)
- goto pushback;
- pedge = pedge->next;
-
- pedge->u += pedge->u_step;
- if (pedge->u < pedge->prev->u)
- goto pushback;
- pedge = pedge->next;
-
- pedge->u += pedge->u_step;
- if (pedge->u < pedge->prev->u)
- goto pushback;
- pedge = pedge->next;
-
- pedge->u += pedge->u_step;
- if (pedge->u < pedge->prev->u)
- goto pushback;
- pedge = pedge->next;
-
- goto nextedge;
-
-pushback:
- if (pedge == &edge_aftertail)
- return;
-
- // push it back to keep it sorted
- pnext_edge = pedge->next;
-
- // pull the edge out of the edge list
- pedge->next->prev = pedge->prev;
- pedge->prev->next = pedge->next;
-
- // find out where the edge goes in the edge list
- pwedge = pedge->prev->prev;
-
- while (pwedge->u > pedge->u)
- {
- pwedge = pwedge->prev;
- }
-
- // put the edge back into the edge list
- pedge->next = pwedge->next;
- pedge->prev = pwedge;
- pedge->next->prev = pedge;
- pwedge->next = pedge;
-
- pedge = pnext_edge;
- if (pedge == &edge_tail)
- return;
- }
-}
-
-
-/*
-==============
-R_CleanupSpan
-==============
-*/
-void R_CleanupSpan (void)
-{
- surf_t *surf;
- int iu;
- espan_t *span;
-
-// now that we've reached the right edge of the screen, we're done with any
-// unfinished surfaces, so emit a span for whatever's on top
- surf = surfaces[1].next;
- iu = edge_tail_u_shift20;
- if (iu > surf->last_u)
- {
- span = span_p++;
- span->u = surf->last_u;
- span->count = iu - span->u;
- span->v = current_iv;
- span->pnext = surf->spans;
- surf->spans = span;
- }
-
-// reset spanstate for all surfaces in the surface stack
- do
- {
- surf->spanstate = 0;
- surf = surf->next;
- } while (surf != &surfaces[1]);
-}
-
-
-/*
-==============
-R_LeadingEdgeBackwards
-==============
-*/
-void R_LeadingEdgeBackwards (edge_t *edge)
-{
- espan_t *span;
- surf_t *surf, *surf2;
- int iu;
-
-// it's adding a new surface in, so find the correct place
- surf = &surfaces[edge->surfs[1]];
-
-// don't start a span if this is an inverted span, with the end
-// edge preceding the start edge (that is, we've already seen the
-// end edge)
- if (++surf->spanstate == 1)
- {
- surf2 = surfaces[1].next;
-
- if (surf->key > surf2->key)
- goto newtop;
-
- // if it's two surfaces on the same plane, the one that's already
- // active is in front, so keep going unless it's a bmodel
- if (surf->insubmodel && (surf->key == surf2->key))
- {
- // must be two bmodels in the same leaf; don't care, because they'll
- // never be farthest anyway
- goto newtop;
- }
-
-continue_search:
-
- do
- {
- surf2 = surf2->next;
- } while (surf->key < surf2->key);
-
- if (surf->key == surf2->key)
- {
- // if it's two surfaces on the same plane, the one that's already
- // active is in front, so keep going unless it's a bmodel
- if (!surf->insubmodel)
- goto continue_search;
-
- // must be two bmodels in the same leaf; don't care which is really
- // in front, because they'll never be farthest anyway
- }
-
- goto gotposition;
-
-newtop:
- // emit a span (obscures current top)
- iu = edge->u >> 20;
-
- if (iu > surf2->last_u)
- {
- span = span_p++;
- span->u = surf2->last_u;
- span->count = iu - span->u;
- span->v = current_iv;
- span->pnext = surf2->spans;
- surf2->spans = span;
- }
-
- // set last_u on the new span
- surf->last_u = iu;
-
-gotposition:
- // insert before surf2
- surf->next = surf2;
- surf->prev = surf2->prev;
- surf2->prev->next = surf;
- surf2->prev = surf;
- }
-}
-
-
-/*
-==============
-R_TrailingEdge
-==============
-*/
-void R_TrailingEdge (surf_t *surf, edge_t *edge)
-{
- espan_t *span;
- int iu;
-
-// don't generate a span if this is an inverted span, with the end
-// edge preceding the start edge (that is, we haven't seen the
-// start edge yet)
- if (--surf->spanstate == 0)
- {
- if (surf == surfaces[1].next)
- {
- // emit a span (current top going away)
- iu = edge->u >> 20;
- if (iu > surf->last_u)
- {
- span = span_p++;
- span->u = surf->last_u;
- span->count = iu - span->u;
- span->v = current_iv;
- span->pnext = surf->spans;
- surf->spans = span;
- }
-
- // set last_u on the surface below
- surf->next->last_u = iu;
- }
-
- surf->prev->next = surf->next;
- surf->next->prev = surf->prev;
- }
-}
-
-
-/*
-==============
-R_LeadingEdge
-==============
-*/
-void R_LeadingEdge (edge_t *edge)
-{
- espan_t *span;
- surf_t *surf, *surf2;
- int iu;
- float fu, newzi, testzi, newzitop, newzibottom;
-
- if (edge->surfs[1])
- {
- // it's adding a new surface in, so find the correct place
- surf = &surfaces[edge->surfs[1]];
-
- // don't start a span if this is an inverted span, with the end
- // edge preceding the start edge (that is, we've already seen the
- // end edge)
- if (++surf->spanstate == 1)
- {
- surf2 = surfaces[1].next;
-
- if (surf->key < surf2->key)
- goto newtop;
-
- // if it's two surfaces on the same plane, the one that's already
- // active is in front, so keep going unless it's a bmodel
- if (surf->insubmodel && (surf->key == surf2->key))
- {
- // must be two bmodels in the same leaf; sort on 1/z
- fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
- newzi = surf->d_ziorigin + fv*surf->d_zistepv +
- fu*surf->d_zistepu;
- newzibottom = newzi * 0.99;
-
- testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
- fu*surf2->d_zistepu;
-
- if (newzibottom >= testzi)
- {
- goto newtop;
- }
-
- newzitop = newzi * 1.01;
- if (newzitop >= testzi)
- {
- if (surf->d_zistepu >= surf2->d_zistepu)
- {
- goto newtop;
- }
- }
- }
-
-continue_search:
-
- do
- {
- surf2 = surf2->next;
- } while (surf->key > surf2->key);
-
- if (surf->key == surf2->key)
- {
- // if it's two surfaces on the same plane, the one that's already
- // active is in front, so keep going unless it's a bmodel
- if (!surf->insubmodel)
- goto continue_search;
-
- // must be two bmodels in the same leaf; sort on 1/z
- fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
- newzi = surf->d_ziorigin + fv*surf->d_zistepv +
- fu*surf->d_zistepu;
- newzibottom = newzi * 0.99;
-
- testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
- fu*surf2->d_zistepu;
-
- if (newzibottom >= testzi)
- {
- goto gotposition;
- }
-
- newzitop = newzi * 1.01;
- if (newzitop >= testzi)
- {
- if (surf->d_zistepu >= surf2->d_zistepu)
- {
- goto gotposition;
- }
- }
-
- goto continue_search;
- }
-
- goto gotposition;
-
-newtop:
- // emit a span (obscures current top)
- iu = edge->u >> 20;
-
- if (iu > surf2->last_u)
- {
- span = span_p++;
- span->u = surf2->last_u;
- span->count = iu - span->u;
- span->v = current_iv;
- span->pnext = surf2->spans;
- surf2->spans = span;
- }
-
- // set last_u on the new span
- surf->last_u = iu;
-
-gotposition:
- // insert before surf2
- surf->next = surf2;
- surf->prev = surf2->prev;
- surf2->prev->next = surf;
- surf2->prev = surf;
- }
- }
-}
-
-
-/*
-==============
-R_GenerateSpans
-==============
-*/
-void R_GenerateSpans (void)
-{
- edge_t *edge;
- surf_t *surf;
-
-// clear active surfaces to just the background surface
- surfaces[1].next = surfaces[1].prev = &surfaces[1];
- surfaces[1].last_u = edge_head_u_shift20;
-
-// generate spans
- for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
- {
- if (edge->surfs[0])
- {
- // it has a left surface, so a surface is going away for this span
- surf = &surfaces[edge->surfs[0]];
-
- R_TrailingEdge (surf, edge);
-
- if (!edge->surfs[1])
- continue;
- }
-
- R_LeadingEdge (edge);
- }
-
- R_CleanupSpan ();
-}
-
-
-/*
-==============
-R_GenerateSpansBackward
-==============
-*/
-void R_GenerateSpansBackward (void)
-{
- edge_t *edge;
-
-// clear active surfaces to just the background surface
- surfaces[1].next = surfaces[1].prev = &surfaces[1];
- surfaces[1].last_u = edge_head_u_shift20;
-
-// generate spans
- for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
- {
- if (edge->surfs[0])
- R_TrailingEdge (&surfaces[edge->surfs[0]], edge);
-
- if (edge->surfs[1])
- R_LeadingEdgeBackwards (edge);
- }
-
- R_CleanupSpan ();
-}
-
-
-/*
-==============
-R_ScanEdges
-
-Input:
-newedges[] array
- this has links to edges, which have links to surfaces
-
-Output:
-Each surface has a linked list of its visible spans
-==============
-*/
-void R_ScanEdges (void)
-{
- int iv, bottom;
- byte basespans[MAXSPANS*sizeof(espan_t)+CACHE_SIZE];
- espan_t *basespan_p;
- surf_t *s;
-
- basespan_p = (espan_t *)
- ((uintptr)(basespans + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
- max_span_p = &basespan_p[MAXSPANS - r_refdef.vrect.width];
-
- span_p = basespan_p;
-
-// clear active edges to just the background edges around the whole screen
-// FIXME: most of this only needs to be set up once
- edge_head.u = r_refdef.vrect.x << 20;
- edge_head_u_shift20 = edge_head.u >> 20;
- edge_head.u_step = 0;
- edge_head.prev = NULL;
- edge_head.next = &edge_tail;
- edge_head.surfs[0] = 0;
- edge_head.surfs[1] = 1;
-
- edge_tail.u = (r_refdef.vrectright << 20) + 0xFFFFF;
- edge_tail_u_shift20 = edge_tail.u >> 20;
- edge_tail.u_step = 0;
- edge_tail.prev = &edge_head;
- edge_tail.next = &edge_aftertail;
- edge_tail.surfs[0] = 1;
- edge_tail.surfs[1] = 0;
-
- edge_aftertail.u = -1; // force a move
- edge_aftertail.u_step = 0;
- edge_aftertail.next = &edge_sentinel;
- edge_aftertail.prev = &edge_tail;
-
-// FIXME: do we need this now that we clamp x in r_draw.c?
- edge_sentinel.u = 2000 << 24; // make sure nothing sorts past this
- edge_sentinel.prev = &edge_aftertail;
-
-//
-// process all scan lines
-//
- bottom = r_refdef.vrectbottom - 1;
-
- for (iv=r_refdef.vrect.y ; iv<bottom ; iv++)
- {
- current_iv = iv;
- fv = (float)iv;
-
- // mark that the head (background start) span is pre-included
- surfaces[1].spanstate = 1;
-
- if (newedges[iv])
- {
- R_InsertNewEdges (newedges[iv], edge_head.next);
- }
-
- (*pdrawfunc) ();
-
- // flush the span list if we can't be sure we have enough spans left for
- // the next scan
- if (span_p > max_span_p)
- {
- D_DrawSurfaces ();
-
- // clear the surface span pointers
- for (s = &surfaces[1] ; s<surface_p ; s++)
- s->spans = NULL;
-
- span_p = basespan_p;
- }
-
- if (removeedges[iv])
- R_RemoveEdges (removeedges[iv]);
-
- if (edge_head.next != &edge_tail)
- R_StepActiveU (edge_head.next);
- }
-
-// do the last scan (no need to step or sort or remove on the last scan)
-
- current_iv = iv;
- fv = (float)iv;
-
-// mark that the head (background start) span is pre-included
- surfaces[1].spanstate = 1;
-
- if (newedges[iv])
- R_InsertNewEdges (newedges[iv], edge_head.next);
-
- (*pdrawfunc) ();
-
-// draw whatever's left in the span list
- D_DrawSurfaces ();
-}
-
-
-/*
-=========================================================================
-
-SURFACE FILLING
-
-=========================================================================
-*/
-
-msurface_t *pface;
-surfcache_t *pcurrentcache;
-vec3_t transformed_modelorg;
-vec3_t world_transformed_modelorg;
-vec3_t local_modelorg;
-
-/*
-=============
-D_MipLevelForScale
-=============
-*/
-int D_MipLevelForScale (float scale)
-{
- int lmiplevel;
-
- if (scale >= d_scalemip[0] )
- lmiplevel = 0;
- else if (scale >= d_scalemip[1] )
- lmiplevel = 1;
- else if (scale >= d_scalemip[2] )
- lmiplevel = 2;
- else
- lmiplevel = 3;
-
- if (lmiplevel < d_minmip)
- lmiplevel = d_minmip;
-
- return lmiplevel;
-}
-
-
-/*
-==============
-D_FlatFillSurface
-
-Simple single color fill with no texture mapping
-==============
-*/
-void D_FlatFillSurface (surf_t *surf, int color)
-{
- espan_t *span;
- byte *pdest;
- int u, u2;
-
- for (span=surf->spans ; span ; span=span->pnext)
- {
- pdest = (byte *)d_viewbuffer + r_screenwidth*span->v;
- u = span->u;
- u2 = span->u + span->count - 1;
- for ( ; u <= u2 ; u++)
- pdest[u] = color;
- }
-}
-
-
-/*
-==============
-D_CalcGradients
-==============
-*/
-void D_CalcGradients (msurface_t *pface)
-{
- float mipscale;
- vec3_t p_temp1;
- vec3_t p_saxis, p_taxis;
- float t;
-
- mipscale = 1.0 / (float)(1 << miplevel);
-
- TransformVector (pface->texinfo->vecs[0], p_saxis);
- TransformVector (pface->texinfo->vecs[1], p_taxis);
-
- t = xscaleinv * mipscale;
- d_sdivzstepu = p_saxis[0] * t;
- d_tdivzstepu = p_taxis[0] * t;
-
- t = yscaleinv * mipscale;
- d_sdivzstepv = -p_saxis[1] * t;
- d_tdivzstepv = -p_taxis[1] * t;
-
- d_sdivzorigin = p_saxis[2] * mipscale - xcenter * d_sdivzstepu -
- ycenter * d_sdivzstepv;
- d_tdivzorigin = p_taxis[2] * mipscale - xcenter * d_tdivzstepu -
- ycenter * d_tdivzstepv;
-
- VectorScale (transformed_modelorg, mipscale, p_temp1);
-
- t = 0x10000*mipscale;
- sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) -
- ((pface->texturemins[0] << 16) >> miplevel)
- + pface->texinfo->vecs[0][3]*t;
- tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) -
- ((pface->texturemins[1] << 16) >> miplevel)
- + pface->texinfo->vecs[1][3]*t;
-
- // PGM - changing flow speed for non-warping textures.
- if (pface->texinfo->flags & SURF_FLOWING)
- {
- if(pface->texinfo->flags & SURF_WARP)
- sadjust += 0x10000 * (-128 * ( (r_newrefdef.time * 0.25) - (int)(r_newrefdef.time * 0.25) ));
- else
- sadjust += 0x10000 * (-128 * ( (r_newrefdef.time * 0.77) - (int)(r_newrefdef.time * 0.77) ));
- }
- // PGM
-
-//
-// -1 (-epsilon) so we never wander off the edge of the texture
-//
- bbextents = ((pface->extents[0] << 16) >> miplevel) - 1;
- bbextentt = ((pface->extents[1] << 16) >> miplevel) - 1;
-}
-
-
-/*
-==============
-D_BackgroundSurf
-
-The grey background filler seen when there is a hole in the map
-==============
-*/
-void D_BackgroundSurf (surf_t *s)
-{
-// set up a gradient for the background surface that places it
-// effectively at infinity distance from the viewpoint
- d_zistepu = 0;
- d_zistepv = 0;
- d_ziorigin = -0.9;
-
- D_FlatFillSurface (s, (int)sw_clearcolor->value & 0xFF);
- D_DrawZSpans (s->spans);
-}
-
-/*
-=================
-D_TurbulentSurf
-=================
-*/
-void D_TurbulentSurf (surf_t *s)
-{
- d_zistepu = s->d_zistepu;
- d_zistepv = s->d_zistepv;
- d_ziorigin = s->d_ziorigin;
-
- pface = s->msurf;
- miplevel = 0;
- cacheblock = pface->texinfo->image->pixels[0];
- cachewidth = 64;
-
- if (s->insubmodel)
- {
- // FIXME: we don't want to do all this for every polygon!
- // TODO: store once at start of frame
- currententity = s->entity; //FIXME: make this passed in to
- // R_RotateBmodel ()
- VectorSubtract (r_origin, currententity->origin,
- local_modelorg);
- TransformVector (local_modelorg, transformed_modelorg);
-
- R_RotateBmodel (); // FIXME: don't mess with the frustum,
- // make entity passed in
- }
-
- D_CalcGradients (pface);
-
-//============
-//PGM
- // textures that aren't warping are just flowing. Use NonTurbulent8 instead
- if(!(pface->texinfo->flags & SURF_WARP))
- NonTurbulent8 (s->spans);
- else
- Turbulent8 (s->spans);
-//PGM
-//============
-
- D_DrawZSpans (s->spans);
-
- if (s->insubmodel)
- {
- //
- // restore the old drawing state
- // FIXME: we don't want to do this every time!
- // TODO: speed up
- //
- currententity = NULL; // &r_worldentity;
- VectorCopy (world_transformed_modelorg,
- transformed_modelorg);
- VectorCopy (base_vpn, vpn);
- VectorCopy (base_vup, vup);
- VectorCopy (base_vright, vright);
- R_TransformFrustum ();
- }
-}
-
-/*
-==============
-D_SkySurf
-==============
-*/
-void D_SkySurf (surf_t *s)
-{
- pface = s->msurf;
- miplevel = 0;
- if (!pface->texinfo->image)
- return;
- cacheblock = pface->texinfo->image->pixels[0];
- cachewidth = 256;
-
- d_zistepu = s->d_zistepu;
- d_zistepv = s->d_zistepv;
- d_ziorigin = s->d_ziorigin;
-
- D_CalcGradients (pface);
-
- D_DrawSpans16 (s->spans);
-
-// set up a gradient for the background surface that places it
-// effectively at infinity distance from the viewpoint
- d_zistepu = 0;
- d_zistepv = 0;
- d_ziorigin = -0.9;
-
- D_DrawZSpans (s->spans);
-}
-
-/*
-==============
-D_SolidSurf
-
-Normal surface cached, texture mapped surface
-==============
-*/
-void D_SolidSurf (surf_t *s)
-{
- d_zistepu = s->d_zistepu;
- d_zistepv = s->d_zistepv;
- d_ziorigin = s->d_ziorigin;
-
- if (s->insubmodel)
- {
- // FIXME: we don't want to do all this for every polygon!
- // TODO: store once at start of frame
- currententity = s->entity; //FIXME: make this passed in to
- // R_RotateBmodel ()
- VectorSubtract (r_origin, currententity->origin, local_modelorg);
- TransformVector (local_modelorg, transformed_modelorg);
-
- R_RotateBmodel (); // FIXME: don't mess with the frustum,
- // make entity passed in
- }
- else
- currententity = &r_worldentity;
-
- pface = s->msurf;
-/* commented out in release
- {
- float dot;
- float normal[3];
-
- if ( s->insubmodel )
- {
- VectorCopy( pface->plane->normal, normal );
-// TransformVector( pface->plane->normal, normal);
- dot = DotProduct( normal, vpn );
- }
- else
- {
- VectorCopy( pface->plane->normal, normal );
- dot = DotProduct( normal, vpn );
- }
-
- if ( pface->flags & SURF_PLANEBACK )
- dot = -dot;
-
- if ( dot > 0 )
- printf( "blah" );
-
- miplevel = D_MipLevelForScale(s->nearzi * scale_for_mip * pface->texinfo->mipadjust);
- }
-*/
- miplevel = D_MipLevelForScale(s->nearzi * scale_for_mip * pface->texinfo->mipadjust);
-
-// FIXME: make this passed in to D_CacheSurface
- pcurrentcache = D_CacheSurface (pface, miplevel);
-
- cacheblock = (pixel_t *)pcurrentcache->data;
- cachewidth = pcurrentcache->width;
-
- D_CalcGradients (pface);
-
- D_DrawSpans16 (s->spans);
-
- D_DrawZSpans (s->spans);
-
- if (s->insubmodel)
- {
- //
- // restore the old drawing state
- // FIXME: we don't want to do this every time!
- // TODO: speed up
- //
- VectorCopy (world_transformed_modelorg,
- transformed_modelorg);
- VectorCopy (base_vpn, vpn);
- VectorCopy (base_vup, vup);
- VectorCopy (base_vright, vright);
- R_TransformFrustum ();
- currententity = NULL; //&r_worldentity;
- }
-}
-
-/*
-=============
-D_DrawflatSurfaces
-
-To allow developers to see the polygon carving of the world
-=============
-*/
-void D_DrawflatSurfaces (void)
-{
- surf_t *s;
-
- for (s = &surfaces[1] ; s<surface_p ; s++)
- {
- if (!s->spans)
- continue;
-
- d_zistepu = s->d_zistepu;
- d_zistepv = s->d_zistepv;
- d_ziorigin = s->d_ziorigin;
-
- // make a stable color for each surface by taking the low
- // bits of the msurface pointer
- D_FlatFillSurface (s, (uintptr)s->msurf & 0xFF);
- D_DrawZSpans (s->spans);
- }
-}
-
-/*
-==============
-D_DrawSurfaces
-
-Rasterize all the span lists. Guaranteed zero overdraw.
-May be called more than once a frame if the surf list overflows (higher res)
-==============
-*/
-void D_DrawSurfaces (void)
-{
- surf_t *s;
-
-// currententity = NULL; //&r_worldentity;
- VectorSubtract (r_origin, vec3_origin, modelorg);
- TransformVector (modelorg, transformed_modelorg);
- VectorCopy (transformed_modelorg, world_transformed_modelorg);
-
- if (!sw_drawflat->value)
- {
- for (s = &surfaces[1] ; s<surface_p ; s++)
- {
- if (!s->spans)
- continue;
-
- r_drawnpolycount++;
-
- if (! (s->flags & (SURF_DRAWSKYBOX|SURF_DRAWBACKGROUND|SURF_DRAWTURB) ) )
- D_SolidSurf (s);
- else if (s->flags & SURF_DRAWSKYBOX)
- D_SkySurf (s);
- else if (s->flags & SURF_DRAWBACKGROUND)
- D_BackgroundSurf (s);
- else if (s->flags & SURF_DRAWTURB)
- D_TurbulentSurf (s);
- }
- }
- else
- D_DrawflatSurfaces ();
-
- currententity = NULL; //&r_worldentity;
- VectorSubtract (r_origin, vec3_origin, modelorg);
- R_TransformFrustum ();
-}
-
--- a/ref/r_image.c
+++ /dev/null
@@ -1,586 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-
-#define MAX_RIMAGES 1024
-image_t r_images[MAX_RIMAGES];
-int numr_images;
-
-
-/*
-===============
-R_ImageList_f
-===============
-*/
-void R_ImageList_f (void)
-{
- int i;
- image_t *image;
- int texels;
-
- ri.Con_Printf (PRINT_ALL, "------------------\n");
- texels = 0;
-
- for (i=0, image=r_images ; i<numr_images ; i++, image++)
- {
- if (image->registration_sequence <= 0)
- continue;
- texels += image->width*image->height;
- switch (image->type)
- {
- case it_skin:
- ri.Con_Printf (PRINT_ALL, "M");
- break;
- case it_sprite:
- ri.Con_Printf (PRINT_ALL, "S");
- break;
- case it_wall:
- ri.Con_Printf (PRINT_ALL, "W");
- break;
- case it_pic:
- ri.Con_Printf (PRINT_ALL, "P");
- break;
- default:
- ri.Con_Printf (PRINT_ALL, " ");
- break;
- }
-
- ri.Con_Printf (PRINT_ALL, " %3i %3i : %s\n",
- image->width, image->height, image->name);
- }
- ri.Con_Printf (PRINT_ALL, "Total texel count: %i\n", texels);
-}
-
-
-/*
-=================================================================
-
-PCX LOADING
-
-=================================================================
-*/
-
-/*
-==============
-LoadPCX
-==============
-*/
-void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
-{
- byte *raw;
- pcx_t *pcx;
- int x, y;
- int len;
- int dataByte, runLength;
- byte *out, *pix;
-
- *pic = NULL;
-
- //
- // load the file
- //
- len = ri.FS_LoadFile (filename, (void **)&raw);
- if (!raw)
- {
- ri.Con_Printf (PRINT_DEVELOPER, "Bad pcx file %s\n", filename);
- return;
- }
-
- //
- // parse the PCX file
- //
- pcx = (pcx_t *)raw;
-
- pcx->xmin = LittleShort(pcx->xmin);
- pcx->ymin = LittleShort(pcx->ymin);
- pcx->xmax = LittleShort(pcx->xmax);
- pcx->ymax = LittleShort(pcx->ymax);
- pcx->hres = LittleShort(pcx->hres);
- pcx->vres = LittleShort(pcx->vres);
- pcx->bytes_per_line = LittleShort(pcx->bytes_per_line);
- pcx->palette_type = LittleShort(pcx->palette_type);
-
- raw = &pcx->data;
-
- if (pcx->manufacturer != 0x0a
- || pcx->version != 5
- || pcx->encoding != 1
- || pcx->bits_per_pixel != 8
- || pcx->xmax >= 640
- || pcx->ymax >= 480)
- {
- ri.Con_Printf (PRINT_ALL, "Bad pcx file %s\n", filename);
- return;
- }
-
- out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
-
- *pic = out;
-
- pix = out;
-
- if (palette)
- {
- *palette = malloc(768);
- memcpy (*palette, (byte *)pcx + len - 768, 768);
- }
-
- if (width)
- *width = pcx->xmax+1;
- if (height)
- *height = pcx->ymax+1;
-
- for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
- {
- for (x=0 ; x<=pcx->xmax ; )
- {
- dataByte = *raw++;
-
- if((dataByte & 0xC0) == 0xC0)
- {
- runLength = dataByte & 0x3F;
- dataByte = *raw++;
- }
- else
- runLength = 1;
-
- while(runLength-- > 0)
- pix[x++] = dataByte;
- }
-
- }
-
- if ( raw - (byte *)pcx > len)
- {
- ri.Con_Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename);
- free (*pic);
- *pic = NULL;
- }
-
- ri.FS_FreeFile (pcx);
-}
-
-/*
-=========================================================
-
-TARGA LOADING
-
-=========================================================
-*/
-
-typedef struct _TargaHeader {
- unsigned char id_length, colormap_type, image_type;
- unsigned short colormap_index, colormap_length;
- unsigned char colormap_size;
- unsigned short x_origin, y_origin, width, height;
- unsigned char pixel_size, attributes;
-} TargaHeader;
-
-
-/*
-=============
-LoadTGA
-=============
-*/
-void LoadTGA (char *name, byte **pic, int *width, int *height)
-{
- int columns, rows, numPixels;
- byte *pixbuf;
- int row, column;
- byte *buf_p;
- byte *buffer;
- TargaHeader targa_header;
- byte *targa_rgba;
- uchar red = 0, green = 0, blue = 0, alphabyte = 0, packetHeader, packetSize, j;
-
- *pic = NULL;
-
- //
- // load the file
- //
- ri.FS_LoadFile (name, (void **)&buffer); /* int length = */
- if (!buffer)
- {
- ri.Con_Printf (PRINT_DEVELOPER, "Bad tga file %s\n", name);
- return;
- }
-
- buf_p = buffer;
-
- targa_header.id_length = *buf_p++;
- targa_header.colormap_type = *buf_p++;
- targa_header.image_type = *buf_p++;
-
- targa_header.colormap_index = LittleShort ( *((short *)buf_p) );
- buf_p+=2;
- targa_header.colormap_length = LittleShort ( *((short *)buf_p) );
- buf_p+=2;
- targa_header.colormap_size = *buf_p++;
- targa_header.x_origin = LittleShort ( *((short *)buf_p) );
- buf_p+=2;
- targa_header.y_origin = LittleShort ( *((short *)buf_p) );
- buf_p+=2;
- targa_header.width = LittleShort ( *((short *)buf_p) );
- buf_p+=2;
- targa_header.height = LittleShort ( *((short *)buf_p) );
- buf_p+=2;
- targa_header.pixel_size = *buf_p++;
- targa_header.attributes = *buf_p++;
-
- if (targa_header.image_type!=2
- && targa_header.image_type!=10)
- ri.Sys_Error (ERR_DROP, "LoadTGA: Only type 2 and 10 targa RGB images supported\n");
-
- if (targa_header.colormap_type !=0
- || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24))
- ri.Sys_Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
-
- columns = targa_header.width;
- rows = targa_header.height;
- numPixels = columns * rows;
-
- if (width)
- *width = columns;
- if (height)
- *height = rows;
-
- targa_rgba = malloc (numPixels*4);
- *pic = targa_rgba;
-
- if (targa_header.id_length != 0)
- buf_p += targa_header.id_length; // skip TARGA image comment
-
- if (targa_header.image_type==2) { // Uncompressed, RGB images
- for(row=rows-1; row>=0; row--) {
- pixbuf = targa_rgba + row*columns*4;
- for(column=0; column<columns; column++) {
- switch (targa_header.pixel_size) {
- case 24:
-
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = 255;
- break;
- case 32:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- alphabyte = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = alphabyte;
- break;
- }
- }
- }
- }
- else if (targa_header.image_type==10) { // Runlength encoded RGB images
- for(row=rows-1; row>=0; row--) {
- pixbuf = targa_rgba + row*columns*4;
- for(column=0; column<columns; ) {
- packetHeader= *buf_p++;
- packetSize = 1 + (packetHeader & 0x7f);
- if (packetHeader & 0x80) { // run-length packet
- switch (targa_header.pixel_size) {
- case 24:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- alphabyte = 255;
- break;
- case 32:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- alphabyte = *buf_p++;
- break;
- }
-
- for(j=0;j<packetSize;j++) {
- *pixbuf++=red;
- *pixbuf++=green;
- *pixbuf++=blue;
- *pixbuf++=alphabyte;
- column++;
- if (column==columns) { // run spans across rows
- column=0;
- if (row>0)
- row--;
- else
- goto breakOut;
- pixbuf = targa_rgba + row*columns*4;
- }
- }
- }
- else { // non run-length packet
- for(j=0;j<packetSize;j++) {
- switch (targa_header.pixel_size) {
- case 24:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = 255;
- break;
- case 32:
- blue = *buf_p++;
- green = *buf_p++;
- red = *buf_p++;
- alphabyte = *buf_p++;
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- *pixbuf++ = alphabyte;
- break;
- }
- column++;
- if (column==columns) { // pixel packet run spans across rows
- column=0;
- if (row>0)
- row--;
- else
- goto breakOut;
- pixbuf = targa_rgba + row*columns*4;
- }
- }
- }
- }
- breakOut:;
- }
- }
-
- ri.FS_FreeFile (buffer);
-}
-
-
-//=======================================================
-
-image_t *R_FindFreeImage (void)
-{
- image_t *image;
- int i;
-
- // find a free image_t
- for (i=0, image=r_images ; i<numr_images ; i++,image++)
- {
- if (!image->registration_sequence)
- break;
- }
- if (i == numr_images)
- {
- if (numr_images == MAX_RIMAGES)
- ri.Sys_Error (ERR_DROP, "MAX_RIMAGES");
- numr_images++;
- }
- image = &r_images[i];
-
- return image;
-}
-
-/*
-================
-GL_LoadPic
-
-================
-*/
-image_t *GL_LoadPic (char *name, byte *pic, int width, int height, imagetype_t type)
-{
- image_t *image;
- int i, c, b;
-
- image = R_FindFreeImage ();
- if (strlen(name) >= sizeof(image->name))
- ri.Sys_Error (ERR_DROP, "Draw_LoadPic: \"%s\" is too long", name);
- strcpy (image->name, name);
- image->registration_sequence = registration_sequence;
-
- image->width = width;
- image->height = height;
- image->type = type;
-
- c = width*height;
- image->pixels[0] = malloc (c);
- image->transparent = false;
- for (i=0 ; i<c ; i++)
- {
- b = pic[i];
- if (b == 255)
- image->transparent = true;
- image->pixels[0][i] = b;
- }
-
- return image;
-}
-
-/*
-================
-R_LoadWal
-================
-*/
-image_t *R_LoadWal (char *name)
-{
- miptex_t *mt;
- int ofs;
- image_t *image;
- int size;
-
- ri.FS_LoadFile (name, (void **)&mt);
- if (!mt)
- {
- ri.Con_Printf (PRINT_ALL, "R_LoadWal: can't load %s\n", name);
- return r_notexture_mip;
- }
-
- image = R_FindFreeImage ();
- strcpy (image->name, name);
- image->width = LittleLong (mt->width);
- image->height = LittleLong (mt->height);
- image->type = it_wall;
- image->registration_sequence = registration_sequence;
-
- size = image->width*image->height * (256+64+16+4)/256;
- image->pixels[0] = malloc (size);
- image->pixels[1] = image->pixels[0] + image->width*image->height;
- image->pixels[2] = image->pixels[1] + image->width*image->height/4;
- image->pixels[3] = image->pixels[2] + image->width*image->height/16;
-
- ofs = LittleLong (mt->offsets[0]);
- memcpy ( image->pixels[0], (byte *)mt + ofs, size);
-
- ri.FS_FreeFile ((void *)mt);
-
- return image;
-}
-
-
-/*
-===============
-R_FindImage
-
-Finds or loads the given image
-===============
-*/
-image_t *R_FindImage (char *name, imagetype_t type)
-{
- image_t *image;
- int i, len;
- byte *pic, *palette;
- int width, height;
-
- if (!name)
- return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: NULL name");
- len = strlen(name);
- if (len<5)
- return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: bad name: %s", name);
-
- // look for it
- for (i=0, image=r_images ; i<numr_images ; i++,image++)
- {
- if (!strcmp(name, image->name))
- {
- image->registration_sequence = registration_sequence;
- return image;
- }
- }
-
- //
- // load the pic from disk
- //
- pic = NULL;
- palette = NULL;
- if (!strcmp(name+len-4, ".pcx"))
- {
- LoadPCX (name, &pic, &palette, &width, &height);
- if (!pic)
- return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: can't load %s", name);
- image = GL_LoadPic (name, pic, width, height, type);
- }
- else if (!strcmp(name+len-4, ".wal"))
- {
- image = R_LoadWal (name);
- }
- else if (!strcmp(name+len-4, ".tga"))
- return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: can't load %s in software renderer", name);
- else
- return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: bad extension on: %s", name);
-
- if (pic)
- free(pic);
- if (palette)
- free(palette);
-
- return image;
-}
-
-
-
-/*
-===============
-R_RegisterSkin
-===============
-*/
-struct image_s *R_RegisterSkin (char *name)
-{
- return R_FindImage (name, it_skin);
-}
-
-
-/*
-================
-R_FreeUnusedImages
-
-Any image that was not touched on this registration sequence
-will be freed.
-================
-*/
-void R_FreeUnusedImages (void)
-{
- int i;
- image_t *image;
-
- for (i=0, image=r_images ; i<numr_images ; i++, image++)
- {
- if (image->registration_sequence == registration_sequence)
- {
- Com_PageInMemory ((byte *)image->pixels[0], image->width*image->height);
- continue; // used this sequence
- }
- if (!image->registration_sequence)
- continue; // free texture
- if (image->type == it_pic)
- continue; // don't free pics
- // free it
- free (image->pixels[0]); // the other mip levels just follow
- memset (image, 0, sizeof(*image));
- }
-}
-
-void
-R_InitImages(void)
-{
- registration_sequence = 1;
-}
-
-void
-R_ShutdownImages(void)
-{
- int i;
- image_t *image;
-
- for(i=0, image=r_images; i<numr_images; i++, image++){
- if(!image->registration_sequence)
- continue; // free texture
- // free it
- free(image->pixels[0]); // the other mip levels just follow
- memset(image, 0, sizeof *image);
- }
-}
--- a/ref/r_light.c
+++ /dev/null
@@ -1,422 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-int r_dlightframecount;
-
-
-/*
-=============================================================================
-
-DYNAMIC LIGHTS
-
-=============================================================================
-*/
-
-/*
-=============
-R_MarkLights
-=============
-*/
-void R_MarkLights (dlight_t *light, int bit, mnode_t *node)
-{
- mplane_t *splitplane;
- float dist;
- msurface_t *surf;
- int i;
-
- if (node->contents != -1)
- return;
-
- splitplane = node->plane;
- dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist;
-
-//=====
-//PGM
- i=light->intensity;
- if(i<0)
- i=-i;
-//PGM
-//=====
-
- if (dist > i) // PGM (dist > light->intensity)
- {
- R_MarkLights (light, bit, node->children[0]);
- return;
- }
- if (dist < -i) // PGM (dist < -light->intensity)
- {
- R_MarkLights (light, bit, node->children[1]);
- return;
- }
-
-// mark the polygons
- surf = r_worldmodel->surfaces + node->firstsurface;
- for (i=0 ; i<node->numsurfaces ; i++, surf++)
- {
- if (surf->dlightframe != r_dlightframecount)
- {
- surf->dlightbits = 0;
- surf->dlightframe = r_dlightframecount;
- }
- surf->dlightbits |= bit;
- }
-
- R_MarkLights (light, bit, node->children[0]);
- R_MarkLights (light, bit, node->children[1]);
-}
-
-
-/*
-=============
-R_PushDlights
-=============
-*/
-void R_PushDlights (model_t *model)
-{
- int i;
- dlight_t *l;
-
- r_dlightframecount = r_framecount;
- for (i=0, l = r_newrefdef.dlights ; i<r_newrefdef.num_dlights ; i++, l++)
- {
- R_MarkLights ( l, 1<<i,
- model->nodes + model->firstnode);
- }
-}
-
-
-/*
-=============================================================================
-
-LIGHT SAMPLING
-
-=============================================================================
-*/
-
-vec3_t pointcolor;
-mplane_t *lightplane; // used as shadow plane
-vec3_t lightspot;
-
-int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end)
-{
- float front, back, frac;
- int side;
- mplane_t *plane;
- vec3_t mid;
- msurface_t *surf;
- int s, t, ds, dt;
- int i;
- mtexinfo_t *tex;
- byte *lightmap;
- float *scales;
- int maps;
- float samp;
- int r;
-
- if (node->contents != -1)
- return -1; // didn't hit anything
-
-// calculate mid point
-
-// FIXME: optimize for axial
- plane = node->plane;
- front = DotProduct (start, plane->normal) - plane->dist;
- back = DotProduct (end, plane->normal) - plane->dist;
- side = front < 0;
-
- if ( (back < 0) == side)
- return RecursiveLightPoint (node->children[side], start, end);
-
- frac = front / (front-back);
- mid[0] = start[0] + (end[0] - start[0])*frac;
- mid[1] = start[1] + (end[1] - start[1])*frac;
- mid[2] = start[2] + (end[2] - start[2])*frac;
- if (plane->type < 3) // axial planes
- mid[plane->type] = plane->dist;
-
-// go down front side
- r = RecursiveLightPoint (node->children[side], start, mid);
- if (r >= 0)
- return r; // hit something
-
- if ( (back < 0) == side )
- return -1; // didn't hit anuthing
-
-// check for impact on this node
- VectorCopy (mid, lightspot);
- lightplane = plane;
-
- surf = r_worldmodel->surfaces + node->firstsurface;
- for (i=0 ; i<node->numsurfaces ; i++, surf++)
- {
- if (surf->flags&(SURF_DRAWTURB|SURF_DRAWSKY))
- continue; // no lightmaps
-
- tex = surf->texinfo;
-
- s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3];
- t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3];
- if (s < surf->texturemins[0] ||
- t < surf->texturemins[1])
- continue;
-
- ds = s - surf->texturemins[0];
- dt = t - surf->texturemins[1];
-
- if ( ds > surf->extents[0] || dt > surf->extents[1] )
- continue;
-
- if (!surf->samples)
- return 0;
-
- ds >>= 4;
- dt >>= 4;
-
- lightmap = surf->samples;
- VectorCopy (vec3_origin, pointcolor);
- if (lightmap)
- {
- lightmap += dt * ((surf->extents[0]>>4)+1) + ds;
-
- for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
- maps++)
- {
- samp = *lightmap * /* 0.5 * */ (1.0/255); // adjust for gl scale
- scales = r_newrefdef.lightstyles[surf->styles[maps]].rgb;
- VectorMA (pointcolor, samp, scales, pointcolor);
- lightmap += ((surf->extents[0]>>4)+1) *
- ((surf->extents[1]>>4)+1);
- }
- }
-
- return 1;
- }
-
-// go down back side
- return RecursiveLightPoint (node->children[!side], mid, end);
-}
-
-/*
-===============
-R_LightPoint
-===============
-*/
-void R_LightPoint (vec3_t p, vec3_t color)
-{
- vec3_t end;
- float r;
- int lnum;
- dlight_t *dl;
- vec3_t dist;
- float add;
-
- if (!r_worldmodel->lightdata)
- {
- color[0] = color[1] = color[2] = 1.0;
- return;
- }
-
- end[0] = p[0];
- end[1] = p[1];
- end[2] = p[2] - 2048;
-
- r = RecursiveLightPoint (r_worldmodel->nodes, p, end);
-
- if (r == -1)
- {
- VectorCopy (vec3_origin, color);
- }
- else
- {
- VectorCopy (pointcolor, color);
- }
-
- //
- // add dynamic lights
- //
- for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++)
- {
- dl = &r_newrefdef.dlights[lnum];
- VectorSubtract (currententity->origin,
- dl->origin,
- dist);
- add = dl->intensity - VectorLength(dist);
- add *= (1.0/256);
- if (add > 0)
- {
- VectorMA (color, add, dl->color, color);
- }
- }
-}
-
-//===================================================================
-
-
-unsigned blocklights[1024]; // allow some very large lightmaps
-
-/*
-===============
-R_AddDynamicLights
-===============
-*/
-void R_AddDynamicLights (void)
-{
- msurface_t *surf;
- int lnum;
- int sd, td;
- float dist, rad, minlight;
- vec3_t impact, local;
- int s, t;
- int i;
- int smax, tmax;
- mtexinfo_t *tex;
- dlight_t *dl;
- int negativeLight; //PGM
-
- surf = r_drawsurf.surf;
- smax = (surf->extents[0]>>4)+1;
- tmax = (surf->extents[1]>>4)+1;
- tex = surf->texinfo;
-
- for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++)
- {
- if ( !(surf->dlightbits & (1<<lnum) ) )
- continue; // not lit by this light
-
- dl = &r_newrefdef.dlights[lnum];
- rad = dl->intensity;
-
-//=====
-//PGM
- negativeLight = 0;
- if(rad < 0)
- {
- negativeLight = 1;
- rad = -rad;
- }
-//PGM
-//=====
-
- dist = DotProduct (dl->origin, surf->plane->normal) -
- surf->plane->dist;
- rad -= fabs(dist);
- minlight = 32; // dl->minlight;
- if (rad < minlight)
- continue;
- minlight = rad - minlight;
-
- for (i=0 ; i<3 ; i++)
- {
- impact[i] = dl->origin[i] -
- surf->plane->normal[i]*dist;
- }
-
- local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3];
- local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3];
-
- local[0] -= surf->texturemins[0];
- local[1] -= surf->texturemins[1];
-
- for (t = 0 ; t<tmax ; t++)
- {
- td = local[1] - t*16;
- if (td < 0)
- td = -td;
- for (s=0 ; s<smax ; s++)
- {
- sd = local[0] - s*16;
- if (sd < 0)
- sd = -sd;
- if (sd > td)
- dist = sd + (td>>1);
- else
- dist = td + (sd>>1);
-//====
-//PGM
- if(!negativeLight)
- {
- if (dist < minlight)
- blocklights[t*smax + s] += (rad - dist)*256;
- }
- else
- {
- if (dist < minlight)
- blocklights[t*smax + s] -= (rad - dist)*256;
- if(blocklights[t*smax + s] < minlight)
- blocklights[t*smax + s] = minlight;
- }
-//PGM
-//====
- }
- }
- }
-}
-
-/*
-===============
-R_BuildLightMap
-
-Combine and scale multiple lightmaps into the 8.8 format in blocklights
-===============
-*/
-void R_BuildLightMap (void)
-{
- int smax, tmax;
- int t;
- int i, size;
- byte *lightmap;
- unsigned scale;
- int maps;
- msurface_t *surf;
-
- surf = r_drawsurf.surf;
-
- smax = (surf->extents[0]>>4)+1;
- tmax = (surf->extents[1]>>4)+1;
- size = smax*tmax;
-
- if (r_fullbright->value || !r_worldmodel->lightdata)
- {
- for (i=0 ; i<size ; i++)
- blocklights[i] = 0;
- return;
- }
-
-// clear to no light
- for (i=0 ; i<size ; i++)
- blocklights[i] = 0;
-
-
-// add all the lightmaps
- lightmap = surf->samples;
- if (lightmap)
- for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
- maps++)
- {
- scale = r_drawsurf.lightadj[maps]; // 8.8 fraction
- for (i=0 ; i<size ; i++)
- blocklights[i] += lightmap[i] * scale;
- lightmap += size; // skip to next lightmap
- }
-
-// add all the dynamic lights
- if (surf->dlightframe == r_framecount)
- R_AddDynamicLights ();
-
-// bound, invert, and shift
- for (i=0 ; i<size ; i++)
- {
- t = (int)blocklights[i];
- if (t < 0)
- t = 0;
- t = (255*256 - t) >> (8 - VID_CBITS);
-
- if (t < (1 << 6))
- t = (1 << 6);
-
- blocklights[i] = t;
- }
-}
-
--- a/ref/r_local.h
+++ /dev/null
@@ -1,1017 +1,0 @@
-#define REF_VERSION "SOFT 0.01"
-
-/* macro redefinitions
-// up / down
-#define PITCH 0
-
-// left / right
-#define YAW 1
-
-// fall over
-#define ROLL 2
-*/
-
-/*
-
- skins will be outline flood filled and mip mapped
- pics and sprites with alpha will be outline flood filled
- pic won't be mip mapped
-
- model skin
- sprite frame
- wall texture
- pic
-
-*/
-
-typedef enum
-{
- it_skin,
- it_sprite,
- it_wall,
- it_pic,
- it_sky
-} imagetype_t;
-
-typedef struct image_s
-{
- char name[MAX_QPATH]; // game path, including extension
- imagetype_t type;
- int width, height;
- qboolean transparent; // true if any 255 pixels in image
- int registration_sequence; // 0 = free
- byte *pixels[4]; // mip levels
-} image_t;
-
-typedef enum
-{
- rserr_ok,
-
- rserr_invalid_fullscreen,
- rserr_invalid_mode,
-
- rserr_unknown
-} rserr_t;
-
-// !!! if this is changed, it must be changed in asm_draw.h too !!!
-typedef struct
-{
- vrect_t vrect; // subwindow in video for refresh
- // FIXME: not need vrect next field here?
- vrect_t aliasvrect; // scaled Alias version
- int vrectright, vrectbottom; // right & bottom screen coords
- int aliasvrectright, aliasvrectbottom; // scaled Alias versions
- float vrectrightedge; // rightmost right edge we care about,
- // for use in edge list
- float fvrectx, fvrecty; // for floating-point compares
- float fvrectx_adj, fvrecty_adj; // left and top edges, for clamping
- int vrect_x_adj_shift20; // (vrect.x + 0.5 - epsilon) << 20
- int vrectright_adj_shift20; // (vrectright + 0.5 - epsilon) << 20
- float fvrectright_adj, fvrectbottom_adj;
- // right and bottom edges, for clamping
- float fvrectright; // rightmost edge, for Alias clamping
- float fvrectbottom; // bottommost edge, for Alias clamping
- float horizontalFieldOfView; // at Z = 1.0, this many X is visible
- // 2.0 = 90 degrees
- float xOrigin; // should probably always be 0.5
- float yOrigin; // between be around 0.3 to 0.5
-
- vec3_t vieworg;
- vec3_t viewangles;
-
- int ambientlight;
-} oldrefdef_t;
-
-extern oldrefdef_t r_refdef;
-
-/* r_model.h */
-
-/*
-d*_t structures are on-disk representations
-m*_t structures are in-memory
-*/
-
-
-/*
-==============================================================================
-
-BRUSH MODELS
-
-==============================================================================
-*/
-
-
-//
-// in memory representation
-//
-// !!! if this is changed, it must be changed in asm_draw.h too !!!
-typedef struct
-{
- vec3_t position;
-} mvertex_t;
-
-#define SIDE_FRONT 0
-#define SIDE_BACK 1
-#define SIDE_ON 2
-
-
-// plane_t structure
-// !!! if this is changed, it must be changed in asm_i386.h too !!!
-typedef struct mplane_s
-{
- vec3_t normal;
- float dist;
- byte type; // for texture axis selection and fast side tests
- byte signbits; // signx + signy<<1 + signz<<1
- byte pad[2];
-} mplane_t;
-
-
-// FIXME: differentiate from texinfo SURF_ flags
-#define SURF_PLANEBACK 2
-#define SURF_DRAWSKY 4 // sky brush face
-#define SURF_DRAWTURB 0x10
-#define SURF_DRAWBACKGROUND 0x40
-#define SURF_DRAWSKYBOX 0x80 // sky box
-
-#define SURF_FLOW 0x100 //PGM
-
-// !!! if this is changed, it must be changed in asm_draw.h too !!!
-typedef struct
-{
- unsigned short v[2];
- unsigned int cachededgeoffset;
-} medge_t;
-
-typedef struct mtexinfo_s
-{
- float vecs[2][4];
- float mipadjust;
- image_t *image;
- int flags;
- int numframes;
- struct mtexinfo_s *next; // animation chain
-} mtexinfo_t;
-
-typedef struct msurface_s
-{
- int visframe; // should be drawn when node is crossed
-
- int dlightframe;
- int dlightbits;
-
- mplane_t *plane;
- int flags;
-
- int firstedge; // look up in model->surfedges[], negative numbers
- int numedges; // are backwards edges
-
-// surface generation data
- struct surfcache_s *cachespots[MIPLEVELS];
-
- short texturemins[2];
- short extents[2];
-
- mtexinfo_t *texinfo;
-
-// lighting info
- byte styles[MAXLIGHTMAPS];
- byte *samples; // [numstyles*surfsize]
-
- struct msurface_s *nextalphasurface;
-} msurface_t;
-
-
-#define CONTENTS_NODE -1
-typedef struct mnode_s
-{
-// common with leaf
- int contents; // CONTENTS_NODE, to differentiate from leafs
- int visframe; // node needs to be traversed if current
-
- short minmaxs[6]; // for bounding box culling
-
- struct mnode_s *parent;
-
-// node specific
- mplane_t *plane;
- struct mnode_s *children[2];
-
- unsigned short firstsurface;
- unsigned short numsurfaces;
-} mnode_t;
-
-
-
-typedef struct mleaf_s
-{
-// common with node
- int contents; // wil be something other than CONTENTS_NODE
- int visframe; // node needs to be traversed if current
-
- short minmaxs[6]; // for bounding box culling
-
- struct mnode_s *parent;
-
-// leaf specific
- int cluster;
- int area;
-
- msurface_t **firstmarksurface;
- int nummarksurfaces;
- int key; // BSP sequence number for leaf's contents
-} mleaf_t;
-
-
-//===================================================================
-
-//
-// Whole model
-//
-
-typedef enum {mod_bad, mod_brush, mod_sprite, mod_alias } modtype_t;
-
-typedef struct model_s
-{
- char name[MAX_QPATH];
-
- int registration_sequence;
-
- modtype_t type;
- int numframes;
-
- int flags;
-
-//
-// volume occupied by the model graphics
-//
- vec3_t mins, maxs;
-
-//
-// solid volume for clipping (sent from server)
-//
- qboolean clipbox;
- vec3_t clipmins, clipmaxs;
-
-//
-// brush model
-//
- int firstmodelsurface, nummodelsurfaces;
-
- int numsubmodels;
- dmodel_t *submodels;
-
- int numplanes;
- mplane_t *planes;
-
- int numleafs; // number of visible leafs, not counting 0
- mleaf_t *leafs;
-
- int numvertexes;
- mvertex_t *vertexes;
-
- int numedges;
- medge_t *edges;
-
- int numnodes;
- int firstnode;
- mnode_t *nodes;
-
- int numtexinfo;
- mtexinfo_t *texinfo;
-
- int numsurfaces;
- msurface_t *surfaces;
-
- int numsurfedges;
- int *surfedges;
-
- int nummarksurfaces;
- msurface_t **marksurfaces;
-
- dvis_t *vis;
-
- byte *lightdata;
-
- // for alias models and sprites
- image_t *skins[MAX_MD2SKINS];
- void *extradata;
- int extradatasize;
-} model_t;
-
-//============================================================================
-
-void Mod_Init (void);
-void Mod_ClearAll (void);
-model_t *Mod_ForName (char *name, qboolean crash);
-void *Mod_Extradata (model_t *mod); // handles caching
-void Mod_TouchModel (char *name);
-
-mleaf_t *Mod_PointInLeaf (float *p, model_t *model);
-byte *Mod_ClusterPVS (int cluster, model_t *model);
-
-void Mod_Modellist_f (void);
-void Mod_FreeAll (void);
-void Mod_Free (model_t *mod);
-
-extern int registration_sequence;
-
-/* end r_model.h */
-
-
-#define CACHE_SIZE 32
-
-/*
-====================================================
-
- CONSTANTS
-
-====================================================
-*/
-
-#define VID_CBITS 6
-#define VID_GRADES (1 << VID_CBITS)
-
-
-// r_shared.h: general refresh-related stuff shared between the refresh and the
-// driver
-
-
-#define MAXVERTS 64 // max points in a surface polygon
-#define MAXWORKINGVERTS (MAXVERTS+4) // max points in an intermediate
- // polygon (while processing)
-// !!! if this is changed, it must be changed in d_ifacea.h too !!!
-#define MAXHEIGHT 4096
-#define MAXWIDTH 4096
-
-#define INFINITE_DISTANCE 0x10000 // distance that's always guaranteed to
- // be farther away than anything in
- // the scene
-
-
-// d_iface.h: interface header file for rasterization driver modules
-
-#define WARP_WIDTH 320
-#define WARP_HEIGHT 240
-
-#define MAX_LBM_HEIGHT 480
-
-
-#define PARTICLE_Z_CLIP 8.0
-
-// !!! must be kept the same as in quakeasm.h !!!
-#define TRANSPARENT_COLOR 0xFF
-
-
-// !!! if this is changed, it must be changed in d_ifacea.h too !!!
-#define TURB_TEX_SIZE 64 // base turbulent texture size
-
-// !!! if this is changed, it must be changed in d_ifacea.h too !!!
-#define CYCLE 128 // turbulent cycle size
-
-#define SCANBUFFERPAD 0x1000
-
-#define DS_SPAN_LIST_END -128
-
-#define NUMSTACKEDGES 2000
-#define MINEDGES NUMSTACKEDGES
-#define NUMSTACKSURFACES 1000
-#define MINSURFACES NUMSTACKSURFACES
-#define MAXSPANS 3000
-
-// flags in finalvert_t.flags
-#define ALIAS_LEFT_CLIP 0x0001
-#define ALIAS_TOP_CLIP 0x0002
-#define ALIAS_RIGHT_CLIP 0x0004
-#define ALIAS_BOTTOM_CLIP 0x0008
-#define ALIAS_Z_CLIP 0x0010
-#define ALIAS_XY_CLIP_MASK 0x000F
-
-#define SURFCACHE_SIZE_AT_320X240 1024*768
-
-#define BMODEL_FULLY_CLIPPED 0x10 // value returned by R_BmodelCheckBBox ()
- // if bbox is trivially rejected
-
-#define XCENTERING (1.0 / 2.0)
-#define YCENTERING (1.0 / 2.0)
-
-#define CLIP_EPSILON 0.001
-
-#define BACKFACE_EPSILON 0.01
-
-// !!! if this is changed, it must be changed in asm_draw.h too !!!
-#define NEAR_CLIP 0.01
-
-
-#define MAXALIASVERTS 2000 // TODO: tune this
-#define ALIAS_Z_CLIP_PLANE 4
-
-// turbulence stuff
-
-#define AMP 8*0x10000
-#define AMP2 3
-#define SPEED 20
-
-
-/*
-====================================================
-
-TYPES
-
-====================================================
-*/
-
-typedef struct
-{
- float u, v;
- float s, t;
- float zi;
-} emitpoint_t;
-
-/*
-** if you change this structure be sure to change the #defines
-** listed after it!
-*/
-//#define SMALL_FINALVERT
-
-#ifdef SMALL_FINALVERT
-
-typedef struct finalvert_s {
- short u, v, s, t;
- int l;
- int zi;
- int flags;
- float xyz[3]; // eye space
-} finalvert_t;
-
-#define FINALVERT_V0 0
-#define FINALVERT_V1 2
-#define FINALVERT_V2 4
-#define FINALVERT_V3 6
-#define FINALVERT_V4 8
-#define FINALVERT_V5 12
-#define FINALVERT_FLAGS 16
-#define FINALVERT_X 20
-#define FINALVERT_Y 24
-#define FINALVERT_Z 28
-#define FINALVERT_SIZE 32
-
-#else
-
-typedef struct finalvert_s {
- int u, v, s, t;
- int l;
- int zi;
- int flags;
- float xyz[3]; // eye space
-} finalvert_t;
-
-#define FINALVERT_V0 0
-#define FINALVERT_V1 4
-#define FINALVERT_V2 8
-#define FINALVERT_V3 12
-#define FINALVERT_V4 16
-#define FINALVERT_V5 20
-#define FINALVERT_FLAGS 24
-#define FINALVERT_X 28
-#define FINALVERT_Y 32
-#define FINALVERT_Z 36
-#define FINALVERT_SIZE 40
-
-#endif
-
-typedef struct
-{
- void *pskin;
- int pskindesc;
- int skinwidth;
- int skinheight;
- dtriangle_t *ptriangles;
- finalvert_t *pfinalverts;
- int numtriangles;
- int drawtype;
- int seamfixupX16;
- qboolean do_vis_thresh;
- int vis_thresh;
-} affinetridesc_t;
-
-typedef struct
-{
- byte *surfdat; // destination for generated surface
- int rowbytes; // destination logical width in bytes
- msurface_t *surf; // description for surface to generate
- fixed8_t lightadj[MAXLIGHTMAPS];
- // adjust for lightmap levels for dynamic lighting
- image_t *image;
- int surfmip; // mipmapped ratio of surface texels / world pixels
- int surfwidth; // in mipmapped texels
- int surfheight; // in mipmapped texels
-} drawsurf_t;
-
-
-
-typedef struct {
- int ambientlight;
- int shadelight;
- float *plightvec;
-} alight_t;
-
-// clipped bmodel edges
-
-typedef struct bedge_s
-{
- mvertex_t *v[2];
- struct bedge_s *pnext;
-} bedge_t;
-
-
-// !!! if this is changed, it must be changed in asm_draw.h too !!!
-typedef struct clipplane_s
-{
- vec3_t normal;
- float dist;
- struct clipplane_s *next;
- byte leftedge;
- byte rightedge;
- byte reserved[2];
-} clipplane_t;
-
-
-typedef struct surfcache_s
-{
- struct surfcache_s *next;
- struct surfcache_s **owner; // NULL is an empty chunk of memory
- int lightadj[MAXLIGHTMAPS]; // checked for strobe flush
- int dlight;
- int size; // including header
- unsigned width;
- unsigned height; // DEBUG only needed for debug
- float mipscale;
- image_t *image;
- byte data[4]; // width*height elements
-} surfcache_t;
-
-// !!! if this is changed, it must be changed in asm_draw.h too !!!
-typedef struct espan_s
-{
- int u, v, count;
- struct espan_s *pnext;
-} espan_t;
-
-// used by the polygon drawer (R_POLY.C) and sprite setup code (R_SPRITE.C)
-typedef struct
-{
- int nump;
- emitpoint_t *pverts;
- byte *pixels; // image
- int pixel_width; // image width
- int pixel_height; // image height
- vec3_t vup, vright, vpn; // in worldspace, for plane eq
- float dist;
- float s_offset, t_offset;
- float viewer_position[3];
- void (*drawspanlet)( void );
- int stipple_parity;
-} polydesc_t;
-
-// FIXME: compress, make a union if that will help
-// insubmodel is only 1, flags is fewer than 32, spanstate could be a byte
-typedef struct surf_s
-{
- struct surf_s *next; // active surface stack in r_edge.c
- struct surf_s *prev; // used in r_edge.c for active surf stack
- struct espan_s *spans; // pointer to linked list of spans to draw
- int key; // sorting key (BSP order)
- int last_u; // set during tracing
- int spanstate; // 0 = not in span
- // 1 = in span
- // -1 = in inverted span (end before
- // start)
- int flags; // currentface flags
- msurface_t *msurf;
- entity_t *entity;
- float nearzi; // nearest 1/z on surface, for mipmapping
- qboolean insubmodel;
- float d_ziorigin, d_zistepu, d_zistepv;
-
- int pad[2]; // to 64 bytes
-} surf_t;
-
-// !!! if this is changed, it must be changed in asm_draw.h too !!!
-typedef struct edge_s
-{
- fixed16_t u;
- fixed16_t u_step;
- struct edge_s *prev, *next;
- unsigned short surfs[2];
- struct edge_s *nextremove;
- float nearzi;
- medge_t *owner;
-} edge_t;
-
-
-/*
-====================================================
-
-VARS
-
-====================================================
-*/
-
-extern int d_spanpixcount;
-extern int r_framecount; // sequence # of current frame since Quake
- // started
-extern float r_aliasuvscale; // scale-up factor for screen u and v
- // on Alias vertices passed to driver
-extern qboolean r_dowarp;
-
-extern affinetridesc_t r_affinetridesc;
-
-extern vec3_t r_pright, r_pup, r_ppn;
-
-void D_DrawSurfaces (void);
-void R_DrawParticle( void );
-void D_ViewChanged (void);
-void D_WarpScreen (void);
-void R_PolysetUpdateTables (void);
-
-extern void *acolormap; // FIXME: should go away
-
-//=======================================================================//
-
-// callbacks to Quake
-
-extern drawsurf_t r_drawsurf;
-
-void R_DrawSurface (void);
-
-extern int c_surf;
-
-extern byte r_warpbuffer[WARP_WIDTH * WARP_HEIGHT];
-
-
-
-
-extern float scale_for_mip;
-
-extern qboolean d_roverwrapped;
-extern surfcache_t *sc_rover;
-extern surfcache_t *d_initial_rover;
-
-extern float d_sdivzstepu, d_tdivzstepu, d_zistepu;
-extern float d_sdivzstepv, d_tdivzstepv, d_zistepv;
-extern float d_sdivzorigin, d_tdivzorigin, d_ziorigin;
-
-extern fixed16_t sadjust, tadjust;
-extern fixed16_t bbextents, bbextentt;
-
-
-void D_DrawSpans16 (espan_t *pspans);
-void D_DrawZSpans (espan_t *pspans);
-void Turbulent8 (espan_t *pspan);
-void NonTurbulent8 (espan_t *pspan); //PGM
-
-surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel);
-
-extern int d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle;
-
-extern int d_pix_min, d_pix_max, d_pix_shift;
-
-extern pixel_t *d_viewbuffer;
-extern short *d_pzbuffer;
-extern unsigned int d_zrowbytes, d_zwidth;
-extern short *zspantable[MAXHEIGHT];
-extern int d_scantable[MAXHEIGHT];
-
-extern int d_minmip;
-extern float d_scalemip[3];
-
-//===================================================================
-
-extern int cachewidth;
-extern pixel_t *cacheblock;
-extern int r_screenwidth;
-
-extern int r_drawnpolycount;
-
-extern int sintable[1280];
-extern int intsintable[1280];
-extern int blanktable[1280]; // PGM
-
-extern vec3_t vup, base_vup;
-extern vec3_t vpn, base_vpn;
-extern vec3_t vright, base_vright;
-
-extern surf_t *surfaces, *surface_p, *surf_max;
-
-// surfaces are generated in back to front order by the bsp, so if a surf
-// pointer is greater than another one, it should be drawn in front
-// surfaces[1] is the background, and is used as the active surface stack.
-// surfaces[0] is a dummy, because index 0 is used to indicate no surface
-// attached to an edge_t
-
-//===================================================================
-
-extern vec3_t sxformaxis[4]; // s axis transformed into viewspace
-extern vec3_t txformaxis[4]; // t axis transformed into viewspac
-
-extern float xcenter, ycenter;
-extern float xscale, yscale;
-extern float xscaleinv, yscaleinv;
-extern float xscaleshrink, yscaleshrink;
-
-extern void TransformVector (vec3_t in, vec3_t out);
-extern void SetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv,
- fixed8_t endvertu, fixed8_t endvertv);
-
-extern int ubasestep, errorterm, erroradjustup, erroradjustdown;
-
-//===========================================================================
-
-extern cvar_t *sw_aliasstats;
-extern cvar_t *sw_clearcolor;
-extern cvar_t *sw_drawflat;
-extern cvar_t *sw_draworder;
-extern cvar_t *sw_maxedges;
-extern cvar_t *sw_maxsurfs;
-extern cvar_t *sw_mipcap;
-extern cvar_t *sw_mipscale;
-extern cvar_t *sw_mode;
-extern cvar_t *sw_reportsurfout;
-extern cvar_t *sw_reportedgeout;
-extern cvar_t *sw_stipplealpha;
-extern cvar_t *sw_surfcacheoverride;
-extern cvar_t *sw_waterwarp;
-
-extern cvar_t *r_fullbright;
-extern cvar_t *r_lefthand;
-extern cvar_t *r_drawentities;
-extern cvar_t *r_drawworld;
-extern cvar_t *r_dspeeds;
-extern cvar_t *r_lerpmodels;
-
-extern cvar_t *r_speeds;
-
-extern cvar_t *r_lightlevel; //FIXME HACK
-
-extern clipplane_t view_clipplanes[4];
-extern int *pfrustum_indexes[4];
-
-
-//=============================================================================
-
-void R_RenderWorld (void);
-
-//=============================================================================
-
-extern mplane_t screenedge[4];
-
-extern vec3_t r_origin;
-
-extern entity_t r_worldentity;
-extern model_t *currentmodel;
-extern entity_t *currententity;
-extern vec3_t modelorg;
-extern vec3_t r_entorigin;
-
-extern float verticalFieldOfView;
-extern float xOrigin, yOrigin;
-
-extern int r_visframecount;
-
-extern msurface_t *r_alpha_surfaces;
-
-//=============================================================================
-
-void R_ClearPolyList (void);
-void R_DrawPolyList (void);
-
-//
-// current entity info
-//
-extern qboolean insubmodel;
-
-void R_DrawAlphaSurfaces( void );
-
-void R_DrawSprite (void);
-void R_DrawBeam( entity_t *e );
-
-void R_RenderFace (msurface_t *fa, int clipflags);
-void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf);
-void R_TransformPlane (mplane_t *p, float *normal, float *dist);
-void R_TransformFrustum (void);
-void R_DrawSurfaceBlock16 (void);
-void R_DrawSurfaceBlock8 (void);
-
-void R_GenSkyTile (void *pdest);
-void R_GenSkyTile16 (void *pdest);
-void R_Surf8Patch (void);
-void R_Surf16Patch (void);
-void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags, mnode_t *topnode);
-void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel, mnode_t *topnode);
-
-void R_AddPolygonEdges (emitpoint_t *pverts, int numverts, int miplevel);
-surf_t *R_GetSurf (void);
-void R_AliasDrawModel (void);
-void R_BeginEdgeFrame (void);
-void R_ScanEdges (void);
-void D_DrawSurfaces (void);
-void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist);
-void R_StepActiveU (edge_t *pedge);
-void R_RemoveEdges (edge_t *pedge);
-void R_PushDlights (model_t *model);
-
-extern void R_Surf8Start (void);
-extern void R_Surf8End (void);
-extern void R_Surf16Start (void);
-extern void R_Surf16End (void);
-extern void R_EdgeCodeStart (void);
-extern void R_EdgeCodeEnd (void);
-
-extern void R_RotateBmodel (void);
-
-extern int c_faceclip;
-extern int r_polycount;
-extern int r_wholepolycount;
-
-extern int ubasestep, errorterm, erroradjustup, erroradjustdown;
-
-extern fixed16_t sadjust, tadjust;
-extern fixed16_t bbextents, bbextentt;
-
-extern mvertex_t *r_ptverts, *r_ptvertsmax;
-
-extern float entity_rotation[3][3];
-
-extern int r_currentkey;
-extern int r_currentbkey;
-
-void R_InitTurb (void);
-
-void R_DrawParticles (void);
-void R_SurfacePatch (void);
-
-extern int r_amodels_drawn;
-extern edge_t *auxedges;
-extern int r_numallocatededges;
-extern edge_t *r_edges, *edge_p, *edge_max;
-
-extern edge_t *newedges[MAXHEIGHT];
-extern edge_t *removeedges[MAXHEIGHT];
-
-// FIXME: make stack vars when debugging done
-extern edge_t edge_head;
-extern edge_t edge_tail;
-extern edge_t edge_aftertail;
-
-extern int r_aliasblendcolor;
-
-extern float aliasxscale, aliasyscale, aliasxcenter, aliasycenter;
-
-extern int r_outofsurfaces;
-extern int r_outofedges;
-
-extern mvertex_t *r_pcurrentvertbase;
-extern int r_maxvalidedgeoffset;
-
-typedef struct
-{
- finalvert_t *a, *b, *c;
-} aliastriangleparms_t;
-
-extern aliastriangleparms_t aliastriangleparms;
-
-void R_DrawTriangle( void );
-//void R_DrawTriangle (finalvert_t *index0, finalvert_t *index1, finalvert_t *index2);
-void R_AliasClipTriangle (finalvert_t *index0, finalvert_t *index1, finalvert_t *index2);
-
-
-extern float r_time1;
-extern float da_time1, da_time2;
-extern float dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;
-extern float se_time1, se_time2, de_time1, de_time2, dv_time1, dv_time2;
-extern int r_frustum_indexes[4*6];
-extern int r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs;
-extern qboolean r_surfsonstack;
-
-extern mleaf_t *r_viewleaf;
-extern int r_viewcluster, r_oldviewcluster;
-
-extern int r_clipflags;
-extern int r_dlightframecount;
-extern qboolean r_fov_greater_than_90;
-
-extern image_t *r_notexture_mip;
-extern model_t *r_worldmodel;
-
-void R_PrintAliasStats (void);
-void R_PrintTimes (void);
-void R_PrintDSpeeds (void);
-void R_AnimateLight (void);
-void R_LightPoint (vec3_t p, vec3_t color);
-void R_SetupFrame (void);
-void R_cshift_f (void);
-void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1);
-void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip);
-void R_SplitEntityOnNode2 (mnode_t *node);
-
-extern refdef_t r_newrefdef;
-
-extern surfcache_t *sc_rover, *sc_base;
-
-extern void *colormap;
-
-//====================================================================
-
-float R_DLightPoint (vec3_t p);
-
-void R_NewMap (void);
-void R_Register (void);
-void R_UnRegister (void);
-void Draw_InitLocal (void);
-qboolean R_Init( void *hInstance, void *wndProc );
-void R_Shutdown (void);
-void R_InitCaches (void);
-void D_FlushCaches (void);
-
-void R_ScreenShot_f( void );
-void R_BeginRegistration (char *map);
-struct model_s *R_RegisterModel (char *name);
-void R_EndRegistration (void);
-
-void R_RenderFrame (refdef_t *fd);
-
-struct image_s *Draw_FindPic (char *name);
-
-void Draw_GetPicSize (int *w, int *h, char *name);
-void Draw_Pic (int x, int y, char *name);
-void Draw_StretchPic (int x, int y, int w, int h, char *name);
-void Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data);
-void Draw_Char (int x, int y, int c);
-void Draw_TileClear (int x, int y, int w, int h, char *name);
-void Draw_Fill (int x, int y, int w, int h, int c);
-void Draw_FadeScreen (void);
-
-void Draw_GetPalette (void);
-
-void R_BeginFrame( float camera_separation );
-
-void R_CinematicSetPalette( const unsigned char *palette );
-
-extern unsigned d_8to24table[256]; // base
-
-void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length);
-void Sys_SetFPCW (void);
-
-void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height);
-
-void R_InitImages (void);
-void R_ShutdownImages (void);
-image_t *R_FindImage (char *name, imagetype_t type);
-void R_FreeUnusedImages (void);
-
-void R_GammaCorrectAndSetPalette( const unsigned char *pal );
-
-extern mtexinfo_t *sky_texinfo[6];
-
-void R_InitSkyBox (void);
-
-typedef struct swstate_s
-{
- qboolean fullscreen;
- int prev_mode; // last valid SW mode
-
- byte gammatable[256];
- byte currentpalette[1024];
-
-} swstate_t;
-
-void R_IMFlatShadedQuad( vec3_t a, vec3_t b, vec3_t c, vec3_t d, int color, float alpha );
-
-extern swstate_t sw_state;
-
-/*
-====================================================================
-
-IMPORTED FUNCTIONS
-
-====================================================================
-*/
-
-extern refimport_t ri;
-
-/*
-====================================================================
-
-IMPLEMENTATION FUNCTIONS
-
-====================================================================
-*/
-
-void SWimp_BeginFrame( float camera_separation );
-void SWimp_EndFrame (void);
-int SWimp_Init( void *hInstance, void *wndProc );
-void SWimp_SetPalette( const unsigned char *palette);
-void SWimp_Shutdown( void );
-rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen );
-void SWimp_AppActivate( qboolean active );
--- a/ref/r_main.c
+++ /dev/null
@@ -1,1355 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-viddef_t vid;
-refimport_t ri;
-
-unsigned d_8to24table[256];
-
-entity_t r_worldentity;
-
-char skyname[MAX_QPATH];
-float skyrotate;
-vec3_t skyaxis;
-image_t *sky_images[6];
-
-refdef_t r_newrefdef;
-model_t *currentmodel;
-
-model_t *r_worldmodel;
-
-byte r_warpbuffer[WARP_WIDTH * WARP_HEIGHT];
-
-swstate_t sw_state;
-
-void *colormap;
-vec3_t viewlightvec;
-alight_t r_viewlighting = {128, 192, viewlightvec};
-float r_time1;
-int r_numallocatededges;
-float r_aliasuvscale = 1.0;
-int r_outofsurfaces;
-int r_outofedges;
-
-qboolean r_dowarp;
-
-mvertex_t *r_pcurrentvertbase;
-
-int c_surf;
-int r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs;
-qboolean r_surfsonstack;
-int r_clipflags;
-
-//
-// view origin
-//
-vec3_t vup, base_vup;
-vec3_t vpn, base_vpn;
-vec3_t vright, base_vright;
-vec3_t r_origin;
-
-//
-// screen size info
-//
-oldrefdef_t r_refdef;
-float xcenter, ycenter;
-float xscale, yscale;
-float xscaleinv, yscaleinv;
-float xscaleshrink, yscaleshrink;
-float aliasxscale, aliasyscale, aliasxcenter, aliasycenter;
-
-int r_screenwidth;
-
-float verticalFieldOfView;
-float xOrigin, yOrigin;
-
-mplane_t screenedge[4];
-
-//
-// refresh flags
-//
-int r_framecount = 1; // so frame counts initialized to 0 don't match
-int r_visframecount;
-int d_spanpixcount;
-int r_polycount;
-int r_drawnpolycount;
-int r_wholepolycount;
-
-int *pfrustum_indexes[4];
-int r_frustum_indexes[4*6];
-
-mleaf_t *r_viewleaf;
-int r_viewcluster, r_oldviewcluster;
-
-image_t *r_notexture_mip;
-
-float da_time1, da_time2, dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;
-float se_time1, se_time2, de_time1, de_time2;
-
-void R_MarkLeaves (void);
-
-cvar_t *r_lefthand;
-cvar_t *sw_aliasstats;
-cvar_t *sw_allow_modex;
-cvar_t *sw_clearcolor;
-cvar_t *sw_drawflat;
-cvar_t *sw_draworder;
-cvar_t *sw_maxedges;
-cvar_t *sw_maxsurfs;
-cvar_t *sw_mode;
-cvar_t *sw_reportedgeout;
-cvar_t *sw_reportsurfout;
-cvar_t *sw_stipplealpha;
-cvar_t *sw_surfcacheoverride;
-cvar_t *sw_waterwarp;
-
-cvar_t *r_drawworld;
-cvar_t *r_drawentities;
-cvar_t *r_dspeeds;
-cvar_t *r_fullbright;
-cvar_t *r_lerpmodels;
-cvar_t *r_novis;
-
-cvar_t *r_speeds;
-cvar_t *r_lightlevel; //FIXME HACK
-
-cvar_t *vid_fullscreen;
-cvar_t *vid_gamma;
-
-//PGM
-cvar_t *sw_lockpvs;
-//PGM
-
-#define STRINGER(x) "x"
-
-
-// r_vars.c
-
-// all global and static refresh variables are collected in a contiguous block
-// to avoid cache conflicts.
-
-//-------------------------------------------------------
-// global refresh variables
-//-------------------------------------------------------
-
-// FIXME: make into one big structure, like cl or sv
-// FIXME: do separately for refresh engine and driver
-
-
-// d_vars.c
-
-// all global and static refresh variables are collected in a contiguous block
-// to avoid cache conflicts.
-
-//-------------------------------------------------------
-// global refresh variables
-//-------------------------------------------------------
-
-// FIXME: make into one big structure, like cl or sv
-// FIXME: do separately for refresh engine and driver
-
-float d_sdivzstepu, d_tdivzstepu, d_zistepu;
-float d_sdivzstepv, d_tdivzstepv, d_zistepv;
-float d_sdivzorigin, d_tdivzorigin, d_ziorigin;
-
-fixed16_t sadjust, tadjust, bbextents, bbextentt;
-
-pixel_t *cacheblock;
-int cachewidth;
-pixel_t *d_viewbuffer;
-short *d_pzbuffer;
-unsigned int d_zrowbytes;
-unsigned int d_zwidth;
-
-
-byte r_notexture_buffer[1024];
-
-/*
-==================
-R_InitTextures
-==================
-*/
-void R_InitTextures (void)
-{
- int x,y, m;
- byte *dest;
-
-// create a simple checkerboard texture for the default
- r_notexture_mip = (image_t *)r_notexture_buffer;
-
- r_notexture_mip->width = r_notexture_mip->height = 16;
- r_notexture_mip->pixels[0] = &r_notexture_buffer[sizeof(image_t)];
- r_notexture_mip->pixels[1] = r_notexture_mip->pixels[0] + 16*16;
- r_notexture_mip->pixels[2] = r_notexture_mip->pixels[1] + 8*8;
- r_notexture_mip->pixels[3] = r_notexture_mip->pixels[2] + 4*4;
-
- for (m=0 ; m<4 ; m++)
- {
- dest = r_notexture_mip->pixels[m];
- for (y=0 ; y< (16>>m) ; y++)
- for (x=0 ; x< (16>>m) ; x++)
- {
- if ( (y< (8>>m) ) ^ (x< (8>>m) ) )
-
- *dest++ = 0;
- else
- *dest++ = 0xff;
- }
- }
-}
-
-
-/*
-================
-R_InitTurb
-================
-*/
-void R_InitTurb (void)
-{
- int i;
-
- for (i=0 ; i<1280 ; i++)
- {
- sintable[i] = AMP + sin(i*3.14159*2/CYCLE)*AMP;
- intsintable[i] = AMP2 + sin(i*3.14159*2/CYCLE)*AMP2; // AMP2, not 20
- blanktable[i] = 0; //PGM
- }
-}
-
-void R_ImageList_f( void );
-
-void R_Register (void)
-{
- sw_aliasstats = Cvar_Get("sw_polymodelstats", "0", 0);
- sw_allow_modex = Cvar_Get("sw_allow_modex", "1", CVAR_ARCHIVE);
- sw_clearcolor = Cvar_Get("sw_clearcolor", "2", 0);
- sw_drawflat = Cvar_Get("sw_drawflat", "0", 0);
- sw_draworder = Cvar_Get("sw_draworder", "0", 0);
- sw_maxedges = Cvar_Get("sw_maxedges", STRINGER(MAXSTACKSURFACES), 0);
- sw_maxsurfs = Cvar_Get("sw_maxsurfs", "0", 0);
- sw_mipcap = Cvar_Get("sw_mipcap", "0", 0);
- sw_mipscale = Cvar_Get("sw_mipscale", "1", 0);
- sw_reportedgeout = Cvar_Get("sw_reportedgeout", "0", 0);
- sw_reportsurfout = Cvar_Get("sw_reportsurfout", "0", 0);
- sw_stipplealpha = Cvar_Get("sw_stipplealpha", "0", CVAR_ARCHIVE);
- sw_surfcacheoverride = Cvar_Get("sw_surfcacheoverride", "0", 0);
- sw_waterwarp = Cvar_Get ("sw_waterwarp", "1", 0);
- sw_mode = Cvar_Get("sw_mode", "0", CVAR_ARCHIVE);
-
- r_lefthand = Cvar_Get("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE);
- r_speeds = Cvar_Get("r_speeds", "0", 0);
- r_fullbright = Cvar_Get("r_fullbright", "0", 0);
- r_drawentities = Cvar_Get("r_drawentities", "1", 0);
- r_drawworld = Cvar_Get("r_drawworld", "1", 0);
- r_dspeeds = Cvar_Get("r_dspeeds", "0", 0);
- r_lightlevel = Cvar_Get("r_lightlevel", "0", 0);
- r_lerpmodels = Cvar_Get("r_lerpmodels", "1", 0);
- r_novis = Cvar_Get("r_novis", "0", 0);
-
- vid_fullscreen = Cvar_Get("vid_fullscreen", "0", CVAR_ARCHIVE);
- vid_gamma = Cvar_Get("vid_gamma", "1", CVAR_ARCHIVE);
-
- Cmd_AddCommand("modellist", Mod_Modellist_f);
- Cmd_AddCommand("screenshot", R_ScreenShot_f);
- Cmd_AddCommand("imagelist", R_ImageList_f);
-
- sw_mode->modified = true; // force us to do mode specific stuff later
- vid_gamma->modified = true; // force us to rebuild the gamma table later
-
-//PGM
- sw_lockpvs = ri.Cvar_Get ("sw_lockpvs", "0", 0);
-//PGM
-}
-
-void
-R_UnRegister(void)
-{
- Cmd_RemoveCommand("screenshot");
- Cmd_RemoveCommand("modellist");
- Cmd_RemoveCommand("imagelist");
-}
-
-/*
-===============
-R_Init
-===============
-*/
-qboolean R_Init( void *hInstance, void *wndProc )
-{
- R_InitImages ();
- Mod_Init ();
- Draw_InitLocal ();
- R_InitTextures ();
-
- R_InitTurb ();
-
- view_clipplanes[0].leftedge = true;
- view_clipplanes[1].rightedge = true;
- view_clipplanes[1].leftedge = view_clipplanes[2].leftedge =
- view_clipplanes[3].leftedge = false;
- view_clipplanes[0].rightedge = view_clipplanes[2].rightedge =
- view_clipplanes[3].rightedge = false;
-
- r_refdef.xOrigin = XCENTERING;
- r_refdef.yOrigin = YCENTERING;
-
- r_aliasuvscale = 1.0;
-
- R_Register ();
- Draw_GetPalette ();
- SWimp_Init( hInstance, wndProc );
-
- // create the window
- R_BeginFrame( 0 );
-
- ri.Con_Printf (PRINT_ALL, "ref_soft version: "REF_VERSION"\n");
-
- return true;
-}
-
-void
-R_Shutdown(void)
-{
- if(d_pzbuffer){
- free(d_pzbuffer);
- d_pzbuffer = nil;
- }
- if(sc_base){
- D_FlushCaches();
- free(sc_base);
- sc_base = nil;
- }
- if(vid.colormap){
- free(vid.colormap);
- vid.colormap = nil;
- }
- R_UnRegister();
- Mod_FreeAll();
- R_ShutdownImages();
-
- SWimp_Shutdown();
-}
-
-/*
-===============
-R_NewMap
-===============
-*/
-void R_NewMap (void)
-{
- r_viewcluster = -1;
-
- r_cnumsurfs = sw_maxsurfs->value;
-
- if (r_cnumsurfs <= MINSURFACES)
- r_cnumsurfs = MINSURFACES;
-
- if (r_cnumsurfs > NUMSTACKSURFACES)
- {
- surfaces = malloc (r_cnumsurfs * sizeof(surf_t));
- surface_p = surfaces;
- surf_max = &surfaces[r_cnumsurfs];
- r_surfsonstack = false;
- // surface 0 doesn't really exist; it's just a dummy because index 0
- // is used to indicate no edge attached to surface
- surfaces--;
- R_SurfacePatch ();
- }
- else
- {
- r_surfsonstack = true;
- }
-
- r_maxedgesseen = 0;
- r_maxsurfsseen = 0;
-
- r_numallocatededges = sw_maxedges->value;
-
- if (r_numallocatededges < MINEDGES)
- r_numallocatededges = MINEDGES;
-
- if (r_numallocatededges <= NUMSTACKEDGES)
- {
- auxedges = NULL;
- }
- else
- {
- auxedges = malloc (r_numallocatededges * sizeof(edge_t));
- }
-}
-
-
-/*
-===============
-R_MarkLeaves
-
-Mark the leaves and nodes that are in the PVS for the current
-cluster
-===============
-*/
-void R_MarkLeaves (void)
-{
- byte *vis;
- mnode_t *node;
- int i;
- mleaf_t *leaf;
- int cluster;
-
- if (r_oldviewcluster == r_viewcluster && !r_novis->value && r_viewcluster != -1)
- return;
-
- // development aid to let you run around and see exactly where
- // the pvs ends
- if (sw_lockpvs->value)
- return;
-
- r_visframecount++;
- r_oldviewcluster = r_viewcluster;
-
- if (r_novis->value || r_viewcluster == -1 || !r_worldmodel->vis)
- {
- // mark everything
- for (i=0 ; i<r_worldmodel->numleafs ; i++)
- r_worldmodel->leafs[i].visframe = r_visframecount;
- for (i=0 ; i<r_worldmodel->numnodes ; i++)
- r_worldmodel->nodes[i].visframe = r_visframecount;
- return;
- }
-
- vis = Mod_ClusterPVS (r_viewcluster, r_worldmodel);
-
- for (i=0,leaf=r_worldmodel->leafs ; i<r_worldmodel->numleafs ; i++, leaf++)
- {
- cluster = leaf->cluster;
- if (cluster == -1)
- continue;
- if (vis[cluster>>3] & (1<<(cluster&7)))
- {
- node = (mnode_t *)leaf;
- do
- {
- if (node->visframe == r_visframecount)
- break;
- node->visframe = r_visframecount;
- node = node->parent;
- } while (node);
- }
- }
-
-/*
- for (i=0 ; i<r_worldmodel->vis->numclusters ; i++)
- {
- if (vis[i>>3] & (1<<(i&7)))
- {
- node = (mnode_t *)&r_worldmodel->leafs[i]; // FIXME: cluster
- do
- {
- if (node->visframe == r_visframecount)
- break;
- node->visframe = r_visframecount;
- node = node->parent;
- } while (node);
- }
- }
-*/
-}
-
-/*
-** R_DrawNullModel
-**
-** IMPLEMENT THIS!
-*/
-void R_DrawNullModel( void )
-{
-}
-
-/*
-=============
-R_DrawEntitiesOnList
-=============
-*/
-void R_DrawEntitiesOnList (void)
-{
- int i;
- qboolean translucent_entities = false;
-
- if (!r_drawentities->value)
- return;
-
- // all bmodels have already been drawn by the edge list
- for (i=0 ; i<r_newrefdef.num_entities ; i++)
- {
- currententity = &r_newrefdef.entities[i];
-
- if ( currententity->flags & RF_TRANSLUCENT )
- {
- translucent_entities = true;
- continue;
- }
-
- if ( currententity->flags & RF_BEAM )
- {
- modelorg[0] = -r_origin[0];
- modelorg[1] = -r_origin[1];
- modelorg[2] = -r_origin[2];
- VectorCopy( vec3_origin, r_entorigin );
- R_DrawBeam( currententity );
- }
- else
- {
- currentmodel = currententity->model;
- if (!currentmodel)
- {
- R_DrawNullModel();
- continue;
- }
- VectorCopy (currententity->origin, r_entorigin);
- VectorSubtract (r_origin, r_entorigin, modelorg);
-
- switch (currentmodel->type)
- {
- case mod_sprite:
- R_DrawSprite ();
- break;
-
- case mod_alias:
- R_AliasDrawModel ();
- break;
-
- default:
- break;
- }
- }
- }
-
- if ( !translucent_entities )
- return;
-
- for (i=0 ; i<r_newrefdef.num_entities ; i++)
- {
- currententity = &r_newrefdef.entities[i];
-
- if ( !( currententity->flags & RF_TRANSLUCENT ) )
- continue;
-
- if ( currententity->flags & RF_BEAM )
- {
- modelorg[0] = -r_origin[0];
- modelorg[1] = -r_origin[1];
- modelorg[2] = -r_origin[2];
- VectorCopy( vec3_origin, r_entorigin );
- R_DrawBeam( currententity );
- }
- else
- {
- currentmodel = currententity->model;
- if (!currentmodel)
- {
- R_DrawNullModel();
- continue;
- }
- VectorCopy (currententity->origin, r_entorigin);
- VectorSubtract (r_origin, r_entorigin, modelorg);
-
- switch (currentmodel->type)
- {
- case mod_sprite:
- R_DrawSprite ();
- break;
-
- case mod_alias:
- R_AliasDrawModel ();
- break;
-
- default:
- break;
- }
- }
- }
-}
-
-
-/*
-=============
-R_BmodelCheckBBox
-=============
-*/
-int R_BmodelCheckBBox (float *minmaxs)
-{
- int i, *pindex, clipflags;
- vec3_t acceptpt, rejectpt;
- float d;
-
- clipflags = 0;
-
- for (i=0 ; i<4 ; i++)
- {
- // generate accept and reject points
- // FIXME: do with fast look-ups or integer tests based on the sign bit
- // of the floating point values
-
- pindex = pfrustum_indexes[i];
-
- rejectpt[0] = minmaxs[pindex[0]];
- rejectpt[1] = minmaxs[pindex[1]];
- rejectpt[2] = minmaxs[pindex[2]];
-
- d = DotProduct (rejectpt, view_clipplanes[i].normal);
- d -= view_clipplanes[i].dist;
-
- if (d <= 0)
- return BMODEL_FULLY_CLIPPED;
-
- acceptpt[0] = minmaxs[pindex[3+0]];
- acceptpt[1] = minmaxs[pindex[3+1]];
- acceptpt[2] = minmaxs[pindex[3+2]];
-
- d = DotProduct (acceptpt, view_clipplanes[i].normal);
- d -= view_clipplanes[i].dist;
-
- if (d <= 0)
- clipflags |= (1<<i);
- }
-
- return clipflags;
-}
-
-
-/*
-===================
-R_FindTopnode
-
-Find the first node that splits the given box
-===================
-*/
-mnode_t *R_FindTopnode (vec3_t mins, vec3_t maxs)
-{
- mplane_t *splitplane;
- int sides;
- mnode_t *node;
-
- node = r_worldmodel->nodes;
-
- while (1)
- {
- if (node->visframe != r_visframecount)
- return NULL; // not visible at all
-
- if (node->contents != CONTENTS_NODE)
- {
- if (node->contents != CONTENTS_SOLID)
- return node; // we've reached a non-solid leaf, so it's
- // visible and not BSP clipped
- return NULL; // in solid, so not visible
- }
-
- splitplane = node->plane;
- sides = BOX_ON_PLANE_SIDE(mins, maxs, (cplane_t *)splitplane);
-
- if (sides == 3)
- return node; // this is the splitter
-
- // not split yet; recurse down the contacted side
- if (sides & 1)
- node = node->children[0];
- else
- node = node->children[1];
- }
-}
-
-
-/*
-=============
-RotatedBBox
-
-Returns an axially aligned box that contains the input box at the given rotation
-=============
-*/
-void RotatedBBox (vec3_t mins, vec3_t maxs, vec3_t angles, vec3_t tmins, vec3_t tmaxs)
-{
- vec3_t tmp, v;
- int i, j;
- vec3_t forward, right, up;
-
- if (!angles[0] && !angles[1] && !angles[2])
- {
- VectorCopy (mins, tmins);
- VectorCopy (maxs, tmaxs);
- return;
- }
-
- for (i=0 ; i<3 ; i++)
- {
- tmins[i] = 99999;
- tmaxs[i] = -99999;
- }
-
- AngleVectors (angles, forward, right, up);
-
- for ( i = 0; i < 8; i++ )
- {
- if ( i & 1 )
- tmp[0] = mins[0];
- else
- tmp[0] = maxs[0];
-
- if ( i & 2 )
- tmp[1] = mins[1];
- else
- tmp[1] = maxs[1];
-
- if ( i & 4 )
- tmp[2] = mins[2];
- else
- tmp[2] = maxs[2];
-
-
- VectorScale (forward, tmp[0], v);
- VectorMA (v, -tmp[1], right, v);
- VectorMA (v, tmp[2], up, v);
-
- for (j=0 ; j<3 ; j++)
- {
- if (v[j] < tmins[j])
- tmins[j] = v[j];
- if (v[j] > tmaxs[j])
- tmaxs[j] = v[j];
- }
- }
-}
-
-/*
-=============
-R_DrawBEntitiesOnList
-=============
-*/
-void R_DrawBEntitiesOnList (void)
-{
- int i, clipflags;
- vec3_t oldorigin;
- vec3_t mins, maxs;
- float minmaxs[6];
- mnode_t *topnode;
-
- if (!r_drawentities->value)
- return;
-
- VectorCopy (modelorg, oldorigin);
- insubmodel = true;
- r_dlightframecount = r_framecount;
-
- for (i=0 ; i<r_newrefdef.num_entities ; i++)
- {
- currententity = &r_newrefdef.entities[i];
- currentmodel = currententity->model;
- if (!currentmodel)
- continue;
- if (currentmodel->nummodelsurfaces == 0)
- continue; // clip brush only
- if ( currententity->flags & RF_BEAM )
- continue;
- if (currentmodel->type != mod_brush)
- continue;
- // see if the bounding box lets us trivially reject, also sets
- // trivial accept status
- RotatedBBox (currentmodel->mins, currentmodel->maxs,
- currententity->angles, mins, maxs);
- VectorAdd (mins, currententity->origin, minmaxs);
- VectorAdd (maxs, currententity->origin, (minmaxs+3));
-
- clipflags = R_BmodelCheckBBox (minmaxs);
- if (clipflags == BMODEL_FULLY_CLIPPED)
- continue; // off the edge of the screen
-
- topnode = R_FindTopnode (minmaxs, minmaxs+3);
- if (!topnode)
- continue; // no part in a visible leaf
-
- VectorCopy (currententity->origin, r_entorigin);
- VectorSubtract (r_origin, r_entorigin, modelorg);
-
- r_pcurrentvertbase = currentmodel->vertexes;
-
- // FIXME: stop transforming twice
- R_RotateBmodel ();
-
- // calculate dynamic lighting for bmodel
- R_PushDlights (currentmodel);
-
- if (topnode->contents == CONTENTS_NODE)
- {
- // not a leaf; has to be clipped to the world BSP
- r_clipflags = clipflags;
- R_DrawSolidClippedSubmodelPolygons (currentmodel, topnode);
- }
- else
- {
- // falls entirely in one leaf, so we just put all the
- // edges in the edge list and let 1/z sorting handle
- // drawing order
- R_DrawSubmodelPolygons (currentmodel, clipflags, topnode);
- }
-
- // put back world rotation and frustum clipping
- // FIXME: R_RotateBmodel should just work off base_vxx
- VectorCopy (base_vpn, vpn);
- VectorCopy (base_vup, vup);
- VectorCopy (base_vright, vright);
- VectorCopy (oldorigin, modelorg);
- R_TransformFrustum ();
- }
-
- insubmodel = false;
-}
-
-
-/*
-================
-R_EdgeDrawing
-================
-*/
-void R_EdgeDrawing (void)
-{
- edge_t ledges[NUMSTACKEDGES +
- ((CACHE_SIZE - 1) / sizeof(edge_t)) + 1];
- surf_t lsurfs[NUMSTACKSURFACES +
- ((CACHE_SIZE - 1) / sizeof(surf_t)) + 1];
-
- if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
- return;
-
- if (auxedges)
- {
- r_edges = auxedges;
- }
- else
- {
- r_edges = (edge_t *)
- (((uintptr)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
- }
-
- if (r_surfsonstack)
- {
- surfaces = (surf_t *)
- (((uintptr)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
- surf_max = &surfaces[r_cnumsurfs];
- // surface 0 doesn't really exist; it's just a dummy because index 0
- // is used to indicate no edge attached to surface
- surfaces--;
- R_SurfacePatch ();
- }
-
- R_BeginEdgeFrame ();
-
- if (r_dspeeds->value)
- {
- rw_time1 = Sys_Milliseconds ();
- }
-
- R_RenderWorld ();
-
- if (r_dspeeds->value)
- {
- rw_time2 = Sys_Milliseconds ();
- db_time1 = rw_time2;
- }
-
- R_DrawBEntitiesOnList ();
-
- if (r_dspeeds->value)
- {
- db_time2 = Sys_Milliseconds ();
- se_time1 = db_time2;
- }
-
- R_ScanEdges ();
-}
-
-//=======================================================================
-
-
-/*
-=============
-R_CalcPalette
-
-=============
-*/
-void R_CalcPalette (void)
-{
- static qboolean modified;
- byte palette[256][4], *in, *out;
- int i, j;
- float alpha, one_minus_alpha;
- vec3_t premult;
- int v;
-
- alpha = r_newrefdef.blend[3];
- if (alpha <= 0)
- {
- if (modified)
- { // set back to default
- modified = false;
- R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
- return;
- }
- return;
- }
-
- modified = true;
- if (alpha > 1)
- alpha = 1;
-
- premult[0] = r_newrefdef.blend[0]*alpha*255;
- premult[1] = r_newrefdef.blend[1]*alpha*255;
- premult[2] = r_newrefdef.blend[2]*alpha*255;
-
- one_minus_alpha = (1.0 - alpha);
-
- in = (byte *)d_8to24table;
- out = palette[0];
- for (i=0 ; i<256 ; i++, in+=4, out+=4)
- {
- for (j=0 ; j<3 ; j++)
- {
- v = premult[j] + one_minus_alpha * in[j];
- if (v > 255)
- v = 255;
- out[j] = v;
- }
- out[3] = 255;
- }
-
- R_GammaCorrectAndSetPalette( ( const unsigned char * ) palette[0] );
-// SWimp_SetPalette( palette[0] );
-}
-
-//=======================================================================
-
-void R_SetLightLevel (void)
-{
- vec3_t light;
-
- if ((r_newrefdef.rdflags & RDF_NOWORLDMODEL) || (!r_drawentities->value) || (!currententity))
- {
- r_lightlevel->value = 150.0;
- return;
- }
-
- // save off light value for server to look at (BIG HACK!)
- R_LightPoint (r_newrefdef.vieworg, light);
- r_lightlevel->value = 150.0 * light[0];
-}
-
-
-/*
-@@@@@@@@@@@@@@@@
-R_RenderFrame
-
-@@@@@@@@@@@@@@@@
-*/
-void R_RenderFrame (refdef_t *fd)
-{
- r_newrefdef = *fd;
-
- if (!r_worldmodel && !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) )
- ri.Sys_Error (ERR_FATAL,"R_RenderView: NULL worldmodel");
-
- VectorCopy (fd->vieworg, r_refdef.vieworg);
- VectorCopy (fd->viewangles, r_refdef.viewangles);
-
- if (r_speeds->value || r_dspeeds->value)
- r_time1 = Sys_Milliseconds ();
-
- R_SetupFrame ();
-
- R_MarkLeaves (); // done here so we know if we're in water
-
- R_PushDlights (r_worldmodel);
-
- R_EdgeDrawing ();
-
- if (r_dspeeds->value)
- {
- se_time2 = Sys_Milliseconds ();
- de_time1 = se_time2;
- }
-
- R_DrawEntitiesOnList ();
-
- if (r_dspeeds->value)
- {
- de_time2 = Sys_Milliseconds ();
- dp_time1 = Sys_Milliseconds ();
- }
-
- R_DrawParticles ();
-
- if (r_dspeeds->value)
- dp_time2 = Sys_Milliseconds ();
-
- R_DrawAlphaSurfaces();
-
- R_SetLightLevel ();
-
- if (r_dowarp)
- D_WarpScreen ();
-
- if (r_dspeeds->value)
- da_time1 = Sys_Milliseconds ();
-
- if (r_dspeeds->value)
- da_time2 = Sys_Milliseconds ();
-
- R_CalcPalette ();
-
- if (sw_aliasstats->value)
- R_PrintAliasStats ();
-
- if (r_speeds->value)
- R_PrintTimes ();
-
- if (r_dspeeds->value)
- R_PrintDSpeeds ();
-
- if (sw_reportsurfout->value && r_outofsurfaces)
- ri.Con_Printf (PRINT_ALL,"Short %d surfaces\n", r_outofsurfaces);
-
- if (sw_reportedgeout->value && r_outofedges)
- ri.Con_Printf (PRINT_ALL,"Short roughly %d edges\n", r_outofedges * 2 / 3);
-}
-
-/*
-** R_InitGraphics
-*/
-void R_InitGraphics( int width, int height )
-{
- vid.width = width;
- vid.height = height;
-
- // free z buffer
- if ( d_pzbuffer )
- {
- free( d_pzbuffer );
- d_pzbuffer = NULL;
- }
-
- // free surface cache
- if ( sc_base )
- {
- D_FlushCaches ();
- free( sc_base );
- sc_base = NULL;
- }
-
- d_pzbuffer = malloc(vid.width*vid.height*2);
-
- R_InitCaches ();
-
- R_GammaCorrectAndSetPalette( ( const unsigned char *) d_8to24table );
-}
-
-/*
-** R_BeginFrame
-*/
-void R_BeginFrame( float /*camera_separation*/ )
-{
- extern void Draw_BuildGammaTable( void );
-
- /*
- ** rebuild the gamma correction palette if necessary
- */
- if ( vid_gamma->modified )
- {
- Draw_BuildGammaTable();
- R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
-
- vid_gamma->modified = false;
- }
-
- while ( sw_mode->modified || vid_fullscreen->modified )
- {
- rserr_t err;
-
- /*
- ** if this returns rserr_invalid_fullscreen then it set the mode but not as a
- ** fullscreen mode, e.g. 320x200 on a system that doesn't support that res
- */
- if ( ( err = SWimp_SetMode( &vid.width, &vid.height, sw_mode->value, vid_fullscreen->value ) ) == rserr_ok )
- {
- R_InitGraphics( vid.width, vid.height );
-
- sw_state.prev_mode = sw_mode->value;
- vid_fullscreen->modified = false;
- sw_mode->modified = false;
- }
- else
- {
- if ( err == rserr_invalid_mode )
- {
- ri.Cvar_SetValue( "sw_mode", sw_state.prev_mode );
- ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - could not set mode\n" );
- }
- else if ( err == rserr_invalid_fullscreen )
- {
- R_InitGraphics( vid.width, vid.height );
-
- ri.Cvar_SetValue( "vid_fullscreen", 0);
- ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - fullscreen unavailable in this mode\n" );
- sw_state.prev_mode = sw_mode->value;
-// vid_fullscreen->modified = false;
-// sw_mode->modified = false;
- }
- else
- {
- ri.Sys_Error( ERR_FATAL, "ref_soft::R_BeginFrame() - catastrophic mode change failure\n" );
- }
- }
- }
-}
-
-/*
-** R_GammaCorrectAndSetPalette
-*/
-void R_GammaCorrectAndSetPalette( const unsigned char *palette )
-{
- int i;
-
- for ( i = 0; i < 256; i++ )
- {
- sw_state.currentpalette[i*4+0] = sw_state.gammatable[palette[i*4+0]];
- sw_state.currentpalette[i*4+1] = sw_state.gammatable[palette[i*4+1]];
- sw_state.currentpalette[i*4+2] = sw_state.gammatable[palette[i*4+2]];
- }
-
- SWimp_SetPalette( sw_state.currentpalette );
-}
-
-/*
-** R_CinematicSetPalette
-*/
-void R_CinematicSetPalette( const unsigned char *palette )
-{
- byte palette32[1024];
- int i, j, w;
- int *d;
-
- // clear screen to black to avoid any palette flash
- w = abs(vid.rowbytes)>>2; // stupid negative pitch win32 stuff...
- for (i=0 ; i<vid.height ; i++)
- {
- d = (int *)(vid.buffer + i*vid.rowbytes);
- for (j=0 ; j<w ; j++)
- d[j] = 0;
- }
- // flush it to the screen
- SWimp_EndFrame ();
-
- if ( palette )
- {
- for ( i = 0; i < 256; i++ )
- {
- palette32[i*4+0] = palette[i*3+0];
- palette32[i*4+1] = palette[i*3+1];
- palette32[i*4+2] = palette[i*3+2];
- palette32[i*4+3] = 0xFF;
- }
-
- R_GammaCorrectAndSetPalette( palette32 );
- }
- else
- {
- R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
- }
-}
-
-/*
-================
-Draw_BuildGammaTable
-================
-*/
-void Draw_BuildGammaTable (void)
-{
- int i, inf;
- float g;
-
- g = vid_gamma->value;
-
- if (g == 1.0)
- {
- for (i=0 ; i<256 ; i++)
- sw_state.gammatable[i] = i;
- return;
- }
-
- for (i=0 ; i<256 ; i++)
- {
- inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5;
- if (inf < 0)
- inf = 0;
- if (inf > 255)
- inf = 255;
- sw_state.gammatable[i] = inf;
- }
-}
-
-/*
-** R_DrawBeam
-*/
-void R_DrawBeam( entity_t *e )
-{
-#define NUM_BEAM_SEGS 6
-
- int i;
-
- vec3_t perpvec;
- vec3_t direction, normalized_direction;
- vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS];
- vec3_t oldorigin, origin;
-
- oldorigin[0] = e->oldorigin[0];
- oldorigin[1] = e->oldorigin[1];
- oldorigin[2] = e->oldorigin[2];
-
- origin[0] = e->origin[0];
- origin[1] = e->origin[1];
- origin[2] = e->origin[2];
-
- normalized_direction[0] = direction[0] = oldorigin[0] - origin[0];
- normalized_direction[1] = direction[1] = oldorigin[1] - origin[1];
- normalized_direction[2] = direction[2] = oldorigin[2] - origin[2];
-
- if ( VectorNormalize( normalized_direction ) == 0 )
- return;
-
- PerpendicularVector( perpvec, normalized_direction );
- VectorScale( perpvec, e->frame / 2, perpvec );
-
- for ( i = 0; i < NUM_BEAM_SEGS; i++ )
- {
- RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i );
- VectorAdd( start_points[i], origin, start_points[i] );
- VectorAdd( start_points[i], direction, end_points[i] );
- }
-
- for ( i = 0; i < NUM_BEAM_SEGS; i++ )
- {
- R_IMFlatShadedQuad( start_points[i],
- end_points[i],
- end_points[(i+1)%NUM_BEAM_SEGS],
- start_points[(i+1)%NUM_BEAM_SEGS],
- e->skinnum & 0xFF,
- e->alpha );
- }
-}
-
-
-//===================================================================
-
-/*
-============
-R_SetSky
-============
-*/
-// 3dstudio environment map names
-char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
-int r_skysideimage[6] = {5, 2, 4, 1, 0, 3};
-extern mtexinfo_t r_skytexinfo[6];
-void R_SetSky (char *name, float rotate, vec3_t axis)
-{
- int i;
- char pathname[MAX_QPATH];
-
- strncpy (skyname, name, sizeof(skyname)-1);
- skyrotate = rotate;
- VectorCopy (axis, skyaxis);
-
- for (i=0 ; i<6 ; i++)
- {
- Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[r_skysideimage[i]]);
- r_skytexinfo[i].image = R_FindImage (pathname, it_sky);
- }
-}
-
-
-/*
-===============
-Draw_GetPalette
-===============
-*/
-void Draw_GetPalette (void)
-{
- byte *pal, *out;
- int i;
- int r, g, b;
-
- // get the palette and colormap
- LoadPCX ("pics/colormap.pcx", &vid.colormap, &pal, NULL, NULL);
- if (!vid.colormap)
- ri.Sys_Error (ERR_FATAL, "Couldn't load pics/colormap.pcx");
- vid.alphamap = vid.colormap + 64*256;
-
- out = (byte *)d_8to24table;
- for (i=0 ; i<256 ; i++, out+=4)
- {
- r = pal[i*3+0];
- g = pal[i*3+1];
- b = pal[i*3+2];
-
- out[0] = r;
- out[1] = g;
- out[2] = b;
- }
-
- free (pal);
-}
-
-struct image_s *R_RegisterSkin (char *name);
-
-/*
-@@@@@@@@@@@@@@@@@@@@@
-GetRefAPI
-
-@@@@@@@@@@@@@@@@@@@@@
-*/
-refexport_t GetRefAPI (refimport_t rimp)
-{
- refexport_t re;
-
- ri = rimp;
-
- re.api_version = API_VERSION;
-
- re.BeginRegistration = R_BeginRegistration;
- re.RegisterModel = R_RegisterModel;
- re.RegisterSkin = R_RegisterSkin;
- re.RegisterPic = Draw_FindPic;
- re.SetSky = R_SetSky;
- re.EndRegistration = R_EndRegistration;
-
- re.RenderFrame = R_RenderFrame;
-
- re.DrawGetPicSize = Draw_GetPicSize;
- re.DrawPic = Draw_Pic;
- re.DrawStretchPic = Draw_StretchPic;
- re.DrawChar = Draw_Char;
- re.DrawTileClear = Draw_TileClear;
- re.DrawFill = Draw_Fill;
- re.DrawFadeScreen= Draw_FadeScreen;
-
- re.DrawStretchRaw = Draw_StretchRaw;
-
- re.Init = R_Init;
- re.Shutdown = R_Shutdown;
-
- re.CinematicSetPalette = R_CinematicSetPalette;
- re.BeginFrame = R_BeginFrame;
- re.EndFrame = SWimp_EndFrame;
-
- re.AppActivate = SWimp_AppActivate;
-
- Swap_Init ();
-
- return re;
-}
--- a/ref/r_misc.c
+++ /dev/null
@@ -1,566 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-#define NUM_MIPS 4
-
-cvar_t *sw_mipcap;
-cvar_t *sw_mipscale;
-
-surfcache_t *d_initial_rover;
-qboolean d_roverwrapped;
-int d_minmip;
-float d_scalemip[NUM_MIPS-1];
-
-static float basemip[NUM_MIPS-1] = {1.0, 0.5*0.8, 0.25*0.8};
-
-extern int d_aflatcolor;
-
-int d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle;
-
-int d_pix_min, d_pix_max, d_pix_shift;
-
-int d_scantable[MAXHEIGHT];
-short *zspantable[MAXHEIGHT];
-
-/*
-================
-D_Patch
-================
-*/
-void D_Patch (void)
-{
-}
-/*
-================
-D_ViewChanged
-================
-*/
-unsigned char *alias_colormap;
-
-void D_ViewChanged (void)
-{
- int i;
-
- scale_for_mip = xscale;
- if (yscale > xscale)
- scale_for_mip = yscale;
-
- d_zrowbytes = vid.width * 2;
- d_zwidth = vid.width;
-
- d_pix_min = r_refdef.vrect.width / 320;
- if (d_pix_min < 1)
- d_pix_min = 1;
-
- d_pix_max = (int)((float)r_refdef.vrect.width / (320.0 / 4.0) + 0.5);
- d_pix_shift = 8 - (int)((float)r_refdef.vrect.width / 320.0 + 0.5);
- if (d_pix_max < 1)
- d_pix_max = 1;
-
- d_vrectx = r_refdef.vrect.x;
- d_vrecty = r_refdef.vrect.y;
- d_vrectright_particle = r_refdef.vrectright - d_pix_max;
- d_vrectbottom_particle =
- r_refdef.vrectbottom - d_pix_max;
-
- for (i=0 ; i<vid.height; i++)
- {
- d_scantable[i] = i*r_screenwidth;
- zspantable[i] = d_pzbuffer + i*d_zwidth;
- }
-
- /*
- ** clear Z-buffer and color-buffers if we're doing the gallery
- */
- if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
- {
- memset( d_pzbuffer, 0xff, vid.width * vid.height * sizeof( d_pzbuffer[0] ) );
- Draw_Fill( r_newrefdef.x, r_newrefdef.y, r_newrefdef.width, r_newrefdef.height,( int ) sw_clearcolor->value & 0xff );
- }
-
- alias_colormap = vid.colormap;
-
- D_Patch ();
-}
-
-
-
-/*
-=============
-R_PrintTimes
-=============
-*/
-void R_PrintTimes (void)
-{
- int r_time2;
- int ms;
-
- r_time2 = Sys_Milliseconds ();
-
- ms = r_time2 - r_time1;
-
- ri.Con_Printf (PRINT_ALL,"%5i ms %3i/%3i/%3i poly %3i surf\n",
- ms, c_faceclip, r_polycount, r_drawnpolycount, c_surf);
- c_surf = 0;
-}
-
-
-/*
-=============
-R_PrintDSpeeds
-=============
-*/
-void R_PrintDSpeeds (void)
-{
- int ms, dp_time, r_time2, rw_time, db_time, se_time, de_time, da_time;
-
- r_time2 = Sys_Milliseconds ();
-
- da_time = (da_time2 - da_time1);
- dp_time = (dp_time2 - dp_time1);
- rw_time = (rw_time2 - rw_time1);
- db_time = (db_time2 - db_time1);
- se_time = (se_time2 - se_time1);
- de_time = (de_time2 - de_time1);
- ms = (r_time2 - r_time1);
-
- ri.Con_Printf (PRINT_ALL,"%3i %2ip %2iw %2ib %2is %2ie %2ia\n",
- ms, dp_time, rw_time, db_time, se_time, de_time, da_time);
-}
-
-
-/*
-=============
-R_PrintAliasStats
-=============
-*/
-void R_PrintAliasStats (void)
-{
- ri.Con_Printf (PRINT_ALL,"%3i polygon model drawn\n", r_amodels_drawn);
-}
-
-
-
-/*
-===================
-R_TransformFrustum
-===================
-*/
-void R_TransformFrustum (void)
-{
- int i;
- vec3_t v, v2;
-
- for (i=0 ; i<4 ; i++)
- {
- v[0] = screenedge[i].normal[2];
- v[1] = -screenedge[i].normal[0];
- v[2] = screenedge[i].normal[1];
-
- v2[0] = v[1]*vright[0] + v[2]*vup[0] + v[0]*vpn[0];
- v2[1] = v[1]*vright[1] + v[2]*vup[1] + v[0]*vpn[1];
- v2[2] = v[1]*vright[2] + v[2]*vup[2] + v[0]*vpn[2];
-
- VectorCopy (v2, view_clipplanes[i].normal);
-
- view_clipplanes[i].dist = DotProduct (modelorg, v2);
- }
-}
-
-
-/*
-================
-TransformVector
-================
-*/
-void TransformVector (vec3_t in, vec3_t out)
-{
- out[0] = DotProduct(in,vright);
- out[1] = DotProduct(in,vup);
- out[2] = DotProduct(in,vpn);
-}
-
-
-/*
-================
-R_TransformPlane
-================
-*/
-void R_TransformPlane (mplane_t *p, float *normal, float *dist)
-{
- float d;
-
- d = DotProduct (r_origin, p->normal);
- *dist = p->dist - d;
-// TODO: when we have rotating entities, this will need to use the view matrix
- TransformVector (p->normal, normal);
-}
-
-
-/*
-===============
-R_SetUpFrustumIndexes
-===============
-*/
-void R_SetUpFrustumIndexes (void)
-{
- int i, j, *pindex;
-
- pindex = r_frustum_indexes;
-
- for (i=0 ; i<4 ; i++)
- {
- for (j=0 ; j<3 ; j++)
- {
- if (view_clipplanes[i].normal[j] < 0)
- {
- pindex[j] = j;
- pindex[j+3] = j+3;
- }
- else
- {
- pindex[j] = j+3;
- pindex[j+3] = j;
- }
- }
-
- // FIXME: do just once at start
- pfrustum_indexes[i] = pindex;
- pindex += 6;
- }
-}
-
-/*
-===============
-R_ViewChanged
-
-Called every time the vid structure or r_refdef changes.
-Guaranteed to be called before the first refresh
-===============
-*/
-void R_ViewChanged (vrect_t *vr)
-{
- int i;
-
- r_refdef.vrect = *vr;
-
- r_refdef.horizontalFieldOfView = 2*tan((float)r_newrefdef.fov_x/360*M_PI);;
- verticalFieldOfView = 2*tan((float)r_newrefdef.fov_y/360*M_PI);
-
- r_refdef.fvrectx = (float)r_refdef.vrect.x;
- r_refdef.fvrectx_adj = (float)r_refdef.vrect.x - 0.5;
- r_refdef.vrect_x_adj_shift20 = (r_refdef.vrect.x<<20) + (1<<19) - 1;
- r_refdef.fvrecty = (float)r_refdef.vrect.y;
- r_refdef.fvrecty_adj = (float)r_refdef.vrect.y - 0.5;
- r_refdef.vrectright = r_refdef.vrect.x + r_refdef.vrect.width;
- r_refdef.vrectright_adj_shift20 = (r_refdef.vrectright<<20) + (1<<19) - 1;
- r_refdef.fvrectright = (float)r_refdef.vrectright;
- r_refdef.fvrectright_adj = (float)r_refdef.vrectright - 0.5;
- r_refdef.vrectrightedge = (float)r_refdef.vrectright - 0.99;
- r_refdef.vrectbottom = r_refdef.vrect.y + r_refdef.vrect.height;
- r_refdef.fvrectbottom = (float)r_refdef.vrectbottom;
- r_refdef.fvrectbottom_adj = (float)r_refdef.vrectbottom - 0.5;
-
- r_refdef.aliasvrect.x = (int)(r_refdef.vrect.x * r_aliasuvscale);
- r_refdef.aliasvrect.y = (int)(r_refdef.vrect.y * r_aliasuvscale);
- r_refdef.aliasvrect.width = (int)(r_refdef.vrect.width * r_aliasuvscale);
- r_refdef.aliasvrect.height = (int)(r_refdef.vrect.height * r_aliasuvscale);
- r_refdef.aliasvrectright = r_refdef.aliasvrect.x +
- r_refdef.aliasvrect.width;
- r_refdef.aliasvrectbottom = r_refdef.aliasvrect.y +
- r_refdef.aliasvrect.height;
-
- xOrigin = r_refdef.xOrigin;
- yOrigin = r_refdef.yOrigin;
-
-// values for perspective projection
-// if math were exact, the values would range from 0.5 to to range+0.5
-// hopefully they wll be in the 0.000001 to range+.999999 and truncate
-// the polygon rasterization will never render in the first row or column
-// but will definately render in the [range] row and column, so adjust the
-// buffer origin to get an exact edge to edge fill
- xcenter = ((float)r_refdef.vrect.width * XCENTERING) +
- r_refdef.vrect.x - 0.5;
- aliasxcenter = xcenter * r_aliasuvscale;
- ycenter = ((float)r_refdef.vrect.height * YCENTERING) +
- r_refdef.vrect.y - 0.5;
- aliasycenter = ycenter * r_aliasuvscale;
-
- xscale = r_refdef.vrect.width / r_refdef.horizontalFieldOfView;
- aliasxscale = xscale * r_aliasuvscale;
- xscaleinv = 1.0 / xscale;
-
- yscale = xscale;
- aliasyscale = yscale * r_aliasuvscale;
- yscaleinv = 1.0 / yscale;
- xscaleshrink = (r_refdef.vrect.width-6)/r_refdef.horizontalFieldOfView;
- yscaleshrink = xscaleshrink;
-
-// left side clip
- screenedge[0].normal[0] = -1.0 / (xOrigin*r_refdef.horizontalFieldOfView);
- screenedge[0].normal[1] = 0;
- screenedge[0].normal[2] = 1;
- screenedge[0].type = PLANE_ANYZ;
-
-// right side clip
- screenedge[1].normal[0] =
- 1.0 / ((1.0-xOrigin)*r_refdef.horizontalFieldOfView);
- screenedge[1].normal[1] = 0;
- screenedge[1].normal[2] = 1;
- screenedge[1].type = PLANE_ANYZ;
-
-// top side clip
- screenedge[2].normal[0] = 0;
- screenedge[2].normal[1] = -1.0 / (yOrigin*verticalFieldOfView);
- screenedge[2].normal[2] = 1;
- screenedge[2].type = PLANE_ANYZ;
-
-// bottom side clip
- screenedge[3].normal[0] = 0;
- screenedge[3].normal[1] = 1.0 / ((1.0-yOrigin)*verticalFieldOfView);
- screenedge[3].normal[2] = 1;
- screenedge[3].type = PLANE_ANYZ;
-
- for (i=0 ; i<4 ; i++)
- VectorNormalize (screenedge[i].normal);
-
- D_ViewChanged ();
-}
-
-
-/*
-===============
-R_SetupFrame
-===============
-*/
-void R_SetupFrame (void)
-{
- int i;
- vrect_t vrect;
-
- if (r_fullbright->modified)
- {
- r_fullbright->modified = false;
- D_FlushCaches (); // so all lighting changes
- }
-
- r_framecount++;
-
-
-// build the transformation matrix for the given view angles
- VectorCopy (r_refdef.vieworg, modelorg);
- VectorCopy (r_refdef.vieworg, r_origin);
-
- AngleVectors (r_refdef.viewangles, vpn, vright, vup);
-
-// current viewleaf
- if ( !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) )
- {
- r_viewleaf = Mod_PointInLeaf (r_origin, r_worldmodel);
- r_viewcluster = r_viewleaf->cluster;
- }
-
- if (sw_waterwarp->value && (r_newrefdef.rdflags & RDF_UNDERWATER) )
- r_dowarp = true;
- else
- r_dowarp = false;
-
- if (r_dowarp)
- { // warp into off screen buffer
- vrect.x = 0;
- vrect.y = 0;
- vrect.width = r_newrefdef.width < WARP_WIDTH ? r_newrefdef.width : WARP_WIDTH;
- vrect.height = r_newrefdef.height < WARP_HEIGHT ? r_newrefdef.height : WARP_HEIGHT;
-
- d_viewbuffer = r_warpbuffer;
- r_screenwidth = WARP_WIDTH;
- }
- else
- {
- vrect.x = r_newrefdef.x;
- vrect.y = r_newrefdef.y;
- vrect.width = r_newrefdef.width;
- vrect.height = r_newrefdef.height;
-
- d_viewbuffer = (void *)vid.buffer;
- r_screenwidth = vid.rowbytes;
- }
-
- R_ViewChanged (&vrect);
-
-// start off with just the four screen edge clip planes
- R_TransformFrustum ();
- R_SetUpFrustumIndexes ();
-
-// save base values
- VectorCopy (vpn, base_vpn);
- VectorCopy (vright, base_vright);
- VectorCopy (vup, base_vup);
-
-// clear frame counts
- c_faceclip = 0;
- d_spanpixcount = 0;
- r_polycount = 0;
- r_drawnpolycount = 0;
- r_wholepolycount = 0;
- r_amodels_drawn = 0;
- r_outofsurfaces = 0;
- r_outofedges = 0;
-
-// d_setup
- d_roverwrapped = false;
- d_initial_rover = sc_rover;
-
- d_minmip = sw_mipcap->value;
- if (d_minmip > 3)
- d_minmip = 3;
- else if (d_minmip < 0)
- d_minmip = 0;
-
- for (i=0 ; i<(NUM_MIPS-1) ; i++)
- d_scalemip[i] = basemip[i] * sw_mipscale->value;
-
- d_aflatcolor = 0;
-}
-
-
-/*
-==============================================================================
-
- SCREEN SHOTS
-
-==============================================================================
-*/
-
-
-/*
-==============
-WritePCXfile
-==============
-*/
-void WritePCXfile (char *filename, byte *data, int width, int height,
- int rowbytes, byte *palette)
-{
- int i, j, length;
- pcx_t *pcx;
- byte *pack;
- FILE *f;
-
- pcx = (pcx_t *)malloc (width*height*2+1000);
- if (!pcx)
- return;
-
- pcx->manufacturer = 0x0a; // PCX id
- pcx->version = 5; // 256 color
- pcx->encoding = 1; // uncompressed
- pcx->bits_per_pixel = 8; // 256 color
- pcx->xmin = 0;
- pcx->ymin = 0;
- pcx->xmax = LittleShort((short)(width-1));
- pcx->ymax = LittleShort((short)(height-1));
- pcx->hres = LittleShort((short)width);
- pcx->vres = LittleShort((short)height);
- memset (pcx->palette,0,sizeof(pcx->palette));
- pcx->color_planes = 1; // chunky image
- pcx->bytes_per_line = LittleShort((short)width);
- pcx->palette_type = LittleShort(2); // not a grey scale
- memset (pcx->filler,0,sizeof(pcx->filler));
-
-// pack the image
- pack = &pcx->data;
-
- for (i=0 ; i<height ; i++)
- {
- for (j=0 ; j<width ; j++)
- {
- if ( (*data & 0xc0) != 0xc0)
- *pack++ = *data++;
- else
- {
- *pack++ = 0xc1;
- *pack++ = *data++;
- }
- }
-
- data += rowbytes - width;
- }
-
-// write the palette
- *pack++ = 0x0c; // palette ID byte
- for (i=0 ; i<768 ; i++)
- *pack++ = *palette++;
-
-// write output file
- length = pack - (byte *)pcx;
- f = fopen (filename, "wb");
- if (!f)
- ri.Con_Printf (PRINT_ALL, "Failed to open to %s\n", filename);
- else
- {
- fwrite ((void *)pcx, 1, length, f);
- fclose (f);
- }
-
- free (pcx);
-}
-
-
-
-/*
-==================
-R_ScreenShot_f
-==================
-*/
-void R_ScreenShot_f (void)
-{
- int i;
- char pcxname[80];
- char checkname[MAX_OSPATH];
- FILE *f;
- byte palette[768];
-
- // create the scrnshots directory if it doesn't exist
- Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot", ri.FS_Gamedir());
- Sys_Mkdir (checkname);
-
-//
-// find a file name to save it to
-//
- strcpy(pcxname,"quake00.pcx");
-
- for (i=0 ; i<=99 ; i++)
- {
- pcxname[5] = i/10 + '0';
- pcxname[6] = i%10 + '0';
- Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/%s", ri.FS_Gamedir(), pcxname);
- f = fopen (checkname, "r");
- if (!f)
- break; // file doesn't exist
- fclose (f);
- }
- if (i==100)
- {
- ri.Con_Printf (PRINT_ALL, "R_ScreenShot_f: Couldn't create a PCX");
- return;
- }
-
- // turn the current 32 bit palette into a 24 bit palette
- for (i=0 ; i<256 ; i++)
- {
- palette[i*3+0] = sw_state.currentpalette[i*4+0];
- palette[i*3+1] = sw_state.currentpalette[i*4+1];
- palette[i*3+2] = sw_state.currentpalette[i*4+2];
- }
-
-//
-// save the pcx file
-//
-
- WritePCXfile (checkname, vid.buffer, vid.width, vid.height, vid.rowbytes,
- palette);
-
- ri.Con_Printf (PRINT_ALL, "Wrote %s\n", checkname);
-}
-
--- a/ref/r_model.c
+++ /dev/null
@@ -1,1210 +1,0 @@
-// models.c -- model loading and caching
-
-// models are the only shared resource between a client and server running
-// on the same machine.
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-model_t *loadmodel;
-char loadname[32]; // for hunk tags
-
-void Mod_LoadSpriteModel (model_t *mod, void *buffer);
-void Mod_LoadBrushModel (model_t *mod, void *buffer);
-void Mod_LoadAliasModel (model_t *mod, void *buffer);
-model_t *Mod_LoadModel (model_t *mod, qboolean crash);
-
-byte mod_novis[MAX_MAP_LEAFS/8];
-
-#define MAX_MOD_KNOWN 256
-model_t mod_known[MAX_MOD_KNOWN];
-int mod_numknown;
-
-// the inline * models from the current map are kept seperate
-model_t mod_inline[MAX_MOD_KNOWN];
-
-int registration_sequence;
-int modfilelen;
-
-//===============================================================================
-
-
-/*
-================
-Mod_Modellist_f
-================
-*/
-void Mod_Modellist_f (void)
-{
- int i;
- model_t *mod;
- int total;
-
- total = 0;
- ri.Con_Printf (PRINT_ALL,"Loaded models:\n");
- for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++)
- {
- if (!mod->name[0])
- continue;
- ri.Con_Printf (PRINT_ALL, "%8i : %s\n",mod->extradatasize, mod->name);
- total += mod->extradatasize;
- }
- ri.Con_Printf (PRINT_ALL, "Total resident: %i\n", total);
-}
-
-/*
-===============
-Mod_Init
-===============
-*/
-void Mod_Init (void)
-{
- memset (mod_novis, 0xff, sizeof(mod_novis));
-}
-
-/*
-==================
-Mod_ForName
-
-Loads in a model for the given name
-==================
-*/
-model_t *Mod_ForName (char *name, qboolean crash)
-{
- model_t *mod;
- unsigned *buf;
- int i;
-
- if (!name[0])
- ri.Sys_Error (ERR_DROP,"Mod_ForName: NULL name");
-
- //
- // inline models are grabbed only from worldmodel
- //
- if (name[0] == '*')
- {
- i = atoi(name+1);
- if (i < 1 || !r_worldmodel || i >= r_worldmodel->numsubmodels)
- ri.Sys_Error (ERR_DROP, "bad inline model number");
- return &mod_inline[i];
- }
-
- //
- // search the currently loaded models
- //
- for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
- if (!strcmp (mod->name, name) )
- return mod;
-
- //
- // find a free model slot spot
- //
- for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
- {
- if (!mod->name[0])
- break; // free spot
- }
- if (i == mod_numknown)
- {
- if (mod_numknown == MAX_MOD_KNOWN)
- ri.Sys_Error (ERR_DROP, "mod_numknown == MAX_MOD_KNOWN");
- mod_numknown++;
- }
- strcpy (mod->name, name);
-
- //
- // load the file
- //
- modfilelen = ri.FS_LoadFile (mod->name, (void **)&buf);
- if (!buf)
- {
- if (crash)
- ri.Sys_Error (ERR_DROP,"Mod_NumForName: %s not found", mod->name);
- memset (mod->name, 0, sizeof(mod->name));
- return NULL;
- }
-
- loadmodel = mod;
-
- //
- // fill it in
- //
-
- // call the apropriate loader
-
- switch (LittleLong(*(unsigned *)buf))
- {
- case IDALIASHEADER:
- loadmodel->extradata = Hunk_Begin (0x200000);
- Mod_LoadAliasModel (mod, buf);
- break;
-
- case IDSPRITEHEADER:
- loadmodel->extradata = Hunk_Begin (0x10000);
- Mod_LoadSpriteModel (mod, buf);
- break;
-
- case IDBSPHEADER:
- loadmodel->extradata = Hunk_Begin (0x1000000);
- Mod_LoadBrushModel (mod, buf);
- break;
-
- default:
- ri.Sys_Error (ERR_DROP,"Mod_NumForName: unknown fileid for %s", mod->name);
- break;
- }
-
- loadmodel->extradatasize = Hunk_End ();
-
- ri.FS_FreeFile (buf);
-
- return mod;
-}
-
-
-/*
-===============
-Mod_PointInLeaf
-===============
-*/
-mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
-{
- mnode_t *node;
- float d;
- mplane_t *plane;
-
- if (!model || !model->nodes)
- ri.Sys_Error (ERR_DROP, "Mod_PointInLeaf: bad model");
-
- node = model->nodes;
- while (1)
- {
- if (node->contents != -1)
- return (mleaf_t *)node;
- plane = node->plane;
- d = DotProduct (p,plane->normal) - plane->dist;
- if (d > 0)
- node = node->children[0];
- else
- node = node->children[1];
- }
-}
-
-
-/*
-===================
-Mod_DecompressVis
-===================
-*/
-byte *Mod_DecompressVis (byte *in, model_t *model)
-{
- static byte decompressed[MAX_MAP_LEAFS/8];
- int c;
- byte *out;
- int row;
-
- row = (model->vis->numclusters+7)>>3;
- out = decompressed;
-
- /*
- memcpy (out, in, row);
- */
- if (!in)
- { // no vis info, so make all visible
- while (row)
- {
- *out++ = 0xff;
- row--;
- }
- return decompressed;
- }
-
- do
- {
- if (*in)
- {
- *out++ = *in++;
- continue;
- }
-
- c = in[1];
- in += 2;
- while (c)
- {
- *out++ = 0;
- c--;
- }
- } while (out - decompressed < row);
-
- return decompressed;
-}
-
-/*
-==============
-Mod_ClusterPVS
-==============
-*/
-byte *Mod_ClusterPVS (int cluster, model_t *model)
-{
- if (cluster == -1 || !model->vis)
- return mod_novis;
- return Mod_DecompressVis ( (byte *)model->vis + model->vis->bitofs[cluster][DVIS_PVS],
- model);
-}
-
-/*
-===============================================================================
-
- BRUSHMODEL LOADING
-
-===============================================================================
-*/
-
-byte *mod_base;
-
-
-/*
-=================
-Mod_LoadLighting
-
-Converts the 24 bit lighting down to 8 bit
-by taking the brightest component
-=================
-*/
-void Mod_LoadLighting (lump_t *l)
-{
- int i, size;
- byte *in;
-
- if (!l->filelen)
- {
- loadmodel->lightdata = NULL;
- return;
- }
- size = l->filelen/3;
- loadmodel->lightdata = Hunk_Alloc (size);
- in = (void *)(mod_base + l->fileofs);
- for (i=0 ; i<size ; i++, in+=3)
- {
- if (in[0] > in[1] && in[0] > in[2])
- loadmodel->lightdata[i] = in[0];
- else if (in[1] > in[0] && in[1] > in[2])
- loadmodel->lightdata[i] = in[1];
- else
- loadmodel->lightdata[i] = in[2];
- }
-}
-
-
-int r_leaftovis[MAX_MAP_LEAFS];
-int r_vistoleaf[MAX_MAP_LEAFS];
-int r_numvisleafs;
-
-void R_NumberLeafs (mnode_t *node)
-{
- mleaf_t *leaf;
- int leafnum;
-
- if (node->contents != -1)
- {
- leaf = (mleaf_t *)node;
- leafnum = leaf - loadmodel->leafs;
- if (leaf->contents & CONTENTS_SOLID)
- return;
- r_leaftovis[leafnum] = r_numvisleafs;
- r_vistoleaf[r_numvisleafs] = leafnum;
- r_numvisleafs++;
- return;
- }
-
- R_NumberLeafs (node->children[0]);
- R_NumberLeafs (node->children[1]);
-}
-
-
-/*
-=================
-Mod_LoadVisibility
-=================
-*/
-void Mod_LoadVisibility (lump_t *l)
-{
- int i;
-
- if (!l->filelen)
- {
- loadmodel->vis = NULL;
- return;
- }
- loadmodel->vis = Hunk_Alloc ( l->filelen);
- memcpy (loadmodel->vis, mod_base + l->fileofs, l->filelen);
-
- loadmodel->vis->numclusters = LittleLong (loadmodel->vis->numclusters);
- for (i=0 ; i<loadmodel->vis->numclusters ; i++)
- {
- loadmodel->vis->bitofs[i][0] = LittleLong (loadmodel->vis->bitofs[i][0]);
- loadmodel->vis->bitofs[i][1] = LittleLong (loadmodel->vis->bitofs[i][1]);
- }
-}
-
-
-/*
-=================
-Mod_LoadVertexes
-=================
-*/
-void Mod_LoadVertexes (lump_t *l)
-{
- dvertex_t *in;
- mvertex_t *out;
- int i, count;
-
- in = (void *)(mod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
- count = l->filelen / sizeof(*in);
- out = Hunk_Alloc ( (count+8)*sizeof(*out)); // extra for skybox
-
- loadmodel->vertexes = out;
- loadmodel->numvertexes = count;
-
- for ( i=0 ; i<count ; i++, in++, out++)
- {
- out->position[0] = LittleFloat (in->point[0]);
- out->position[1] = LittleFloat (in->point[1]);
- out->position[2] = LittleFloat (in->point[2]);
- }
-}
-
-/*
-=================
-Mod_LoadSubmodels
-=================
-*/
-void Mod_LoadSubmodels (lump_t *l)
-{
- dmodel_t *in;
- dmodel_t *out;
- int i, j, count;
-
- in = (void *)(mod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
- count = l->filelen / sizeof(*in);
- out = Hunk_Alloc ( count*sizeof(*out));
-
- loadmodel->submodels = out;
- loadmodel->numsubmodels = count;
-
- for ( i=0 ; i<count ; i++, in++, out++)
- {
- for (j=0 ; j<3 ; j++)
- { // spread the mins / maxs by a pixel
- out->mins[j] = LittleFloat (in->mins[j]) - 1;
- out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
- out->origin[j] = LittleFloat (in->origin[j]);
- }
- out->headnode = LittleLong (in->headnode);
- out->firstface = LittleLong (in->firstface);
- out->numfaces = LittleLong (in->numfaces);
- }
-}
-
-/*
-=================
-Mod_LoadEdges
-=================
-*/
-void Mod_LoadEdges (lump_t *l)
-{
- dedge_t *in;
- medge_t *out;
- int i, count;
-
- in = (void *)(mod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
- count = l->filelen / sizeof(*in);
- out = Hunk_Alloc ( (count + 13) * sizeof(*out)); // extra for skybox
-
- loadmodel->edges = out;
- loadmodel->numedges = count;
-
- for ( i=0 ; i<count ; i++, in++, out++)
- {
- out->v[0] = (unsigned short)LittleShort(in->v[0]);
- out->v[1] = (unsigned short)LittleShort(in->v[1]);
- }
-}
-
-/*
-=================
-Mod_LoadTexinfo
-=================
-*/
-void Mod_LoadTexinfo (lump_t *l)
-{
- texinfo_t *in;
- mtexinfo_t *out, *step;
- int i, j, count;
- float len1, len2;
- char name[MAX_QPATH];
- int next;
-
- in = (void *)(mod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
- count = l->filelen / sizeof(*in);
- out = Hunk_Alloc ( (count+6)*sizeof(*out)); // extra for skybox
-
- loadmodel->texinfo = out;
- loadmodel->numtexinfo = count;
-
- for ( i=0 ; i<count ; i++, in++, out++)
- {
- for (j=0 ; j<8 ; j++)
- out->vecs[0][j] = LittleFloat (in->vecs[0][j]);
- len1 = VectorLength (out->vecs[0]);
- len2 = VectorLength (out->vecs[1]);
- len1 = (len1 + len2)/2;
- if (len1 < 0.32)
- out->mipadjust = 4;
- else if (len1 < 0.49)
- out->mipadjust = 3;
- else if (len1 < 0.99)
- out->mipadjust = 2;
- else
- out->mipadjust = 1;
- /*
- if (len1 + len2 < 0.001)
- out->mipadjust = 1; // don't crash
- else
- out->mipadjust = 1 / floor( (len1+len2)/2 + 0.1 );
- */
-
- out->flags = LittleLong (in->flags);
-
- next = LittleLong (in->nexttexinfo);
- if (next > 0)
- out->next = loadmodel->texinfo + next;
-
- Com_sprintf (name, sizeof(name), "textures/%s.wal", in->texture);
- out->image = R_FindImage (name, it_wall);
- if (!out->image)
- {
- out->image = r_notexture_mip; // texture not found
- out->flags = 0;
- }
- }
-
- // count animation frames
- for (i=0 ; i<count ; i++)
- {
- out = &loadmodel->texinfo[i];
- out->numframes = 1;
- for (step = out->next ; step && step != out ; step=step->next)
- out->numframes++;
- }
-}
-
-/*
-================
-CalcSurfaceExtents
-
-Fills in s->texturemins[] and s->extents[]
-================
-*/
-void CalcSurfaceExtents (msurface_t *s)
-{
- float mins[2], maxs[2], val;
- int i,j, e;
- mvertex_t *v;
- mtexinfo_t *tex;
- int bmins[2], bmaxs[2];
-
- mins[0] = mins[1] = 999999;
- maxs[0] = maxs[1] = -99999;
-
- tex = s->texinfo;
-
- for (i=0 ; i<s->numedges ; i++)
- {
- e = loadmodel->surfedges[s->firstedge+i];
- if (e >= 0)
- v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
- else
- v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
-
- for (j=0 ; j<2 ; j++)
- {
- val = v->position[0] * tex->vecs[j][0] +
- v->position[1] * tex->vecs[j][1] +
- v->position[2] * tex->vecs[j][2] +
- tex->vecs[j][3];
- if (val < mins[j])
- mins[j] = val;
- if (val > maxs[j])
- maxs[j] = val;
- }
- }
-
- for (i=0 ; i<2 ; i++)
- {
- bmins[i] = floor(mins[i]/16);
- bmaxs[i] = ceil(maxs[i]/16);
-
- s->texturemins[i] = bmins[i] * 16;
- s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
- if (s->extents[i] < 16)
- s->extents[i] = 16; // take at least one cache block
- if ( !(tex->flags & (SURF_WARP|SURF_SKY)) && s->extents[i] > 256)
- ri.Sys_Error (ERR_DROP,"Bad surface extents");
- }
-}
-
-
-/*
-=================
-Mod_LoadFaces
-=================
-*/
-void Mod_LoadFaces (lump_t *l)
-{
- dface_t *in;
- msurface_t *out;
- int i, count, surfnum;
- int planenum, side;
-
- in = (void *)(mod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
- count = l->filelen / sizeof(*in);
- out = Hunk_Alloc ( (count+6)*sizeof(*out)); // extra for skybox
-
- loadmodel->surfaces = out;
- loadmodel->numsurfaces = count;
-
- for ( surfnum=0 ; surfnum<count ; surfnum++, in++, out++)
- {
- out->firstedge = LittleLong(in->firstedge);
- out->numedges = LittleShort(in->numedges);
- if (out->numedges < 3)
- ri.Sys_Error (ERR_DROP,"Surface with %s edges", out->numedges);
- out->flags = 0;
-
- planenum = LittleShort(in->planenum);
- side = LittleShort(in->side);
- if (side)
- out->flags |= SURF_PLANEBACK;
-
- out->plane = loadmodel->planes + planenum;
-
- out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo);
-
- CalcSurfaceExtents (out);
-
- // lighting info is converted from 24 bit on disk to 8 bit
-
- for (i=0 ; i<MAXLIGHTMAPS ; i++)
- out->styles[i] = in->styles[i];
- i = LittleLong(in->lightofs);
- if (i == -1)
- out->samples = NULL;
- else
- out->samples = loadmodel->lightdata + i/3;
-
- // set the drawing flags flag
-
- if (!out->texinfo->image)
- continue;
- if (out->texinfo->flags & SURF_SKY)
- {
- out->flags |= SURF_DRAWSKY;
- continue;
- }
-
- if (out->texinfo->flags & SURF_WARP)
- {
- out->flags |= SURF_DRAWTURB;
- for (i=0 ; i<2 ; i++)
- {
- out->extents[i] = 16384;
- out->texturemins[i] = -8192;
- }
- continue;
- }
-//==============
-//PGM
- // this marks flowing surfaces as turbulent, but with the new
- // SURF_FLOW flag.
- if (out->texinfo->flags & SURF_FLOWING)
- {
- out->flags |= SURF_DRAWTURB | SURF_FLOW;
- for (i=0 ; i<2 ; i++)
- {
- out->extents[i] = 16384;
- out->texturemins[i] = -8192;
- }
- continue;
- }
-//PGM
-//==============
- }
-}
-
-
-/*
-=================
-Mod_SetParent
-=================
-*/
-void Mod_SetParent (mnode_t *node, mnode_t *parent)
-{
- node->parent = parent;
- if (node->contents != -1)
- return;
- Mod_SetParent (node->children[0], node);
- Mod_SetParent (node->children[1], node);
-}
-
-/*
-=================
-Mod_LoadNodes
-=================
-*/
-void Mod_LoadNodes (lump_t *l)
-{
- int i, j, count, p;
- dnode_t *in;
- mnode_t *out;
-
- in = (void *)(mod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
- count = l->filelen / sizeof(*in);
- out = Hunk_Alloc ( count*sizeof(*out));
-
- loadmodel->nodes = out;
- loadmodel->numnodes = count;
-
- for ( i=0 ; i<count ; i++, in++, out++)
- {
- for (j=0 ; j<3 ; j++)
- {
- out->minmaxs[j] = LittleShort (in->mins[j]);
- out->minmaxs[3+j] = LittleShort (in->maxs[j]);
- }
-
- p = LittleLong(in->planenum);
- out->plane = loadmodel->planes + p;
-
- out->firstsurface = LittleShort (in->firstface);
- out->numsurfaces = LittleShort (in->numfaces);
- out->contents = CONTENTS_NODE; // differentiate from leafs
-
- for (j=0 ; j<2 ; j++)
- {
- p = LittleLong (in->children[j]);
- if (p >= 0)
- out->children[j] = loadmodel->nodes + p;
- else
- out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
- }
- }
-
- Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
-}
-
-/*
-=================
-Mod_LoadLeafs
-=================
-*/
-void Mod_LoadLeafs (lump_t *l)
-{
- dleaf_t *in;
- mleaf_t *out;
- int i, j, count;
-
- in = (void *)(mod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
- count = l->filelen / sizeof(*in);
- out = Hunk_Alloc ( count*sizeof(*out));
-
- loadmodel->leafs = out;
- loadmodel->numleafs = count;
-
- for ( i=0 ; i<count ; i++, in++, out++)
- {
- for (j=0 ; j<3 ; j++)
- {
- out->minmaxs[j] = LittleShort (in->mins[j]);
- out->minmaxs[3+j] = LittleShort (in->maxs[j]);
- }
-
- out->contents = LittleLong(in->contents);
- out->cluster = LittleShort(in->cluster);
- out->area = LittleShort(in->area);
-
- out->firstmarksurface = loadmodel->marksurfaces +
- LittleShort(in->firstleafface);
- out->nummarksurfaces = LittleShort(in->numleaffaces);
- }
-}
-
-
-/*
-=================
-Mod_LoadMarksurfaces
-=================
-*/
-void Mod_LoadMarksurfaces (lump_t *l)
-{
- int i, j, count;
- short *in;
- msurface_t **out;
-
- in = (void *)(mod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
- count = l->filelen / sizeof(*in);
- out = Hunk_Alloc ( count*sizeof(*out));
-
- loadmodel->marksurfaces = out;
- loadmodel->nummarksurfaces = count;
-
- for ( i=0 ; i<count ; i++)
- {
- j = LittleShort(in[i]);
- if (j >= loadmodel->numsurfaces)
- ri.Sys_Error (ERR_DROP,"Mod_ParseMarksurfaces: bad surface number");
- out[i] = loadmodel->surfaces + j;
- }
-}
-
-/*
-=================
-Mod_LoadSurfedges
-=================
-*/
-void Mod_LoadSurfedges (lump_t *l)
-{
- int i, count;
- int *in, *out;
-
- in = (void *)(mod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
- count = l->filelen / sizeof(*in);
- out = Hunk_Alloc ( (count+24)*sizeof(*out)); // extra for skybox
-
- loadmodel->surfedges = out;
- loadmodel->numsurfedges = count;
-
- for ( i=0 ; i<count ; i++)
- out[i] = LittleLong (in[i]);
-}
-
-/*
-=================
-Mod_LoadPlanes
-=================
-*/
-void Mod_LoadPlanes (lump_t *l)
-{
- int i, j;
- mplane_t *out;
- dplane_t *in;
- int count;
- int bits;
-
- in = (void *)(mod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- ri.Sys_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
- count = l->filelen / sizeof(*in);
- out = Hunk_Alloc ( (count+6)*sizeof(*out)); // extra for skybox
-
- loadmodel->planes = out;
- loadmodel->numplanes = count;
-
- for ( i=0 ; i<count ; i++, in++, out++)
- {
- bits = 0;
- for (j=0 ; j<3 ; j++)
- {
- out->normal[j] = LittleFloat (in->normal[j]);
- if (out->normal[j] < 0)
- bits |= 1<<j;
- }
-
- out->dist = LittleFloat (in->dist);
- out->type = LittleLong (in->type);
- out->signbits = bits;
- }
-}
-
-
-/*
-=================
-Mod_LoadBrushModel
-=================
-*/
-void Mod_LoadBrushModel (model_t *mod, void *buffer)
-{
- int i;
- dheader_t *header;
- dmodel_t *bm;
-
- loadmodel->type = mod_brush;
- if (loadmodel != mod_known)
- ri.Sys_Error (ERR_DROP, "Loaded a brush model after the world");
-
- header = (dheader_t *)buffer;
-
- i = LittleLong (header->version);
- if (i != BSPVERSION)
- ri.Sys_Error (ERR_DROP,"Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION);
-
-// swap all the lumps
- mod_base = (byte *)header;
-
- for (i=0 ; i<sizeof(dheader_t)/sizeof(int) ; i++)
- ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
-
-// load into heap
-
- Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
- Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
- Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
- Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
- Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
- Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
- Mod_LoadFaces (&header->lumps[LUMP_FACES]);
- Mod_LoadMarksurfaces (&header->lumps[LUMP_LEAFFACES]);
- Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
- Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
- Mod_LoadNodes (&header->lumps[LUMP_NODES]);
- Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
- r_numvisleafs = 0;
- R_NumberLeafs (loadmodel->nodes);
-
-//
-// set up the submodels
-//
- for (i=0 ; i<mod->numsubmodels ; i++)
- {
- model_t *starmod;
-
- bm = &mod->submodels[i];
- starmod = &mod_inline[i];
-
- *starmod = *loadmodel;
-
- starmod->firstmodelsurface = bm->firstface;
- starmod->nummodelsurfaces = bm->numfaces;
- starmod->firstnode = bm->headnode;
- if (starmod->firstnode >= loadmodel->numnodes)
- ri.Sys_Error (ERR_DROP, "Inline model %i has bad firstnode", i);
-
- VectorCopy (bm->maxs, starmod->maxs);
- VectorCopy (bm->mins, starmod->mins);
-
- if (i == 0)
- *loadmodel = *starmod;
- }
-
- R_InitSkyBox ();
-}
-
-/*
-==============================================================================
-
-ALIAS MODELS
-
-==============================================================================
-*/
-
-/*
-=================
-Mod_LoadAliasModel
-=================
-*/
-void Mod_LoadAliasModel (model_t *mod, void *buffer)
-{
- int i, j;
- dmdl_t *pinmodel, *pheader;
- dstvert_t *pinst, *poutst;
- dtriangle_t *pintri, *pouttri;
- daliasframe_t *pinframe, *poutframe;
- int *pincmd, *poutcmd;
- int version;
-
- pinmodel = (dmdl_t *)buffer;
-
- version = LittleLong (pinmodel->version);
- if (version != ALIAS_VERSION)
- ri.Sys_Error (ERR_DROP, "%s has wrong version number (%i should be %i)",
- mod->name, version, ALIAS_VERSION);
-
- pheader = Hunk_Alloc (LittleLong(pinmodel->ofs_end));
-
- // byte swap the header fields and sanity check
- for (i=0 ; i<sizeof(dmdl_t)/sizeof(int) ; i++)
- ((int *)pheader)[i] = LittleLong (((int *)buffer)[i]);
-
- if (pheader->skinheight > MAX_LBM_HEIGHT)
- ri.Sys_Error (ERR_DROP, "model %s has a skin taller than %d", mod->name,
- MAX_LBM_HEIGHT);
-
- if (pheader->num_xyz <= 0)
- ri.Sys_Error (ERR_DROP, "model %s has no vertices", mod->name);
-
- if (pheader->num_xyz > MAX_VERTS)
- ri.Sys_Error (ERR_DROP, "model %s has too many vertices", mod->name);
-
- if (pheader->num_st <= 0)
- ri.Sys_Error (ERR_DROP, "model %s has no st vertices", mod->name);
-
- if (pheader->num_tris <= 0)
- ri.Sys_Error (ERR_DROP, "model %s has no triangles", mod->name);
-
- if (pheader->num_frames <= 0)
- ri.Sys_Error (ERR_DROP, "model %s has no frames", mod->name);
-
-//
-// load base s and t vertices (not used in gl version)
-//
- pinst = (dstvert_t *) ((byte *)pinmodel + pheader->ofs_st);
- poutst = (dstvert_t *) ((byte *)pheader + pheader->ofs_st);
-
- for (i=0 ; i<pheader->num_st ; i++)
- {
- poutst[i].s = LittleShort (pinst[i].s);
- poutst[i].t = LittleShort (pinst[i].t);
- }
-
-//
-// load triangle lists
-//
- pintri = (dtriangle_t *) ((byte *)pinmodel + pheader->ofs_tris);
- pouttri = (dtriangle_t *) ((byte *)pheader + pheader->ofs_tris);
-
- for (i=0 ; i<pheader->num_tris ; i++)
- {
- for (j=0 ; j<3 ; j++)
- {
- pouttri[i].index_xyz[j] = LittleShort (pintri[i].index_xyz[j]);
- pouttri[i].index_st[j] = LittleShort (pintri[i].index_st[j]);
- }
- }
-
-//
-// load the frames
-//
- for (i=0 ; i<pheader->num_frames ; i++)
- {
- pinframe = (daliasframe_t *) ((byte *)pinmodel
- + pheader->ofs_frames + i * pheader->framesize);
- poutframe = (daliasframe_t *) ((byte *)pheader
- + pheader->ofs_frames + i * pheader->framesize);
-
- memcpy (poutframe->name, pinframe->name, sizeof(poutframe->name));
- for (j=0 ; j<3 ; j++)
- {
- poutframe->scale[j] = LittleFloat (pinframe->scale[j]);
- poutframe->translate[j] = LittleFloat (pinframe->translate[j]);
- }
- // verts are all 8 bit, so no swapping needed
- memcpy (poutframe->verts, pinframe->verts,
- pheader->num_xyz*sizeof(dtrivertx_t));
-
- }
-
- mod->type = mod_alias;
-
- //
- // load the glcmds
- //
- pincmd = (int *) ((byte *)pinmodel + pheader->ofs_glcmds);
- poutcmd = (int *) ((byte *)pheader + pheader->ofs_glcmds);
- for (i=0 ; i<pheader->num_glcmds ; i++)
- poutcmd[i] = LittleLong (pincmd[i]);
-
-
- // register all skins
- memcpy ((char *)pheader + pheader->ofs_skins, (char *)pinmodel + pheader->ofs_skins,
- pheader->num_skins*MAX_SKINNAME);
- for (i=0 ; i<pheader->num_skins ; i++)
- {
- mod->skins[i] = R_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME, it_skin);
- }
-}
-
-/*
-==============================================================================
-
-SPRITE MODELS
-
-==============================================================================
-*/
-
-/*
-=================
-Mod_LoadSpriteModel
-=================
-*/
-void Mod_LoadSpriteModel (model_t *mod, void *buffer)
-{
- dsprite_t *sprin, *sprout;
- int i;
-
- sprin = (dsprite_t *)buffer;
- sprout = Hunk_Alloc (modfilelen);
-
- sprout->ident = LittleLong (sprin->ident);
- sprout->version = LittleLong (sprin->version);
- sprout->numframes = LittleLong (sprin->numframes);
-
- if (sprout->version != SPRITE_VERSION)
- ri.Sys_Error (ERR_DROP, "%s has wrong version number (%i should be %i)",
- mod->name, sprout->version, SPRITE_VERSION);
-
- if (sprout->numframes > MAX_MD2SKINS)
- ri.Sys_Error (ERR_DROP, "%s has too many frames (%i > %i)",
- mod->name, sprout->numframes, MAX_MD2SKINS);
-
- // byte swap everything
- for (i=0 ; i<sprout->numframes ; i++)
- {
- sprout->frames[i].width = LittleLong (sprin->frames[i].width);
- sprout->frames[i].height = LittleLong (sprin->frames[i].height);
- sprout->frames[i].origin_x = LittleLong (sprin->frames[i].origin_x);
- sprout->frames[i].origin_y = LittleLong (sprin->frames[i].origin_y);
- memcpy (sprout->frames[i].name, sprin->frames[i].name, MAX_SKINNAME);
- mod->skins[i] = R_FindImage (sprout->frames[i].name, it_sprite);
- }
-
- mod->type = mod_sprite;
-}
-
-//=============================================================================
-
-/*
-@@@@@@@@@@@@@@@@@@@@@
-R_BeginRegistration
-
-Specifies the model that will be used as the world
-@@@@@@@@@@@@@@@@@@@@@
-*/
-void R_BeginRegistration (char *model)
-{
- char fullname[MAX_QPATH];
- cvar_t *flushmap;
-
- registration_sequence++;
- r_oldviewcluster = -1; // force markleafs
- Com_sprintf (fullname, sizeof(fullname), "maps/%s.bsp", model);
-
- D_FlushCaches ();
- // explicitly free the old map if different
- // this guarantees that mod_known[0] is the world map
- flushmap = ri.Cvar_Get ("flushmap", "0", 0);
- if ( strcmp(mod_known[0].name, fullname) || flushmap->value)
- Mod_Free (&mod_known[0]);
- r_worldmodel = R_RegisterModel (fullname);
- R_NewMap ();
-}
-
-
-/*
-@@@@@@@@@@@@@@@@@@@@@
-R_RegisterModel
-
-@@@@@@@@@@@@@@@@@@@@@
-*/
-struct model_s *R_RegisterModel (char *name)
-{
- model_t *mod;
- int i;
- dsprite_t *sprout;
- dmdl_t *pheader;
-
- mod = Mod_ForName (name, false);
- if (mod)
- {
- mod->registration_sequence = registration_sequence;
-
- // register any images used by the models
- if (mod->type == mod_sprite)
- {
- sprout = (dsprite_t *)mod->extradata;
- for (i=0 ; i<sprout->numframes ; i++)
- mod->skins[i] = R_FindImage (sprout->frames[i].name, it_sprite);
- }
- else if (mod->type == mod_alias)
- {
- pheader = (dmdl_t *)mod->extradata;
- for (i=0 ; i<pheader->num_skins ; i++)
- mod->skins[i] = R_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME, it_skin);
-//PGM
- mod->numframes = pheader->num_frames;
-//PGM
- }
- else if (mod->type == mod_brush)
- {
- for (i=0 ; i<mod->numtexinfo ; i++)
- mod->texinfo[i].image->registration_sequence = registration_sequence;
- }
- }
- return mod;
-}
-
-/*
-@@@@@@@@@@@@@@@@@@@@@
-R_EndRegistration
-
-@@@@@@@@@@@@@@@@@@@@@
-*/
-void R_EndRegistration (void)
-{
- int i;
- model_t *mod;
-
- for (i=0, mod=mod_known ; i<mod_numknown ; i++, mod++)
- {
- if (!mod->name[0])
- continue;
- if (mod->registration_sequence != registration_sequence)
- { // don't need this model
- Hunk_Free (mod->extradata);
- memset (mod, 0, sizeof(*mod));
- }
- else
- { // make sure it is paged in
- Com_PageInMemory (mod->extradata, mod->extradatasize);
- }
- }
-
- R_FreeUnusedImages ();
-}
-
-void
-Mod_Free(model_t *mod)
-{
- Hunk_Free(mod->extradata);
- memset(mod, 0, sizeof *mod);
-}
-
-void
-Mod_FreeAll(void)
-{
- int i;
-
- for(i=0; i<mod_numknown; i++){
- if(mod_known[i].extradatasize)
- Mod_Free(&mod_known[i]);
- }
-}
--- a/ref/r_part.c
+++ /dev/null
@@ -1,203 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-vec3_t r_pright, r_pup, r_ppn;
-
-#define PARTICLE_33 0
-#define PARTICLE_66 1
-#define PARTICLE_OPAQUE 2
-
-typedef struct
-{
- particle_t *particle;
- int level;
- int color;
-} partparms_t;
-
-static partparms_t partparms;
-
-static byte BlendParticle33( int pcolor, int dstcolor )
-{
- return vid.alphamap[pcolor + dstcolor*256];
-}
-
-static byte BlendParticle66( int pcolor, int dstcolor )
-{
- return vid.alphamap[pcolor*256+dstcolor];
-}
-
-static byte BlendParticle100( int pcolor, int /*dstcolor*/ )
-{
- return pcolor;
-}
-
-/*
-** R_DrawParticle
-**
-** Yes, this is amazingly slow, but it's the C reference
-** implementation and should be both robust and vaguely
-** understandable. The only time this path should be
-** executed is if we're debugging on x86 or if we're
-** recompiling and deploying on a non-x86 platform.
-**
-** To minimize error and improve readability I went the
-** function pointer route. This exacts some overhead, but
-** it pays off in clean and easy to understand code.
-*/
-void R_DrawParticle( void )
-{
- particle_t *pparticle = partparms.particle;
- int level = partparms.level;
- vec3_t local, transformed;
- float zi;
- byte *pdest;
- short *pz;
- int color = pparticle->color;
- int i, izi, pix, count, u, v;
-
- /*
- ** transform the particle
- */
- VectorSubtract (pparticle->origin, r_origin, local);
-
- transformed[0] = DotProduct(local, r_pright);
- transformed[1] = DotProduct(local, r_pup);
- transformed[2] = DotProduct(local, r_ppn);
-
- if (transformed[2] < PARTICLE_Z_CLIP)
- return;
-
- /*
- ** bind the blend function pointer to the appropriate blender
- */
- /*
- byte (*blendparticle)( int, int );
- if ( level == PARTICLE_33 )
- blendparticle = BlendParticle33;
- else if ( level == PARTICLE_66 )
- blendparticle = BlendParticle66;
- else
- blendparticle = BlendParticle100;
- */
-
- /*
- ** project the point
- */
- // FIXME: preadjust xcenter and ycenter
- zi = 1.0 / transformed[2];
- u = (int)(xcenter + zi * transformed[0] + 0.5);
- v = (int)(ycenter - zi * transformed[1] + 0.5);
-
- if ((v > d_vrectbottom_particle) ||
- (u > d_vrectright_particle) ||
- (v < d_vrecty) ||
- (u < d_vrectx))
- {
- return;
- }
-
- /*
- ** compute addresses of zbuffer, framebuffer, and
- ** compute the Z-buffer reference value.
- */
- pz = d_pzbuffer + (d_zwidth * v) + u;
- pdest = d_viewbuffer + d_scantable[v] + u;
- izi = (int)(zi * 0x8000);
-
- /*
- ** determine the screen area covered by the particle,
- ** which also means clamping to a min and max
- */
- pix = izi >> d_pix_shift;
- if (pix < d_pix_min)
- pix = d_pix_min;
- else if (pix > d_pix_max)
- pix = d_pix_max;
-
- /*
- ** render the appropriate pixels
- */
- count = pix;
-
- switch (level) {
- case PARTICLE_33 :
- for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth)
- {
-//FIXME--do it in blocks of 8?
- for (i=0 ; i<pix ; i++)
- {
- if (pz[i] <= izi)
- {
- pz[i] = izi;
- pdest[i] = vid.alphamap[color + ((int)pdest[i]<<8)];
- }
- }
- }
- break;
-
- case PARTICLE_66 :
- for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth)
- {
- for (i=0 ; i<pix ; i++)
- {
- if (pz[i] <= izi)
- {
- pz[i] = izi;
- pdest[i] = vid.alphamap[(color<<8) + (int)pdest[i]];
- }
- }
- }
- break;
-
- default: //100
- for ( ; count ; count--, pz += d_zwidth, pdest += r_screenwidth)
- {
- for (i=0 ; i<pix ; i++)
- {
- if (pz[i] <= izi)
- {
- pz[i] = izi;
- pdest[i] = color;
- }
- }
- }
- break;
- }
-}
-
-/*
-** R_DrawParticles
-**
-** Responsible for drawing all of the particles in the particle list
-** throughout the world. Doesn't care if we're using the C path or
-** if we're using the asm path, it simply assigns a function pointer
-** and goes.
-*/
-void R_DrawParticles (void)
-{
- particle_t *p;
- int i;
- extern unsigned long fpu_sp24_cw, fpu_chop_cw;
-
- VectorScale( vright, xscaleshrink, r_pright );
- VectorScale( vup, yscaleshrink, r_pup );
- VectorCopy( vpn, r_ppn );
-
- for (p=r_newrefdef.particles, i=0 ; i<r_newrefdef.num_particles ; i++,p++)
- {
-
- if ( p->alpha > 0.66 )
- partparms.level = PARTICLE_OPAQUE;
- else if ( p->alpha > 0.33 )
- partparms.level = PARTICLE_66;
- else
- partparms.level = PARTICLE_33;
-
- partparms.particle = p;
- partparms.color = p->color;
-
- R_DrawParticle();
- }
-}
--- a/ref/r_poly.c
+++ /dev/null
@@ -1,1225 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-#define AFFINE_SPANLET_SIZE 16
-#define AFFINE_SPANLET_SIZE_BITS 4
-
-typedef struct
-{
- byte *pbase, *pdest;
- short *pz;
- fixed16_t s, t;
- fixed16_t sstep, tstep;
- int izi, izistep, izistep_times_2;
- int spancount;
- unsigned u, v;
-} spanletvars_t;
-
-spanletvars_t s_spanletvars;
-
-static int r_polyblendcolor;
-
-static espan_t *s_polygon_spans;
-
-polydesc_t r_polydesc;
-
-msurface_t *r_alpha_surfaces;
-
-extern int *r_turb_turb;
-
-static int clip_current;
-vec5_t r_clip_verts[2][MAXWORKINGVERTS+2];
-
-static int s_minindex, s_maxindex;
-
-static void R_DrawPoly( qboolean iswater );
-
-/*
-** R_DrawSpanletOpaque
-*/
-void R_DrawSpanletOpaque( void )
-{
- unsigned btemp;
-
- do
- {
- unsigned ts, tt;
-
- ts = s_spanletvars.s >> 16;
- tt = s_spanletvars.t >> 16;
-
- btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth);
- if (btemp != 255)
- {
- if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
- {
- *s_spanletvars.pz = s_spanletvars.izi >> 16;
- *s_spanletvars.pdest = btemp;
- }
- }
-
- s_spanletvars.izi += s_spanletvars.izistep;
- s_spanletvars.pdest++;
- s_spanletvars.pz++;
- s_spanletvars.s += s_spanletvars.sstep;
- s_spanletvars.t += s_spanletvars.tstep;
- } while (--s_spanletvars.spancount > 0);
-}
-
-/*
-** R_DrawSpanletTurbulentStipple33
-*/
-void R_DrawSpanletTurbulentStipple33( void )
-{
- unsigned btemp;
- int sturb, tturb;
- byte *pdest = s_spanletvars.pdest;
- short *pz = s_spanletvars.pz;
- int izi = s_spanletvars.izi;
-
- if ( s_spanletvars.v & 1 )
- {
- s_spanletvars.pdest += s_spanletvars.spancount;
- s_spanletvars.pz += s_spanletvars.spancount;
-
- if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
- s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
- else
- s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
-
- if ( s_spanletvars.u & 1 )
- {
- izi += s_spanletvars.izistep;
- s_spanletvars.s += s_spanletvars.sstep;
- s_spanletvars.t += s_spanletvars.tstep;
-
- pdest++;
- pz++;
- s_spanletvars.spancount--;
- }
-
- s_spanletvars.sstep *= 2;
- s_spanletvars.tstep *= 2;
-
- while ( s_spanletvars.spancount > 0 )
- {
- sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
- tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
-
- btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
-
- if ( *pz <= ( izi >> 16 ) )
- *pdest = btemp;
-
- izi += s_spanletvars.izistep_times_2;
- s_spanletvars.s += s_spanletvars.sstep;
- s_spanletvars.t += s_spanletvars.tstep;
-
- pdest += 2;
- pz += 2;
-
- s_spanletvars.spancount -= 2;
- }
- }
-}
-
-/*
-** R_DrawSpanletTurbulentStipple66
-*/
-void R_DrawSpanletTurbulentStipple66( void )
-{
- unsigned btemp;
- int sturb, tturb;
- byte *pdest = s_spanletvars.pdest;
- short *pz = s_spanletvars.pz;
- int izi = s_spanletvars.izi;
-
- if ( !( s_spanletvars.v & 1 ) )
- {
- s_spanletvars.pdest += s_spanletvars.spancount;
- s_spanletvars.pz += s_spanletvars.spancount;
-
- if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
- s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
- else
- s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
-
- if ( s_spanletvars.u & 1 )
- {
- izi += s_spanletvars.izistep;
- s_spanletvars.s += s_spanletvars.sstep;
- s_spanletvars.t += s_spanletvars.tstep;
-
- pdest++;
- pz++;
- s_spanletvars.spancount--;
- }
-
- s_spanletvars.sstep *= 2;
- s_spanletvars.tstep *= 2;
-
- while ( s_spanletvars.spancount > 0 )
- {
- sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
- tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
-
- btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
-
- if ( *pz <= ( izi >> 16 ) )
- *pdest = btemp;
-
- izi += s_spanletvars.izistep_times_2;
- s_spanletvars.s += s_spanletvars.sstep;
- s_spanletvars.t += s_spanletvars.tstep;
-
- pdest += 2;
- pz += 2;
-
- s_spanletvars.spancount -= 2;
- }
- }
- else
- {
- s_spanletvars.pdest += s_spanletvars.spancount;
- s_spanletvars.pz += s_spanletvars.spancount;
-
- if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
- s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
- else
- s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
-
- while ( s_spanletvars.spancount > 0 )
- {
- sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
- tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
-
- btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
-
- if ( *pz <= ( izi >> 16 ) )
- *pdest = btemp;
-
- izi += s_spanletvars.izistep;
- s_spanletvars.s += s_spanletvars.sstep;
- s_spanletvars.t += s_spanletvars.tstep;
-
- pdest++;
- pz++;
-
- s_spanletvars.spancount--;
- }
- }
-}
-
-/*
-** R_DrawSpanletTurbulentBlended
-*/
-void R_DrawSpanletTurbulentBlended66( void )
-{
- unsigned btemp;
- int sturb, tturb;
-
- do
- {
- sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
- tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
-
- btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
-
- if ( *s_spanletvars.pz <= ( s_spanletvars.izi >> 16 ) )
- *s_spanletvars.pdest = vid.alphamap[btemp*256+*s_spanletvars.pdest];
-
- s_spanletvars.izi += s_spanletvars.izistep;
- s_spanletvars.pdest++;
- s_spanletvars.pz++;
- s_spanletvars.s += s_spanletvars.sstep;
- s_spanletvars.t += s_spanletvars.tstep;
-
- } while ( --s_spanletvars.spancount > 0 );
-}
-
-void R_DrawSpanletTurbulentBlended33( void )
-{
- unsigned btemp;
- int sturb, tturb;
-
- do
- {
- sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63;
- tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63;
-
- btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) );
-
- if ( *s_spanletvars.pz <= ( s_spanletvars.izi >> 16 ) )
- *s_spanletvars.pdest = vid.alphamap[btemp+*s_spanletvars.pdest*256];
-
- s_spanletvars.izi += s_spanletvars.izistep;
- s_spanletvars.pdest++;
- s_spanletvars.pz++;
- s_spanletvars.s += s_spanletvars.sstep;
- s_spanletvars.t += s_spanletvars.tstep;
-
- } while ( --s_spanletvars.spancount > 0 );
-}
-
-/*
-** R_DrawSpanlet33
-*/
-void R_DrawSpanlet33( void )
-{
- unsigned btemp;
-
- do
- {
- unsigned ts, tt;
-
- ts = s_spanletvars.s >> 16;
- tt = s_spanletvars.t >> 16;
-
- btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth);
-
- if ( btemp != 255 )
- {
- if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
- {
- *s_spanletvars.pdest = vid.alphamap[btemp+*s_spanletvars.pdest*256];
- }
- }
-
- s_spanletvars.izi += s_spanletvars.izistep;
- s_spanletvars.pdest++;
- s_spanletvars.pz++;
- s_spanletvars.s += s_spanletvars.sstep;
- s_spanletvars.t += s_spanletvars.tstep;
- } while (--s_spanletvars.spancount > 0);
-}
-
-void R_DrawSpanletConstant33( void )
-{
- do
- {
- if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
- {
- *s_spanletvars.pdest = vid.alphamap[r_polyblendcolor+*s_spanletvars.pdest*256];
- }
-
- s_spanletvars.izi += s_spanletvars.izistep;
- s_spanletvars.pdest++;
- s_spanletvars.pz++;
- } while (--s_spanletvars.spancount > 0);
-}
-
-/*
-** R_DrawSpanlet66
-*/
-void R_DrawSpanlet66( void )
-{
- unsigned btemp;
-
- do
- {
- unsigned ts, tt;
-
- ts = s_spanletvars.s >> 16;
- tt = s_spanletvars.t >> 16;
-
- btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth);
-
- if ( btemp != 255 )
- {
- if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16))
- {
- *s_spanletvars.pdest = vid.alphamap[btemp*256+*s_spanletvars.pdest];
- }
- }
-
- s_spanletvars.izi += s_spanletvars.izistep;
- s_spanletvars.pdest++;
- s_spanletvars.pz++;
- s_spanletvars.s += s_spanletvars.sstep;
- s_spanletvars.t += s_spanletvars.tstep;
- } while (--s_spanletvars.spancount > 0);
-}
-
-/*
-** R_DrawSpanlet33Stipple
-*/
-void R_DrawSpanlet33Stipple( void )
-{
- unsigned btemp;
- byte *pdest = s_spanletvars.pdest;
- short *pz = s_spanletvars.pz;
- int izi = s_spanletvars.izi;
-
- if ( r_polydesc.stipple_parity ^ ( s_spanletvars.v & 1 ) )
- {
- s_spanletvars.pdest += s_spanletvars.spancount;
- s_spanletvars.pz += s_spanletvars.spancount;
-
- if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
- s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
- else
- s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
-
- if ( r_polydesc.stipple_parity ^ ( s_spanletvars.u & 1 ) )
- {
- izi += s_spanletvars.izistep;
- s_spanletvars.s += s_spanletvars.sstep;
- s_spanletvars.t += s_spanletvars.tstep;
-
- pdest++;
- pz++;
- s_spanletvars.spancount--;
- }
-
- s_spanletvars.sstep *= 2;
- s_spanletvars.tstep *= 2;
-
- while ( s_spanletvars.spancount > 0 )
- {
- unsigned s = s_spanletvars.s >> 16;
- unsigned t = s_spanletvars.t >> 16;
-
- btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) );
-
- if ( btemp != 255 )
- {
- if ( *pz <= ( izi >> 16 ) )
- *pdest = btemp;
- }
-
- izi += s_spanletvars.izistep_times_2;
- s_spanletvars.s += s_spanletvars.sstep;
- s_spanletvars.t += s_spanletvars.tstep;
-
- pdest += 2;
- pz += 2;
-
- s_spanletvars.spancount -= 2;
- }
- }
-}
-
-/*
-** R_DrawSpanlet66Stipple
-*/
-void R_DrawSpanlet66Stipple( void )
-{
- unsigned btemp;
- byte *pdest = s_spanletvars.pdest;
- short *pz = s_spanletvars.pz;
- int izi = s_spanletvars.izi;
-
- s_spanletvars.pdest += s_spanletvars.spancount;
- s_spanletvars.pz += s_spanletvars.spancount;
-
- if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE )
- s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS;
- else
- s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep;
-
- if ( r_polydesc.stipple_parity ^ ( s_spanletvars.v & 1 ) )
- {
- if ( r_polydesc.stipple_parity ^ ( s_spanletvars.u & 1 ) )
- {
- izi += s_spanletvars.izistep;
- s_spanletvars.s += s_spanletvars.sstep;
- s_spanletvars.t += s_spanletvars.tstep;
-
- pdest++;
- pz++;
- s_spanletvars.spancount--;
- }
-
- s_spanletvars.sstep *= 2;
- s_spanletvars.tstep *= 2;
-
- while ( s_spanletvars.spancount > 0 )
- {
- unsigned s = s_spanletvars.s >> 16;
- unsigned t = s_spanletvars.t >> 16;
-
- btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) );
-
- if ( btemp != 255 )
- {
- if ( *pz <= ( izi >> 16 ) )
- *pdest = btemp;
- }
-
- izi += s_spanletvars.izistep_times_2;
- s_spanletvars.s += s_spanletvars.sstep;
- s_spanletvars.t += s_spanletvars.tstep;
-
- pdest += 2;
- pz += 2;
-
- s_spanletvars.spancount -= 2;
- }
- }
- else
- {
- while ( s_spanletvars.spancount > 0 )
- {
- unsigned s = s_spanletvars.s >> 16;
- unsigned t = s_spanletvars.t >> 16;
-
- btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) );
-
- if ( btemp != 255 )
- {
- if ( *pz <= ( izi >> 16 ) )
- *pdest = btemp;
- }
-
- izi += s_spanletvars.izistep;
- s_spanletvars.s += s_spanletvars.sstep;
- s_spanletvars.t += s_spanletvars.tstep;
-
- pdest++;
- pz++;
-
- s_spanletvars.spancount--;
- }
- }
-}
-
-/*
-** R_ClipPolyFace
-**
-** Clips the winding at clip_verts[clip_current] and changes clip_current
-** Throws out the back side
-*/
-int R_ClipPolyFace (int nump, clipplane_t *pclipplane)
-{
- int i, outcount;
- float dists[MAXWORKINGVERTS+3];
- float frac, clipdist, *pclipnormal;
- float *in, *instep, *outstep, *vert2;
-
- clipdist = pclipplane->dist;
- pclipnormal = pclipplane->normal;
-
-// calc dists
- if (clip_current)
- {
- in = r_clip_verts[1][0];
- outstep = r_clip_verts[0][0];
- clip_current = 0;
- }
- else
- {
- in = r_clip_verts[0][0];
- outstep = r_clip_verts[1][0];
- clip_current = 1;
- }
-
- instep = in;
- for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
- {
- dists[i] = DotProduct (instep, pclipnormal) - clipdist;
- }
-
-// handle wraparound case
- dists[nump] = dists[0];
- memcpy (instep, in, sizeof (vec5_t));
-
-
-// clip the winding
- instep = in;
- outcount = 0;
-
- for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
- {
- if (dists[i] >= 0)
- {
- memcpy (outstep, instep, sizeof (vec5_t));
- outstep += sizeof (vec5_t) / sizeof (float);
- outcount++;
- }
-
- if (dists[i] == 0 || dists[i+1] == 0)
- continue;
-
- if ( (dists[i] > 0) == (dists[i+1] > 0) )
- continue;
-
- // split it into a new vertex
- frac = dists[i] / (dists[i] - dists[i+1]);
-
- vert2 = instep + sizeof (vec5_t) / sizeof (float);
-
- outstep[0] = instep[0] + frac*(vert2[0] - instep[0]);
- outstep[1] = instep[1] + frac*(vert2[1] - instep[1]);
- outstep[2] = instep[2] + frac*(vert2[2] - instep[2]);
- outstep[3] = instep[3] + frac*(vert2[3] - instep[3]);
- outstep[4] = instep[4] + frac*(vert2[4] - instep[4]);
-
- outstep += sizeof (vec5_t) / sizeof (float);
- outcount++;
- }
-
- return outcount;
-}
-
-/*
-** R_PolygonDrawSpans
-*/
-void R_PolygonDrawSpans(espan_t *pspan, qboolean iswater )
-{
- int count;
- fixed16_t snext, tnext;
- float sdivz, tdivz, zi, z, du, dv, spancountminus1;
- float sdivzspanletstepu, tdivzspanletstepu, zispanletstepu;
-
- s_spanletvars.pbase = cacheblock;
-
- if ( iswater )
- r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
-
- sdivzspanletstepu = d_sdivzstepu * AFFINE_SPANLET_SIZE;
- tdivzspanletstepu = d_tdivzstepu * AFFINE_SPANLET_SIZE;
- zispanletstepu = d_zistepu * AFFINE_SPANLET_SIZE;
-
-// we count on FP exceptions being turned off to avoid range problems
- s_spanletvars.izistep = (int)(d_zistepu * 0x8000 * 0x10000);
- s_spanletvars.izistep_times_2 = s_spanletvars.izistep * 2;
-
- s_spanletvars.pz = 0;
-
- do
- {
- s_spanletvars.pdest = (byte *)d_viewbuffer + ( d_scantable[pspan->v] /*r_screenwidth * pspan->v*/) + pspan->u;
- s_spanletvars.pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
- s_spanletvars.u = pspan->u;
- s_spanletvars.v = pspan->v;
-
- count = pspan->count;
-
- if (count <= 0)
- goto NextSpan;
-
- // calculate the initial s/z, t/z, 1/z, s, and t and clamp
- du = (float)pspan->u;
- dv = (float)pspan->v;
-
- sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
- tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
-
- zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
- z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
- // we count on FP exceptions being turned off to avoid range problems
- s_spanletvars.izi = (int)(zi * 0x8000 * 0x10000);
-
- s_spanletvars.s = (int)(sdivz * z) + sadjust;
- s_spanletvars.t = (int)(tdivz * z) + tadjust;
-
- if ( !iswater )
- {
- if (s_spanletvars.s > bbextents)
- s_spanletvars.s = bbextents;
- else if (s_spanletvars.s < 0)
- s_spanletvars.s = 0;
-
- if (s_spanletvars.t > bbextentt)
- s_spanletvars.t = bbextentt;
- else if (s_spanletvars.t < 0)
- s_spanletvars.t = 0;
- }
-
- do
- {
- // calculate s and t at the far end of the span
- if (count >= AFFINE_SPANLET_SIZE )
- s_spanletvars.spancount = AFFINE_SPANLET_SIZE;
- else
- s_spanletvars.spancount = count;
-
- count -= s_spanletvars.spancount;
-
- if (count)
- {
- // calculate s/z, t/z, zi->fixed s and t at far end of span,
- // calculate s and t steps across span by shifting
- sdivz += sdivzspanletstepu;
- tdivz += tdivzspanletstepu;
- zi += zispanletstepu;
- z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
-
- snext = (int)(sdivz * z) + sadjust;
- tnext = (int)(tdivz * z) + tadjust;
-
- if ( !iswater )
- {
- if (snext > bbextents)
- snext = bbextents;
- else if (snext < AFFINE_SPANLET_SIZE)
- snext = AFFINE_SPANLET_SIZE; // prevent round-off error on <0 steps from
- // from causing overstepping & running off the
- // edge of the texture
-
- if (tnext > bbextentt)
- tnext = bbextentt;
- else if (tnext < AFFINE_SPANLET_SIZE)
- tnext = AFFINE_SPANLET_SIZE; // guard against round-off error on <0 steps
- }
-
- s_spanletvars.sstep = (snext - s_spanletvars.s) >> AFFINE_SPANLET_SIZE_BITS;
- s_spanletvars.tstep = (tnext - s_spanletvars.t) >> AFFINE_SPANLET_SIZE_BITS;
- }
- else
- {
- // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
- // can't step off polygon), clamp, calculate s and t steps across
- // span by division, biasing steps low so we don't run off the
- // texture
- spancountminus1 = (float)(s_spanletvars.spancount - 1);
- sdivz += d_sdivzstepu * spancountminus1;
- tdivz += d_tdivzstepu * spancountminus1;
- zi += d_zistepu * spancountminus1;
- z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
- snext = (int)(sdivz * z) + sadjust;
- tnext = (int)(tdivz * z) + tadjust;
-
- if ( !iswater )
- {
- if (snext > bbextents)
- snext = bbextents;
- else if (snext < AFFINE_SPANLET_SIZE)
- snext = AFFINE_SPANLET_SIZE; // prevent round-off error on <0 steps from
- // from causing overstepping & running off the
- // edge of the texture
-
- if (tnext > bbextentt)
- tnext = bbextentt;
- else if (tnext < AFFINE_SPANLET_SIZE)
- tnext = AFFINE_SPANLET_SIZE; // guard against round-off error on <0 steps
- }
-
- if (s_spanletvars.spancount > 1)
- {
- s_spanletvars.sstep = (snext - s_spanletvars.s) / (s_spanletvars.spancount - 1);
- s_spanletvars.tstep = (tnext - s_spanletvars.t) / (s_spanletvars.spancount - 1);
- }
- }
-
- if ( iswater )
- {
- s_spanletvars.s = s_spanletvars.s & ((CYCLE<<16)-1);
- s_spanletvars.t = s_spanletvars.t & ((CYCLE<<16)-1);
- }
-
- r_polydesc.drawspanlet();
-
- s_spanletvars.s = snext;
- s_spanletvars.t = tnext;
-
- } while (count > 0);
-
-NextSpan:
- pspan++;
-
- } while (pspan->count != DS_SPAN_LIST_END);
-}
-
-/*
-**
-** R_PolygonScanLeftEdge
-**
-** Goes through the polygon and scans the left edge, filling in
-** screen coordinate data for the spans
-*/
-void R_PolygonScanLeftEdge (void)
-{
- int i, v, itop, ibottom, lmaxindex;
- emitpoint_t *pvert, *pnext;
- espan_t *pspan;
- float du, dv, vtop, vbottom, slope;
- fixed16_t u, u_step;
-
- pspan = s_polygon_spans;
- i = s_minindex;
- if (i == 0)
- i = r_polydesc.nump;
-
- lmaxindex = s_maxindex;
- if (lmaxindex == 0)
- lmaxindex = r_polydesc.nump;
-
- vtop = ceil (r_polydesc.pverts[i].v);
-
- do
- {
- pvert = &r_polydesc.pverts[i];
- pnext = pvert - 1;
-
- vbottom = ceil (pnext->v);
-
- if (vtop < vbottom)
- {
- du = pnext->u - pvert->u;
- dv = pnext->v - pvert->v;
-
- slope = du / dv;
- u_step = (int)(slope * 0x10000);
- // adjust u to ceil the integer portion
- u = (int)((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) +
- (0x10000 - 1);
- itop = (int)vtop;
- ibottom = (int)vbottom;
-
- for (v=itop ; v<ibottom ; v++)
- {
- pspan->u = u >> 16;
- pspan->v = v;
- u += u_step;
- pspan++;
- }
- }
-
- vtop = vbottom;
-
- i--;
- if (i == 0)
- i = r_polydesc.nump;
-
- } while (i != lmaxindex);
-}
-
-/*
-** R_PolygonScanRightEdge
-**
-** Goes through the polygon and scans the right edge, filling in
-** count values.
-*/
-void R_PolygonScanRightEdge (void)
-{
- int i, v, itop, ibottom;
- emitpoint_t *pvert, *pnext;
- espan_t *pspan;
- float du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext;
- fixed16_t u, u_step;
-
- pspan = s_polygon_spans;
- i = s_minindex;
-
- vvert = r_polydesc.pverts[i].v;
- if (vvert < r_refdef.fvrecty_adj)
- vvert = r_refdef.fvrecty_adj;
- if (vvert > r_refdef.fvrectbottom_adj)
- vvert = r_refdef.fvrectbottom_adj;
-
- vtop = ceil (vvert);
-
- do
- {
- pvert = &r_polydesc.pverts[i];
- pnext = pvert + 1;
-
- vnext = pnext->v;
- if (vnext < r_refdef.fvrecty_adj)
- vnext = r_refdef.fvrecty_adj;
- if (vnext > r_refdef.fvrectbottom_adj)
- vnext = r_refdef.fvrectbottom_adj;
-
- vbottom = ceil (vnext);
-
- if (vtop < vbottom)
- {
- uvert = pvert->u;
- if (uvert < r_refdef.fvrectx_adj)
- uvert = r_refdef.fvrectx_adj;
- if (uvert > r_refdef.fvrectright_adj)
- uvert = r_refdef.fvrectright_adj;
-
- unext = pnext->u;
- if (unext < r_refdef.fvrectx_adj)
- unext = r_refdef.fvrectx_adj;
- if (unext > r_refdef.fvrectright_adj)
- unext = r_refdef.fvrectright_adj;
-
- du = unext - uvert;
- dv = vnext - vvert;
- slope = du / dv;
- u_step = (int)(slope * 0x10000);
- // adjust u to ceil the integer portion
- u = (int)((uvert + (slope * (vtop - vvert))) * 0x10000) +
- (0x10000 - 1);
- itop = (int)vtop;
- ibottom = (int)vbottom;
-
- for (v=itop ; v<ibottom ; v++)
- {
- pspan->count = (u >> 16) - pspan->u;
- u += u_step;
- pspan++;
- }
- }
-
- vtop = vbottom;
- vvert = vnext;
-
- i++;
- if (i == r_polydesc.nump)
- i = 0;
-
- } while (i != s_maxindex);
-
- pspan->count = DS_SPAN_LIST_END; // mark the end of the span list
-}
-
-/*
-** R_ClipAndDrawPoly
-*/
-void R_ClipAndDrawPoly( float alpha, qboolean isturbulent, qboolean textured )
-{
- emitpoint_t outverts[MAXWORKINGVERTS+3], *pout;
- float *pv;
- int i, nump;
- float scale;
- vec3_t transformed, local;
-
- if ( !textured )
- {
- r_polydesc.drawspanlet = R_DrawSpanletConstant33;
- }
- else
- {
-
- /*
- ** choose the correct spanlet routine based on alpha
- */
- if ( alpha == 1 )
- {
- // isturbulent is ignored because we know that turbulent surfaces
- // can't be opaque
- r_polydesc.drawspanlet = R_DrawSpanletOpaque;
- }
- else
- {
- if ( sw_stipplealpha->value )
- {
- if ( isturbulent )
- {
- if ( alpha > 0.33 )
- r_polydesc.drawspanlet = R_DrawSpanletTurbulentStipple66;
- else
- r_polydesc.drawspanlet = R_DrawSpanletTurbulentStipple33;
- }
- else
- {
- if ( alpha > 0.33 )
- r_polydesc.drawspanlet = R_DrawSpanlet66Stipple;
- else
- r_polydesc.drawspanlet = R_DrawSpanlet33Stipple;
- }
- }
- else
- {
- if ( isturbulent )
- {
- if ( alpha > 0.33 )
- r_polydesc.drawspanlet = R_DrawSpanletTurbulentBlended66;
- else
- r_polydesc.drawspanlet = R_DrawSpanletTurbulentBlended33;
- }
- else
- {
- if ( alpha > 0.33 )
- r_polydesc.drawspanlet = R_DrawSpanlet66;
- else
- r_polydesc.drawspanlet = R_DrawSpanlet33;
- }
- }
- }
- }
-
- // clip to the frustum in worldspace
- nump = r_polydesc.nump;
- clip_current = 0;
-
- for (i=0 ; i<4 ; i++)
- {
- nump = R_ClipPolyFace (nump, &view_clipplanes[i]);
- if (nump < 3)
- return;
- if (nump > MAXWORKINGVERTS)
- ri.Sys_Error(ERR_DROP, "R_ClipAndDrawPoly: too many points: %d", nump );
- }
-
-// transform vertices into viewspace and project
- pv = &r_clip_verts[clip_current][0][0];
-
- for (i=0 ; i<nump ; i++)
- {
- VectorSubtract (pv, r_origin, local);
- TransformVector (local, transformed);
-
- if (transformed[2] < NEAR_CLIP)
- transformed[2] = NEAR_CLIP;
-
- pout = &outverts[i];
- pout->zi = 1.0 / transformed[2];
-
- pout->s = pv[3];
- pout->t = pv[4];
-
- scale = xscale * pout->zi;
- pout->u = (xcenter + scale * transformed[0]);
-
- scale = yscale * pout->zi;
- pout->v = (ycenter - scale * transformed[1]);
-
- pv += sizeof (vec5_t) / sizeof (*pv);
- }
-
-// draw it
- r_polydesc.nump = nump;
- r_polydesc.pverts = outverts;
-
- R_DrawPoly( isturbulent );
-}
-
-/*
-** R_BuildPolygonFromSurface
-*/
-void R_BuildPolygonFromSurface(msurface_t *fa)
-{
- int i, lindex, lnumverts;
- medge_t *pedges, *r_pedge;
- float *vec;
- vec5_t *pverts;
- float tmins[2] = { 0, 0 };
-
- r_polydesc.nump = 0;
-
- // reconstruct the polygon
- pedges = currentmodel->edges;
- lnumverts = fa->numedges;
-
- pverts = r_clip_verts[0];
-
- for (i=0 ; i<lnumverts ; i++)
- {
- lindex = currentmodel->surfedges[fa->firstedge + i];
-
- if (lindex > 0)
- {
- r_pedge = &pedges[lindex];
- vec = currentmodel->vertexes[r_pedge->v[0]].position;
- }
- else
- {
- r_pedge = &pedges[-lindex];
- vec = currentmodel->vertexes[r_pedge->v[1]].position;
- }
-
- VectorCopy (vec, pverts[i] );
- }
-
- VectorCopy( fa->texinfo->vecs[0], r_polydesc.vright );
- VectorCopy( fa->texinfo->vecs[1], r_polydesc.vup );
- VectorCopy( fa->plane->normal, r_polydesc.vpn );
- VectorCopy( r_origin, r_polydesc.viewer_position );
-
- if ( fa->flags & SURF_PLANEBACK )
- {
- VectorSubtract( vec3_origin, r_polydesc.vpn, r_polydesc.vpn );
- }
-
- if ( fa->texinfo->flags & SURF_WARP )
- {
- r_polydesc.pixels = fa->texinfo->image->pixels[0];
- r_polydesc.pixel_width = fa->texinfo->image->width;
- r_polydesc.pixel_height = fa->texinfo->image->height;
- }
- else
- {
- surfcache_t *scache;
-
- scache = D_CacheSurface( fa, 0 );
-
- r_polydesc.pixels = scache->data;
- r_polydesc.pixel_width = scache->width;
- r_polydesc.pixel_height = scache->height;
-
- tmins[0] = fa->texturemins[0];
- tmins[1] = fa->texturemins[1];
- }
-
- r_polydesc.dist = DotProduct( r_polydesc.vpn, pverts[0] );
-
- r_polydesc.s_offset = fa->texinfo->vecs[0][3] - tmins[0];
- r_polydesc.t_offset = fa->texinfo->vecs[1][3] - tmins[1];
-
- // scrolling texture addition
- if (fa->texinfo->flags & SURF_FLOWING)
- {
- r_polydesc.s_offset += -128 * ( (r_newrefdef.time*0.25) - (int)(r_newrefdef.time*0.25) );
- }
-
- r_polydesc.nump = lnumverts;
-}
-
-/*
-** R_PolygonCalculateGradients
-*/
-void R_PolygonCalculateGradients (void)
-{
- vec3_t p_normal, p_saxis, p_taxis;
- float distinv;
-
- TransformVector (r_polydesc.vpn, p_normal);
- TransformVector (r_polydesc.vright, p_saxis);
- TransformVector (r_polydesc.vup, p_taxis);
-
- distinv = 1.0 / (-(DotProduct (r_polydesc.viewer_position, r_polydesc.vpn)) + r_polydesc.dist );
-
- d_sdivzstepu = p_saxis[0] * xscaleinv;
- d_sdivzstepv = -p_saxis[1] * yscaleinv;
- d_sdivzorigin = p_saxis[2] - xcenter * d_sdivzstepu - ycenter * d_sdivzstepv;
-
- d_tdivzstepu = p_taxis[0] * xscaleinv;
- d_tdivzstepv = -p_taxis[1] * yscaleinv;
- d_tdivzorigin = p_taxis[2] - xcenter * d_tdivzstepu - ycenter * d_tdivzstepv;
-
- d_zistepu = p_normal[0] * xscaleinv * distinv;
- d_zistepv = -p_normal[1] * yscaleinv * distinv;
- d_ziorigin = p_normal[2] * distinv - xcenter * d_zistepu - ycenter * d_zistepv;
-
- sadjust = (fixed16_t) ( ( DotProduct( r_polydesc.viewer_position, r_polydesc.vright) + r_polydesc.s_offset ) * 0x10000 );
- tadjust = (fixed16_t) ( ( DotProduct( r_polydesc.viewer_position, r_polydesc.vup ) + r_polydesc.t_offset ) * 0x10000 );
-
-// -1 (-epsilon) so we never wander off the edge of the texture
- bbextents = (r_polydesc.pixel_width << 16) - 1;
- bbextentt = (r_polydesc.pixel_height << 16) - 1;
-}
-
-/*
-** R_DrawPoly
-**
-** Polygon drawing function. Uses the polygon described in r_polydesc
-** to calculate edges and gradients, then renders the resultant spans.
-**
-** This should NOT be called externally since it doesn't do clipping!
-*/
-static void R_DrawPoly( qboolean iswater )
-{
- int i, nump;
- float ymin, ymax;
- emitpoint_t *pverts;
- espan_t spans[MAXHEIGHT+1];
-
- s_polygon_spans = spans;
-
-// find the top and bottom vertices, and make sure there's at least one scan to
-// draw
- ymin = 999999.9;
- ymax = -999999.9;
- pverts = r_polydesc.pverts;
-
- for (i=0 ; i<r_polydesc.nump ; i++)
- {
- if (pverts->v < ymin)
- {
- ymin = pverts->v;
- s_minindex = i;
- }
-
- if (pverts->v > ymax)
- {
- ymax = pverts->v;
- s_maxindex = i;
- }
-
- pverts++;
- }
-
- ymin = ceil (ymin);
- ymax = ceil (ymax);
-
- if (ymin >= ymax)
- return; // doesn't cross any scans at all
-
- cachewidth = r_polydesc.pixel_width;
- cacheblock = r_polydesc.pixels;
-
-// copy the first vertex to the last vertex, so we don't have to deal with
-// wrapping
- nump = r_polydesc.nump;
- pverts = r_polydesc.pverts;
- pverts[nump] = pverts[0];
-
- R_PolygonCalculateGradients ();
- R_PolygonScanLeftEdge ();
- R_PolygonScanRightEdge ();
-
- R_PolygonDrawSpans( s_polygon_spans, iswater );
-}
-
-/*
-** R_DrawAlphaSurfaces
-*/
-void R_DrawAlphaSurfaces( void )
-{
- msurface_t *s = r_alpha_surfaces;
-
- currentmodel = r_worldmodel;
-
- modelorg[0] = -r_origin[0];
- modelorg[1] = -r_origin[1];
- modelorg[2] = -r_origin[2];
-
- while ( s )
- {
- R_BuildPolygonFromSurface( s );
-
- if (s->texinfo->flags & SURF_TRANS66)
- R_ClipAndDrawPoly( 0.60f, ( s->texinfo->flags & SURF_WARP) != 0, true );
- else
- R_ClipAndDrawPoly( 0.30f, ( s->texinfo->flags & SURF_WARP) != 0, true );
-
- s = s->nextalphasurface;
- }
-
- r_alpha_surfaces = NULL;
-}
-
-/*
-** R_IMFlatShadedQuad
-*/
-void R_IMFlatShadedQuad( vec3_t a, vec3_t b, vec3_t c, vec3_t d, int color, float alpha )
-{
- vec3_t s0, s1;
-
- r_polydesc.nump = 4;
- VectorCopy( r_origin, r_polydesc.viewer_position );
-
- VectorCopy( a, r_clip_verts[0][0] );
- VectorCopy( b, r_clip_verts[0][1] );
- VectorCopy( c, r_clip_verts[0][2] );
- VectorCopy( d, r_clip_verts[0][3] );
-
- r_clip_verts[0][0][3] = 0;
- r_clip_verts[0][1][3] = 0;
- r_clip_verts[0][2][3] = 0;
- r_clip_verts[0][3][3] = 0;
-
- r_clip_verts[0][0][4] = 0;
- r_clip_verts[0][1][4] = 0;
- r_clip_verts[0][2][4] = 0;
- r_clip_verts[0][3][4] = 0;
-
- VectorSubtract( d, c, s0 );
- VectorSubtract( c, b, s1 );
- CrossProduct( s0, s1, r_polydesc.vpn );
- VectorNormalize( r_polydesc.vpn );
-
- r_polydesc.dist = DotProduct( r_polydesc.vpn, r_clip_verts[0][0] );
-
- r_polyblendcolor = color;
-
- R_ClipAndDrawPoly( alpha, false, false );
-}
-
--- a/ref/r_polyse.c
+++ /dev/null
@@ -1,1146 +1,0 @@
-// d_polyset.c: routines for drawing sets of polygons sharing the same
-// texture (used for Alias models)
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-int rand1k[] = {
-#include "rand1k.h"
-};
-
-#define MASK_1K 0x3FF
-
-int rand1k_index = 0;
-
-// TODO: put in span spilling to shrink list size
-// !!! if this is changed, it must be changed in d_polysa.s too !!!
-#define DPS_MAXSPANS MAXHEIGHT+1
- // 1 extra for spanpackage that marks end
-
-// !!! if this is changed, it must be changed in asm_draw.h too !!!
-typedef struct {
- void *pdest;
- short *pz;
- int count;
- byte *ptex;
- int sfrac, tfrac, light, zi;
-} spanpackage_t;
-
-typedef struct {
- int isflattop;
- int numleftedges;
- int *pleftedgevert0;
- int *pleftedgevert1;
- int *pleftedgevert2;
- int numrightedges;
- int *prightedgevert0;
- int *prightedgevert1;
- int *prightedgevert2;
-} edgetable;
-
-aliastriangleparms_t aliastriangleparms;
-
-int r_p0[6], r_p1[6], r_p2[6];
-
-byte *d_pcolormap;
-
-int d_aflatcolor;
-int d_xdenom;
-
-edgetable *pedgetable;
-
-edgetable edgetables[12] = {
- {0, 1, r_p0, r_p2, NULL, 2, r_p0, r_p1, r_p2 },
- {0, 2, r_p1, r_p0, r_p2, 1, r_p1, r_p2, NULL},
- {1, 1, r_p0, r_p2, NULL, 1, r_p1, r_p2, NULL},
- {0, 1, r_p1, r_p0, NULL, 2, r_p1, r_p2, r_p0 },
- {0, 2, r_p0, r_p2, r_p1, 1, r_p0, r_p1, NULL},
- {0, 1, r_p2, r_p1, NULL, 1, r_p2, r_p0, NULL},
- {0, 1, r_p2, r_p1, NULL, 2, r_p2, r_p0, r_p1 },
- {0, 2, r_p2, r_p1, r_p0, 1, r_p2, r_p0, NULL},
- {0, 1, r_p1, r_p0, NULL, 1, r_p1, r_p2, NULL},
- {1, 1, r_p2, r_p1, NULL, 1, r_p0, r_p1, NULL},
- {1, 1, r_p1, r_p0, NULL, 1, r_p2, r_p0, NULL},
- {0, 1, r_p0, r_p2, NULL, 1, r_p0, r_p1, NULL},
-};
-
-// FIXME: some of these can become statics
-int a_sstepxfrac, a_tstepxfrac, r_lstepx, a_ststepxwhole;
-int r_sstepx, r_tstepx, r_lstepy, r_sstepy, r_tstepy;
-int r_zistepx, r_zistepy;
-int d_aspancount, d_countextrastep;
-
-spanpackage_t *a_spans;
-spanpackage_t *d_pedgespanpackage;
-static int ystart;
-byte *d_pdest, *d_ptex;
-short *d_pz;
-int d_sfrac, d_tfrac, d_light, d_zi;
-int d_ptexextrastep, d_sfracextrastep;
-int d_tfracextrastep, d_lightextrastep, d_pdestextrastep;
-int d_lightbasestep, d_pdestbasestep, d_ptexbasestep;
-int d_sfracbasestep, d_tfracbasestep;
-int d_ziextrastep, d_zibasestep;
-int d_pzextrastep, d_pzbasestep;
-
-typedef struct {
- int quotient;
- int remainder;
-} adivtab_t;
-
-static adivtab_t adivtab[32*32] = {
-#include "adivtab.h"
-};
-
-byte *skintable[MAX_LBM_HEIGHT];
-int skinwidth;
-byte *skinstart;
-
-void (*d_pdrawspans)(spanpackage_t *pspanpackage);
-
-void R_PolysetDrawSpans8_33 (spanpackage_t *pspanpackage);
-void R_PolysetDrawSpans8_66 (spanpackage_t *pspanpackage);
-void R_PolysetDrawSpans8_Opaque (spanpackage_t *pspanpackage);
-
-void R_PolysetDrawThreshSpans8 (spanpackage_t *pspanpackage);
-void R_PolysetCalcGradients (int skinwidth);
-void R_DrawNonSubdiv (void);
-void R_PolysetSetEdgeTable (void);
-void R_RasterizeAliasPolySmooth (void);
-void R_PolysetScanLeftEdge(int height);
-void R_PolysetScanLeftEdge_C(int height);
-
-// ======================
-// PGM
-// 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
-byte iractive = 0;
-byte irtable[256] = { 79, 78, 77, 76, 75, 74, 73, 72, // black/white
- 71, 70, 69, 68, 67, 66, 65, 64,
- 64, 65, 66, 67, 68, 69, 70, 71, // dark taupe
- 72, 73, 74, 75, 76, 77, 78, 79,
-
- 64, 65, 66, 67, 68, 69, 70, 71, // slate grey
- 72, 73, 74, 75, 76, 77, 78, 79,
- 208, 208, 208, 208, 208, 208, 208, 208, // unused?'
- 64, 66, 68, 70, 72, 74, 76, 78, // dark yellow
-
- 64, 65, 66, 67, 68, 69, 70, 71, // dark red
- 72, 73, 74, 75, 76, 77, 78, 79,
- 64, 65, 66, 67, 68, 69, 70, 71, // grey/tan
- 72, 73, 74, 75, 76, 77, 78, 79,
-
- 64, 66, 68, 70, 72, 74, 76, 78, // chocolate
- 68, 67, 66, 65, 64, 65, 66, 67, // mauve / teal
- 68, 69, 70, 71, 72, 73, 74, 75,
- 76, 76, 77, 77, 78, 78, 79, 79,
-
- 64, 65, 66, 67, 68, 69, 70, 71, // more mauve
- 72, 73, 74, 75, 76, 77, 78, 79,
- 64, 65, 66, 67, 68, 69, 70, 71, // olive
- 72, 73, 74, 75, 76, 77, 78, 79,
-
- 64, 65, 66, 67, 68, 69, 70, 71, // maroon
- 72, 73, 74, 75, 76, 77, 78, 79,
- 64, 65, 66, 67, 68, 69, 70, 71, // sky blue
- 72, 73, 74, 75, 76, 77, 78, 79,
-
- 64, 65, 66, 67, 68, 69, 70, 71, // olive again
- 72, 73, 74, 75, 76, 77, 78, 79,
- 64, 65, 66, 67, 68, 69, 70, 71, // nuclear green
- 64, 65, 66, 67, 68, 69, 70, 71, // bright yellow
-
- 64, 65, 66, 67, 68, 69, 70, 71, // fire colors
- 72, 73, 74, 75, 76, 77, 78, 79,
- 208, 208, 64, 64, 70, 71, 72, 64, // mishmash1
- 66, 68, 70, 64, 65, 66, 67, 68}; // mishmash2
-// PGM
-// ======================
-
-/*
-================
-R_PolysetUpdateTables
-================
-*/
-void R_PolysetUpdateTables (void)
-{
- int i;
- byte *s;
-
- if (r_affinetridesc.skinwidth != skinwidth ||
- r_affinetridesc.pskin != skinstart)
- {
- skinwidth = r_affinetridesc.skinwidth;
- skinstart = r_affinetridesc.pskin;
- s = skinstart;
- for (i=0 ; i<MAX_LBM_HEIGHT ; i++, s+=skinwidth)
- skintable[i] = s;
- }
-}
-
-
-/*
-================
-R_DrawTriangle
-================
-*/
-void R_DrawTriangle( void )
-{
- spanpackage_t spans[DPS_MAXSPANS];
-
- int dv1_ab, dv0_ac;
- int dv0_ab, dv1_ac;
-
- /*
- d_xdenom = ( aliastriangleparms.a->v[1] - aliastriangleparms.b->v[1] ) * ( aliastriangleparms.a->v[0] - aliastriangleparms.c->v[0] ) -
- ( aliastriangleparms.a->v[0] - aliastriangleparms.b->v[0] ) * ( aliastriangleparms.a->v[1] - aliastriangleparms.c->v[1] );
- */
-
- dv0_ab = aliastriangleparms.a->u - aliastriangleparms.b->u;
- dv1_ab = aliastriangleparms.a->v - aliastriangleparms.b->v;
-
- if ( !( dv0_ab | dv1_ab ) )
- return;
-
- dv0_ac = aliastriangleparms.a->u - aliastriangleparms.c->u;
- dv1_ac = aliastriangleparms.a->v - aliastriangleparms.c->v;
-
- if ( !( dv0_ac | dv1_ac ) )
- return;
-
- d_xdenom = ( dv0_ac * dv1_ab ) - ( dv0_ab * dv1_ac );
-
- if ( d_xdenom < 0 )
- {
- a_spans = spans;
-
- r_p0[0] = aliastriangleparms.a->u; // u
- r_p0[1] = aliastriangleparms.a->v; // v
- r_p0[2] = aliastriangleparms.a->s; // s
- r_p0[3] = aliastriangleparms.a->t; // t
- r_p0[4] = aliastriangleparms.a->l; // light
- r_p0[5] = aliastriangleparms.a->zi; // iz
-
- r_p1[0] = aliastriangleparms.b->u;
- r_p1[1] = aliastriangleparms.b->v;
- r_p1[2] = aliastriangleparms.b->s;
- r_p1[3] = aliastriangleparms.b->t;
- r_p1[4] = aliastriangleparms.b->l;
- r_p1[5] = aliastriangleparms.b->zi;
-
- r_p2[0] = aliastriangleparms.c->u;
- r_p2[1] = aliastriangleparms.c->v;
- r_p2[2] = aliastriangleparms.c->s;
- r_p2[3] = aliastriangleparms.c->t;
- r_p2[4] = aliastriangleparms.c->l;
- r_p2[5] = aliastriangleparms.c->zi;
-
- R_PolysetSetEdgeTable ();
- R_RasterizeAliasPolySmooth ();
- }
-}
-
-
-/*
-===================
-R_PolysetScanLeftEdge_C
-====================
-*/
-void R_PolysetScanLeftEdge_C(int height)
-{
- do
- {
- d_pedgespanpackage->pdest = d_pdest;
- d_pedgespanpackage->pz = d_pz;
- d_pedgespanpackage->count = d_aspancount;
- d_pedgespanpackage->ptex = d_ptex;
-
- d_pedgespanpackage->sfrac = d_sfrac;
- d_pedgespanpackage->tfrac = d_tfrac;
-
- // FIXME: need to clamp l, s, t, at both ends?
- d_pedgespanpackage->light = d_light;
- d_pedgespanpackage->zi = d_zi;
-
- d_pedgespanpackage++;
-
- errorterm += erroradjustup;
- if (errorterm >= 0)
- {
- d_pdest += d_pdestextrastep;
- d_pz += d_pzextrastep;
- d_aspancount += d_countextrastep;
- d_ptex += d_ptexextrastep;
- d_sfrac += d_sfracextrastep;
- d_ptex += d_sfrac >> 16;
-
- d_sfrac &= 0xFFFF;
- d_tfrac += d_tfracextrastep;
- if (d_tfrac & 0x10000)
- {
- d_ptex += r_affinetridesc.skinwidth;
- d_tfrac &= 0xFFFF;
- }
- d_light += d_lightextrastep;
- d_zi += d_ziextrastep;
- errorterm -= erroradjustdown;
- }
- else
- {
- d_pdest += d_pdestbasestep;
- d_pz += d_pzbasestep;
- d_aspancount += ubasestep;
- d_ptex += d_ptexbasestep;
- d_sfrac += d_sfracbasestep;
- d_ptex += d_sfrac >> 16;
- d_sfrac &= 0xFFFF;
- d_tfrac += d_tfracbasestep;
- if (d_tfrac & 0x10000)
- {
- d_ptex += r_affinetridesc.skinwidth;
- d_tfrac &= 0xFFFF;
- }
- d_light += d_lightbasestep;
- d_zi += d_zibasestep;
- }
- } while (--height);
-}
-
-/*
-===================
-FloorDivMod
-
-Returns mathematically correct (floor-based) quotient and remainder for
-numer and denom, both of which should contain no fractional part. The
-quotient must fit in 32 bits.
-FIXME: GET RID OF THIS! (FloorDivMod)
-====================
-*/
-void FloorDivMod (float numer, float denom, int *quotient,
- int *rem)
-{
- int q, r;
- float x;
-
- if (numer >= 0.0)
- {
-
- x = floor(numer / denom);
- q = (int)x;
- r = (int)floor(numer - (x * denom));
- }
- else
- {
- //
- // perform operations with positive values, and fix mod to make floor-based
- //
- x = floor(-numer / denom);
- q = -(int)x;
- r = (int)floor(-numer - (x * denom));
- if (r != 0)
- {
- q--;
- r = (int)denom - r;
- }
- }
-
- *quotient = q;
- *rem = r;
-}
-
-
-/*
-===================
-R_PolysetSetUpForLineScan
-====================
-*/
-void R_PolysetSetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv,
- fixed8_t endvertu, fixed8_t endvertv)
-{
- float dm, dn;
- int tm, tn;
- adivtab_t *ptemp;
-
-// TODO: implement x86 version
-
- errorterm = -1;
-
- tm = endvertu - startvertu;
- tn = endvertv - startvertv;
-
- if (((tm <= 16) && (tm >= -15)) &&
- ((tn <= 16) && (tn >= -15)))
- {
- ptemp = &adivtab[((tm+15) << 5) + (tn+15)];
- ubasestep = ptemp->quotient;
- erroradjustup = ptemp->remainder;
- erroradjustdown = tn;
- }
- else
- {
- dm = tm;
- dn = tn;
-
- FloorDivMod (dm, dn, &ubasestep, &erroradjustup);
-
- erroradjustdown = dn;
- }
-}
-
-
-
-/*
-================
-R_PolysetCalcGradients
-================
-*/
-void R_PolysetCalcGradients (int skinwidth)
-{
- float xstepdenominv, ystepdenominv, t0, t1;
- float p01_minus_p21, p11_minus_p21, p00_minus_p20, p10_minus_p20;
-
- p00_minus_p20 = r_p0[0] - r_p2[0];
- p01_minus_p21 = r_p0[1] - r_p2[1];
- p10_minus_p20 = r_p1[0] - r_p2[0];
- p11_minus_p21 = r_p1[1] - r_p2[1];
-
- xstepdenominv = 1.0 / (float)d_xdenom;
-
- ystepdenominv = -xstepdenominv;
-
-// ceil () for light so positive steps are exaggerated, negative steps
-// diminished, pushing us away from underflow toward overflow. Underflow is
-// very visible, overflow is very unlikely, because of ambient lighting
- t0 = r_p0[4] - r_p2[4];
- t1 = r_p1[4] - r_p2[4];
- r_lstepx = (int)
- ceil((t1 * p01_minus_p21 - t0 * p11_minus_p21) * xstepdenominv);
- r_lstepy = (int)
- ceil((t1 * p00_minus_p20 - t0 * p10_minus_p20) * ystepdenominv);
-
- t0 = r_p0[2] - r_p2[2];
- t1 = r_p1[2] - r_p2[2];
- r_sstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
- xstepdenominv);
- r_sstepy = (int)((t1 * p00_minus_p20 - t0* p10_minus_p20) *
- ystepdenominv);
-
- t0 = r_p0[3] - r_p2[3];
- t1 = r_p1[3] - r_p2[3];
- r_tstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
- xstepdenominv);
- r_tstepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) *
- ystepdenominv);
-
- t0 = r_p0[5] - r_p2[5];
- t1 = r_p1[5] - r_p2[5];
- r_zistepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
- xstepdenominv);
- r_zistepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) *
- ystepdenominv);
-
- a_sstepxfrac = r_sstepx & 0xFFFF;
- a_tstepxfrac = r_tstepx & 0xFFFF;
-
- a_ststepxwhole = skinwidth * (r_tstepx >> 16) + (r_sstepx >> 16);
-}
-
-/*
-================
-R_PolysetDrawThreshSpans8
-
-Random fizzle fade rasterizer
-================
-*/
-void R_PolysetDrawThreshSpans8 (spanpackage_t *pspanpackage)
-{
- int lcount;
- byte *lpdest;
- byte *lptex;
- int lsfrac, ltfrac;
- int llight;
- int lzi;
- short *lpz;
-
- do
- {
- lcount = d_aspancount - pspanpackage->count;
-
- errorterm += erroradjustup;
- if (errorterm >= 0)
- {
- d_aspancount += d_countextrastep;
- errorterm -= erroradjustdown;
- }
- else
- {
- d_aspancount += ubasestep;
- }
-
- if (lcount)
- {
- lpdest = pspanpackage->pdest;
- lptex = pspanpackage->ptex;
- lpz = pspanpackage->pz;
- lsfrac = pspanpackage->sfrac;
- ltfrac = pspanpackage->tfrac;
- llight = pspanpackage->light;
- lzi = pspanpackage->zi;
-
- do
- {
- if ((lzi >> 16) >= *lpz)
- {
- rand1k_index = (rand1k_index + 1) & MASK_1K;
-
- if (rand1k[rand1k_index] <= r_affinetridesc.vis_thresh)
- {
- *lpdest = ((byte *)vid.colormap)[*lptex + (llight & 0xFF00)];
- *lpz = lzi >> 16;
- }
- }
-
- lpdest++;
- lzi += r_zistepx;
- lpz++;
- llight += r_lstepx;
- lptex += a_ststepxwhole;
- lsfrac += a_sstepxfrac;
- lptex += lsfrac >> 16;
- lsfrac &= 0xFFFF;
- ltfrac += a_tstepxfrac;
- if (ltfrac & 0x10000)
- {
- lptex += r_affinetridesc.skinwidth;
- ltfrac &= 0xFFFF;
- }
- } while (--lcount);
- }
-
- pspanpackage++;
- } while (pspanpackage->count != -999999);
-}
-
-
-/*
-================
-R_PolysetDrawSpans8
-================
-*/
-void R_PolysetDrawSpans8_33( spanpackage_t *pspanpackage)
-{
- int lcount;
- byte *lpdest;
- byte *lptex;
- int lsfrac, ltfrac;
- int llight;
- int lzi;
- short *lpz;
-
- do
- {
- lcount = d_aspancount - pspanpackage->count;
-
- errorterm += erroradjustup;
- if (errorterm >= 0)
- {
- d_aspancount += d_countextrastep;
- errorterm -= erroradjustdown;
- }
- else
- {
- d_aspancount += ubasestep;
- }
-
- if (lcount)
- {
- lpdest = pspanpackage->pdest;
- lptex = pspanpackage->ptex;
- lpz = pspanpackage->pz;
- lsfrac = pspanpackage->sfrac;
- ltfrac = pspanpackage->tfrac;
- llight = pspanpackage->light;
- lzi = pspanpackage->zi;
-
- do
- {
- if ((lzi >> 16) >= *lpz)
- {
- int temp = vid.colormap[*lptex + ( llight & 0xFF00 )];
-
- *lpdest = vid.alphamap[temp+ *lpdest*256];
- }
- lpdest++;
- lzi += r_zistepx;
- lpz++;
- llight += r_lstepx;
- lptex += a_ststepxwhole;
- lsfrac += a_sstepxfrac;
- lptex += lsfrac >> 16;
- lsfrac &= 0xFFFF;
- ltfrac += a_tstepxfrac;
- if (ltfrac & 0x10000)
- {
- lptex += r_affinetridesc.skinwidth;
- ltfrac &= 0xFFFF;
- }
- } while (--lcount);
- }
-
- pspanpackage++;
- } while (pspanpackage->count != -999999);
-}
-
-void R_PolysetDrawSpansConstant8_33( spanpackage_t *pspanpackage)
-{
- int lcount;
- byte *lpdest;
- int lzi;
- short *lpz;
-
- do
- {
- lcount = d_aspancount - pspanpackage->count;
-
- errorterm += erroradjustup;
- if (errorterm >= 0)
- {
- d_aspancount += d_countextrastep;
- errorterm -= erroradjustdown;
- }
- else
- {
- d_aspancount += ubasestep;
- }
-
- if (lcount)
- {
- lpdest = pspanpackage->pdest;
- lpz = pspanpackage->pz;
- lzi = pspanpackage->zi;
-
- do
- {
- if ((lzi >> 16) >= *lpz)
- {
- *lpdest = vid.alphamap[r_aliasblendcolor + *lpdest*256];
- }
- lpdest++;
- lzi += r_zistepx;
- lpz++;
- } while (--lcount);
- }
-
- pspanpackage++;
- } while (pspanpackage->count != -999999);
-}
-
-void R_PolysetDrawSpans8_66(spanpackage_t *pspanpackage)
-{
- int lcount;
- byte *lpdest;
- byte *lptex;
- int lsfrac, ltfrac;
- int llight;
- int lzi;
- short *lpz;
-
- do
- {
- lcount = d_aspancount - pspanpackage->count;
-
- errorterm += erroradjustup;
- if (errorterm >= 0)
- {
- d_aspancount += d_countextrastep;
- errorterm -= erroradjustdown;
- }
- else
- {
- d_aspancount += ubasestep;
- }
-
- if (lcount)
- {
- lpdest = pspanpackage->pdest;
- lptex = pspanpackage->ptex;
- lpz = pspanpackage->pz;
- lsfrac = pspanpackage->sfrac;
- ltfrac = pspanpackage->tfrac;
- llight = pspanpackage->light;
- lzi = pspanpackage->zi;
-
- do
- {
- if ((lzi >> 16) >= *lpz)
- {
- int temp = vid.colormap[*lptex + ( llight & 0xFF00 )];
-
- *lpdest = vid.alphamap[temp*256 + *lpdest];
- *lpz = lzi >> 16;
- }
- lpdest++;
- lzi += r_zistepx;
- lpz++;
- llight += r_lstepx;
- lptex += a_ststepxwhole;
- lsfrac += a_sstepxfrac;
- lptex += lsfrac >> 16;
- lsfrac &= 0xFFFF;
- ltfrac += a_tstepxfrac;
- if (ltfrac & 0x10000)
- {
- lptex += r_affinetridesc.skinwidth;
- ltfrac &= 0xFFFF;
- }
- } while (--lcount);
- }
-
- pspanpackage++;
- } while (pspanpackage->count != -999999);
-}
-
-void R_PolysetDrawSpansConstant8_66( spanpackage_t *pspanpackage)
-{
- int lcount;
- byte *lpdest;
- int lzi;
- short *lpz;
-
- do
- {
- lcount = d_aspancount - pspanpackage->count;
-
- errorterm += erroradjustup;
- if (errorterm >= 0)
- {
- d_aspancount += d_countextrastep;
- errorterm -= erroradjustdown;
- }
- else
- {
- d_aspancount += ubasestep;
- }
-
- if (lcount)
- {
- lpdest = pspanpackage->pdest;
- lpz = pspanpackage->pz;
- lzi = pspanpackage->zi;
-
- do
- {
- if ((lzi >> 16) >= *lpz)
- {
- *lpdest = vid.alphamap[r_aliasblendcolor*256 + *lpdest];
- }
- lpdest++;
- lzi += r_zistepx;
- lpz++;
- } while (--lcount);
- }
-
- pspanpackage++;
- } while (pspanpackage->count != -999999);
-}
-
-void R_PolysetDrawSpans8_Opaque (spanpackage_t *pspanpackage)
-{
- int lcount;
-
- do
- {
- lcount = d_aspancount - pspanpackage->count;
-
- errorterm += erroradjustup;
- if (errorterm >= 0)
- {
- d_aspancount += d_countextrastep;
- errorterm -= erroradjustdown;
- }
- else
- {
- d_aspancount += ubasestep;
- }
-
- if (lcount)
- {
- int lsfrac, ltfrac;
- byte *lpdest;
- byte *lptex;
- int llight;
- int lzi;
- short *lpz;
-
- lpdest = pspanpackage->pdest;
- lptex = pspanpackage->ptex;
- lpz = pspanpackage->pz;
- lsfrac = pspanpackage->sfrac;
- ltfrac = pspanpackage->tfrac;
- llight = pspanpackage->light;
- lzi = pspanpackage->zi;
-
- do
- {
- if ((lzi >> 16) >= *lpz)
- {
-//PGM
- if(r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE)
- *lpdest = ((byte *)vid.colormap)[irtable[*lptex]];
- else
- *lpdest = ((byte *)vid.colormap)[*lptex + (llight & 0xFF00)];
-//PGM
- *lpz = lzi >> 16;
- }
- lpdest++;
- lzi += r_zistepx;
- lpz++;
- llight += r_lstepx;
- lptex += a_ststepxwhole;
- lsfrac += a_sstepxfrac;
- lptex += lsfrac >> 16;
- lsfrac &= 0xFFFF;
- ltfrac += a_tstepxfrac;
- if (ltfrac & 0x10000)
- {
- lptex += r_affinetridesc.skinwidth;
- ltfrac &= 0xFFFF;
- }
- } while (--lcount);
- }
-
- pspanpackage++;
- } while (pspanpackage->count != -999999);
-}
-
-
-/*
-================
-R_PolysetFillSpans8
-================
-*/
-void R_PolysetFillSpans8 (spanpackage_t *pspanpackage)
-{
- int color;
-
-// FIXME: do z buffering
-
- color = d_aflatcolor++;
-
- while (1)
- {
- int lcount;
- byte *lpdest;
-
- lcount = pspanpackage->count;
-
- if (lcount == -1)
- return;
-
- if (lcount)
- {
- lpdest = pspanpackage->pdest;
-
- do
- {
- *lpdest++ = color;
- } while (--lcount);
- }
-
- pspanpackage++;
- }
-}
-
-/*
-================
-R_RasterizeAliasPolySmooth
-================
-*/
-void R_RasterizeAliasPolySmooth (void)
-{
- int initialleftheight, initialrightheight;
- int *plefttop, *prighttop, *pleftbottom, *prightbottom;
- int working_lstepx, originalcount;
-
- plefttop = pedgetable->pleftedgevert0;
- prighttop = pedgetable->prightedgevert0;
-
- pleftbottom = pedgetable->pleftedgevert1;
- prightbottom = pedgetable->prightedgevert1;
-
- initialleftheight = pleftbottom[1] - plefttop[1];
- initialrightheight = prightbottom[1] - prighttop[1];
-
-//
-// set the s, t, and light gradients, which are consistent across the triangle
-// because being a triangle, things are affine
-//
- R_PolysetCalcGradients (r_affinetridesc.skinwidth);
-//
-// rasterize the polygon
-//
-
-//
-// scan out the top (and possibly only) part of the left edge
-//
- d_pedgespanpackage = a_spans;
-
- ystart = plefttop[1];
- d_aspancount = plefttop[0] - prighttop[0];
-
- d_ptex = (byte *)r_affinetridesc.pskin + (plefttop[2] >> 16) +
- (plefttop[3] >> 16) * r_affinetridesc.skinwidth;
-
- d_sfrac = plefttop[2] & 0xFFFF;
- d_tfrac = plefttop[3] & 0xFFFF;
-
- d_light = plefttop[4];
- d_zi = plefttop[5];
-
- d_pdest = (byte *)d_viewbuffer +
- ystart * r_screenwidth + plefttop[0];
- d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0];
-
- if (initialleftheight == 1)
- {
- d_pedgespanpackage->pdest = d_pdest;
- d_pedgespanpackage->pz = d_pz;
- d_pedgespanpackage->count = d_aspancount;
- d_pedgespanpackage->ptex = d_ptex;
-
- d_pedgespanpackage->sfrac = d_sfrac;
- d_pedgespanpackage->tfrac = d_tfrac;
-
- // FIXME: need to clamp l, s, t, at both ends?
- d_pedgespanpackage->light = d_light;
- d_pedgespanpackage->zi = d_zi;
-
- d_pedgespanpackage++;
- }
- else
- {
- R_PolysetSetUpForLineScan(plefttop[0], plefttop[1],
- pleftbottom[0], pleftbottom[1]);
-
- d_pzbasestep = d_zwidth + ubasestep;
- d_pzextrastep = d_pzbasestep + 1;
-
- d_pdestbasestep = r_screenwidth + ubasestep;
- d_pdestextrastep = d_pdestbasestep + 1;
-
- // TODO: can reuse partial expressions here
-
- // for negative steps in x along left edge, bias toward overflow rather than
- // underflow (sort of turning the floor () we did in the gradient calcs into
- // ceil (), but plus a little bit)
- if (ubasestep < 0)
- working_lstepx = r_lstepx - 1;
- else
- working_lstepx = r_lstepx;
-
- d_countextrastep = ubasestep + 1;
- d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) +
- ((r_tstepy + r_tstepx * ubasestep) >> 16) *
- r_affinetridesc.skinwidth;
-
- d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF;
- d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF;
-
- d_lightbasestep = r_lstepy + working_lstepx * ubasestep;
- d_zibasestep = r_zistepy + r_zistepx * ubasestep;
-
- d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) +
- ((r_tstepy + r_tstepx * d_countextrastep) >> 16) *
- r_affinetridesc.skinwidth;
-
- d_sfracextrastep = (r_sstepy + r_sstepx*d_countextrastep) & 0xFFFF;
- d_tfracextrastep = (r_tstepy + r_tstepx*d_countextrastep) & 0xFFFF;
-
- d_lightextrastep = d_lightbasestep + working_lstepx;
- d_ziextrastep = d_zibasestep + r_zistepx;
-
- R_PolysetScanLeftEdge_C(initialleftheight);
- }
-
-//
-// scan out the bottom part of the left edge, if it exists
-//
- if (pedgetable->numleftedges == 2)
- {
- int height;
-
- plefttop = pleftbottom;
- pleftbottom = pedgetable->pleftedgevert2;
-
- height = pleftbottom[1] - plefttop[1];
-
-// TODO: make this a function; modularize this function in general
-
- ystart = plefttop[1];
- d_aspancount = plefttop[0] - prighttop[0];
- d_ptex = (byte *)r_affinetridesc.pskin + (plefttop[2] >> 16) +
- (plefttop[3] >> 16) * r_affinetridesc.skinwidth;
- d_sfrac = 0;
- d_tfrac = 0;
- d_light = plefttop[4];
- d_zi = plefttop[5];
-
- d_pdest = (byte *)d_viewbuffer + ystart * r_screenwidth + plefttop[0];
- d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0];
-
- if (height == 1)
- {
- d_pedgespanpackage->pdest = d_pdest;
- d_pedgespanpackage->pz = d_pz;
- d_pedgespanpackage->count = d_aspancount;
- d_pedgespanpackage->ptex = d_ptex;
-
- d_pedgespanpackage->sfrac = d_sfrac;
- d_pedgespanpackage->tfrac = d_tfrac;
-
- // FIXME: need to clamp l, s, t, at both ends?
- d_pedgespanpackage->light = d_light;
- d_pedgespanpackage->zi = d_zi;
- }
- else
- {
- R_PolysetSetUpForLineScan(plefttop[0], plefttop[1],
- pleftbottom[0], pleftbottom[1]);
-
- d_pdestbasestep = r_screenwidth + ubasestep;
- d_pdestextrastep = d_pdestbasestep + 1;
-
- d_pzbasestep = d_zwidth + ubasestep;
- d_pzextrastep = d_pzbasestep + 1;
-
- if (ubasestep < 0)
- working_lstepx = r_lstepx - 1;
- else
- working_lstepx = r_lstepx;
-
- d_countextrastep = ubasestep + 1;
- d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) +
- ((r_tstepy + r_tstepx * ubasestep) >> 16) *
- r_affinetridesc.skinwidth;
-
- d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF;
- d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF;
-
- d_lightbasestep = r_lstepy + working_lstepx * ubasestep;
- d_zibasestep = r_zistepy + r_zistepx * ubasestep;
-
- d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) +
- ((r_tstepy + r_tstepx * d_countextrastep) >> 16) *
- r_affinetridesc.skinwidth;
-
-
- d_sfracextrastep = (r_sstepy+r_sstepx*d_countextrastep) & 0xFFFF;
- d_tfracextrastep = (r_tstepy+r_tstepx*d_countextrastep) & 0xFFFF;
-
- d_lightextrastep = d_lightbasestep + working_lstepx;
- d_ziextrastep = d_zibasestep + r_zistepx;
-
- R_PolysetScanLeftEdge_C(height);
- }
- }
-
-// scan out the top (and possibly only) part of the right edge, updating the
-// count field
- d_pedgespanpackage = a_spans;
-
- R_PolysetSetUpForLineScan(prighttop[0], prighttop[1],
- prightbottom[0], prightbottom[1]);
- d_aspancount = 0;
- d_countextrastep = ubasestep + 1;
- originalcount = a_spans[initialrightheight].count;
- a_spans[initialrightheight].count = -999999; // mark end of the spanpackages
- (*d_pdrawspans) (a_spans);
-
-// scan out the bottom part of the right edge, if it exists
- if (pedgetable->numrightedges == 2)
- {
- int height;
- spanpackage_t *pstart;
-
- pstart = a_spans + initialrightheight;
- pstart->count = originalcount;
-
- d_aspancount = prightbottom[0] - prighttop[0];
-
- prighttop = prightbottom;
- prightbottom = pedgetable->prightedgevert2;
-
- height = prightbottom[1] - prighttop[1];
-
- R_PolysetSetUpForLineScan(prighttop[0], prighttop[1],
- prightbottom[0], prightbottom[1]);
-
- d_countextrastep = ubasestep + 1;
- a_spans[initialrightheight + height].count = -999999;
- // mark end of the spanpackages
- (*d_pdrawspans) (pstart);
- }
-}
-
-
-/*
-================
-R_PolysetSetEdgeTable
-================
-*/
-void R_PolysetSetEdgeTable (void)
-{
- int edgetableindex;
-
- edgetableindex = 0; // assume the vertices are already in
- // top to bottom order
-
-//
-// determine which edges are right & left, and the order in which
-// to rasterize them
-//
- if (r_p0[1] >= r_p1[1])
- {
- if (r_p0[1] == r_p1[1])
- {
- if (r_p0[1] < r_p2[1])
- pedgetable = &edgetables[2];
- else
- pedgetable = &edgetables[5];
-
- return;
- }
- else
- {
- edgetableindex = 1;
- }
- }
-
- if (r_p0[1] == r_p2[1])
- {
- if (edgetableindex)
- pedgetable = &edgetables[8];
- else
- pedgetable = &edgetables[9];
-
- return;
- }
- else if (r_p1[1] == r_p2[1])
- {
- if (edgetableindex)
- pedgetable = &edgetables[10];
- else
- pedgetable = &edgetables[11];
-
- return;
- }
-
- if (r_p0[1] > r_p2[1])
- edgetableindex += 2;
-
- if (r_p1[1] > r_p2[1])
- edgetableindex += 4;
-
- pedgetable = &edgetables[edgetableindex];
-}
--- a/ref/r_rast.c
+++ /dev/null
@@ -1,828 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-#define MAXLEFTCLIPEDGES 100
-
-// !!! if these are changed, they must be changed in asm_draw.h too !!!
-#define FULLY_CLIPPED_CACHED 0x80000000
-#define FRAMECOUNT_MASK 0x7FFFFFFF
-
-unsigned int cacheoffset;
-
-int c_faceclip; // number of faces clipped
-
-
-clipplane_t *entity_clipplanes;
-clipplane_t view_clipplanes[4];
-clipplane_t world_clipplanes[16];
-
-medge_t *r_pedge;
-
-qboolean r_leftclipped, r_rightclipped;
-static qboolean makeleftedge, makerightedge;
-qboolean r_nearzionly;
-
-int sintable[1280];
-int intsintable[1280];
-int blanktable[1280]; // PGM
-
-mvertex_t r_leftenter, r_leftexit;
-mvertex_t r_rightenter, r_rightexit;
-
-typedef struct
-{
- float u,v;
- int ceilv;
-} evert_t;
-
-int r_emitted;
-float r_nearzi;
-float r_u1, r_v1, r_lzi1;
-int r_ceilv1;
-
-qboolean r_lastvertvalid;
-int r_skyframe;
-
-msurface_t *r_skyfaces;
-mplane_t r_skyplanes[6];
-mtexinfo_t r_skytexinfo[6];
-mvertex_t *r_skyverts;
-medge_t *r_skyedges;
-int *r_skysurfedges;
-
-// I just copied this data from a box map...
-int skybox_planes[12] = {2,-128, 0,-128, 2,128, 1,128, 0,128, 1,-128};
-
-int box_surfedges[24] = { 1,2,3,4, -1,5,6,7, 8,9,-6,10, -2,-7,-9,11,
- 12,-3,-11,-8, -12,-10,-5,-4};
-int box_edges[24] = { 1,2, 2,3, 3,4, 4,1, 1,5, 5,6, 6,2, 7,8, 8,6, 5,7, 8,3, 7,4};
-
-int box_faces[6] = {0,0,2,2,2,0};
-
-vec3_t box_vecs[6][2] = {
- { {0,-1,0}, {-1,0,0} },
- { {0,1,0}, {0,0,-1} },
- { {0,-1,0}, {1,0,0} },
- { {1,0,0}, {0,0,-1} },
- { {0,-1,0}, {0,0,-1} },
- { {-1,0,0}, {0,0,-1} }
-};
-
-float box_verts[8][3] = {
- {-1,-1,-1},
- {-1,1,-1},
- {1,1,-1},
- {1,-1,-1},
- {-1,-1,1},
- {-1,1,1},
- {1,-1,1},
- {1,1,1}
-};
-
-// down, west, up, north, east, south
-// {"rt", "bk", "lf", "ft", "up", "dn"};
-
-/*
-================
-R_InitSkyBox
-
-================
-*/
-void R_InitSkyBox (void)
-{
- int i;
- extern model_t *loadmodel;
-
- r_skyfaces = loadmodel->surfaces + loadmodel->numsurfaces;
- loadmodel->numsurfaces += 6;
- r_skyverts = loadmodel->vertexes + loadmodel->numvertexes;
- loadmodel->numvertexes += 8;
- r_skyedges = loadmodel->edges + loadmodel->numedges;
- loadmodel->numedges += 12;
- r_skysurfedges = loadmodel->surfedges + loadmodel->numsurfedges;
- loadmodel->numsurfedges += 24;
- if (loadmodel->numsurfaces > MAX_MAP_FACES
- || loadmodel->numvertexes > MAX_MAP_VERTS
- || loadmodel->numedges > MAX_MAP_EDGES)
- ri.Sys_Error (ERR_DROP, "InitSkyBox: map overflow");
-
- memset (r_skyfaces, 0, 6*sizeof(*r_skyfaces));
- for (i=0 ; i<6 ; i++)
- {
- r_skyplanes[i].normal[skybox_planes[i*2]] = 1;
- r_skyplanes[i].dist = skybox_planes[i*2+1];
-
- VectorCopy (box_vecs[i][0], r_skytexinfo[i].vecs[0]);
- VectorCopy (box_vecs[i][1], r_skytexinfo[i].vecs[1]);
-
- r_skyfaces[i].plane = &r_skyplanes[i];
- r_skyfaces[i].numedges = 4;
- r_skyfaces[i].flags = box_faces[i] | SURF_DRAWSKYBOX;
- r_skyfaces[i].firstedge = loadmodel->numsurfedges-24+i*4;
- r_skyfaces[i].texinfo = &r_skytexinfo[i];
- r_skyfaces[i].texturemins[0] = -128;
- r_skyfaces[i].texturemins[1] = -128;
- r_skyfaces[i].extents[0] = 256;
- r_skyfaces[i].extents[1] = 256;
- }
-
- for (i=0 ; i<24 ; i++)
- if (box_surfedges[i] > 0)
- r_skysurfedges[i] = loadmodel->numedges-13 + box_surfedges[i];
- else
- r_skysurfedges[i] = - (loadmodel->numedges-13 + -box_surfedges[i]);
-
- for(i=0 ; i<12 ; i++)
- {
- r_skyedges[i].v[0] = loadmodel->numvertexes-9+box_edges[i*2+0];
- r_skyedges[i].v[1] = loadmodel->numvertexes-9+box_edges[i*2+1];
- r_skyedges[i].cachededgeoffset = 0;
- }
-}
-
-/*
-================
-R_EmitSkyBox
-================
-*/
-void R_EmitSkyBox (void)
-{
- int i, j;
- int oldkey;
-
- if (insubmodel)
- return; // submodels should never have skies
- if (r_skyframe == r_framecount)
- return; // already set this frame
-
- r_skyframe = r_framecount;
-
- // set the eight fake vertexes
- for (i=0 ; i<8 ; i++)
- for (j=0 ; j<3 ; j++)
- r_skyverts[i].position[j] = r_origin[j] + box_verts[i][j]*128;
-
- // set the six fake planes
- for (i=0 ; i<6 ; i++)
- if (skybox_planes[i*2+1] > 0)
- r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]+128;
- else
- r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]-128;
-
- // fix texture offseets
- for (i=0 ; i<6 ; i++)
- {
- r_skytexinfo[i].vecs[0][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[0]);
- r_skytexinfo[i].vecs[1][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[1]);
- }
-
- // emit the six faces
- oldkey = r_currentkey;
- r_currentkey = 0x7ffffff0;
- for (i=0 ; i<6 ; i++)
- {
- R_RenderFace (r_skyfaces + i, 15);
- }
- r_currentkey = oldkey; // bsp sorting order
-}
-
-
-/*
-================
-R_EmitEdge
-================
-*/
-void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1)
-{
- edge_t *edge, *pcheck;
- int u_check;
- float u, u_step;
- vec3_t local, transformed;
- float *world;
- int v, v2, ceilv0;
- float scale, lzi0, u0, v0;
- int side;
-
- if (r_lastvertvalid)
- {
- u0 = r_u1;
- v0 = r_v1;
- lzi0 = r_lzi1;
- ceilv0 = r_ceilv1;
- }
- else
- {
- world = &pv0->position[0];
-
- // transform and project
- VectorSubtract (world, modelorg, local);
- TransformVector (local, transformed);
-
- if (transformed[2] < NEAR_CLIP)
- transformed[2] = NEAR_CLIP;
-
- lzi0 = 1.0 / transformed[2];
-
- // FIXME: build x/yscale into transform?
- scale = xscale * lzi0;
- u0 = (xcenter + scale*transformed[0]);
- if (u0 < r_refdef.fvrectx_adj)
- u0 = r_refdef.fvrectx_adj;
- if (u0 > r_refdef.fvrectright_adj)
- u0 = r_refdef.fvrectright_adj;
-
- scale = yscale * lzi0;
- v0 = (ycenter - scale*transformed[1]);
- if (v0 < r_refdef.fvrecty_adj)
- v0 = r_refdef.fvrecty_adj;
- if (v0 > r_refdef.fvrectbottom_adj)
- v0 = r_refdef.fvrectbottom_adj;
-
- ceilv0 = (int) ceil(v0);
- }
-
- world = &pv1->position[0];
-
-// transform and project
- VectorSubtract (world, modelorg, local);
- TransformVector (local, transformed);
-
- if (transformed[2] < NEAR_CLIP)
- transformed[2] = NEAR_CLIP;
-
- r_lzi1 = 1.0 / transformed[2];
-
- scale = xscale * r_lzi1;
- r_u1 = (xcenter + scale*transformed[0]);
- if (r_u1 < r_refdef.fvrectx_adj)
- r_u1 = r_refdef.fvrectx_adj;
- if (r_u1 > r_refdef.fvrectright_adj)
- r_u1 = r_refdef.fvrectright_adj;
-
- scale = yscale * r_lzi1;
- r_v1 = (ycenter - scale*transformed[1]);
- if (r_v1 < r_refdef.fvrecty_adj)
- r_v1 = r_refdef.fvrecty_adj;
- if (r_v1 > r_refdef.fvrectbottom_adj)
- r_v1 = r_refdef.fvrectbottom_adj;
-
- if (r_lzi1 > lzi0)
- lzi0 = r_lzi1;
-
- if (lzi0 > r_nearzi) // for mipmap finding
- r_nearzi = lzi0;
-
-// for right edges, all we want is the effect on 1/z
- if (r_nearzionly)
- return;
-
- r_emitted = 1;
-
- r_ceilv1 = (int) ceil(r_v1);
-
-
-// create the edge
- if (ceilv0 == r_ceilv1)
- {
- // we cache unclipped horizontal edges as fully clipped
- if (cacheoffset != 0x7FFFFFFF)
- {
- cacheoffset = FULLY_CLIPPED_CACHED |
- (r_framecount & FRAMECOUNT_MASK);
- }
-
- return; // horizontal edge
- }
-
- side = ceilv0 > r_ceilv1;
-
- edge = edge_p++;
-
- edge->owner = r_pedge;
-
- edge->nearzi = lzi0;
-
- if (side == 0)
- {
- // trailing edge (go from p1 to p2)
- v = ceilv0;
- v2 = r_ceilv1 - 1;
-
- edge->surfs[0] = surface_p - surfaces;
- edge->surfs[1] = 0;
-
- u_step = ((r_u1 - u0) / (r_v1 - v0));
- u = u0 + ((float)v - v0) * u_step;
- }
- else
- {
- // leading edge (go from p2 to p1)
- v2 = ceilv0 - 1;
- v = r_ceilv1;
-
- edge->surfs[0] = 0;
- edge->surfs[1] = surface_p - surfaces;
-
- u_step = ((u0 - r_u1) / (v0 - r_v1));
- u = r_u1 + ((float)v - r_v1) * u_step;
- }
-
- edge->u_step = u_step*0x100000;
- edge->u = u*0x100000 + 0xFFFFF;
-
-// we need to do this to avoid stepping off the edges if a very nearly
-// horizontal edge is less than epsilon above a scan, and numeric error causes
-// it to incorrectly extend to the scan, and the extension of the line goes off
-// the edge of the screen
-// FIXME: is this actually needed?
- if (edge->u < r_refdef.vrect_x_adj_shift20)
- edge->u = r_refdef.vrect_x_adj_shift20;
- if (edge->u > r_refdef.vrectright_adj_shift20)
- edge->u = r_refdef.vrectright_adj_shift20;
-
-//
-// sort the edge in normally
-//
- u_check = edge->u;
- if (edge->surfs[0])
- u_check++; // sort trailers after leaders
-
- if (!newedges[v] || newedges[v]->u >= u_check)
- {
- edge->next = newedges[v];
- newedges[v] = edge;
- }
- else
- {
- pcheck = newedges[v];
- while (pcheck->next && pcheck->next->u < u_check)
- pcheck = pcheck->next;
- edge->next = pcheck->next;
- pcheck->next = edge;
- }
-
- edge->nextremove = removeedges[v2];
- removeedges[v2] = edge;
-}
-
-
-/*
-================
-R_ClipEdge
-================
-*/
-void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip)
-{
- float d0, d1, f;
- mvertex_t clipvert;
-
- if (clip)
- {
- do
- {
- d0 = DotProduct (pv0->position, clip->normal) - clip->dist;
- d1 = DotProduct (pv1->position, clip->normal) - clip->dist;
-
- if (d0 >= 0)
- {
- // point 0 is unclipped
- if (d1 >= 0)
- {
- // both points are unclipped
- continue;
- }
-
- // only point 1 is clipped
-
- // we don't cache clipped edges
- cacheoffset = 0x7FFFFFFF;
-
- f = d0 / (d0 - d1);
- clipvert.position[0] = pv0->position[0] +
- f * (pv1->position[0] - pv0->position[0]);
- clipvert.position[1] = pv0->position[1] +
- f * (pv1->position[1] - pv0->position[1]);
- clipvert.position[2] = pv0->position[2] +
- f * (pv1->position[2] - pv0->position[2]);
-
- if (clip->leftedge)
- {
- r_leftclipped = true;
- r_leftexit = clipvert;
- }
- else if (clip->rightedge)
- {
- r_rightclipped = true;
- r_rightexit = clipvert;
- }
-
- R_ClipEdge (pv0, &clipvert, clip->next);
- return;
- }
- else
- {
- // point 0 is clipped
- if (d1 < 0)
- {
- // both points are clipped
- // we do cache fully clipped edges
- if (!r_leftclipped)
- cacheoffset = FULLY_CLIPPED_CACHED |
- (r_framecount & FRAMECOUNT_MASK);
- return;
- }
-
- // only point 0 is clipped
- r_lastvertvalid = false;
-
- // we don't cache partially clipped edges
- cacheoffset = 0x7FFFFFFF;
-
- f = d0 / (d0 - d1);
- clipvert.position[0] = pv0->position[0] +
- f * (pv1->position[0] - pv0->position[0]);
- clipvert.position[1] = pv0->position[1] +
- f * (pv1->position[1] - pv0->position[1]);
- clipvert.position[2] = pv0->position[2] +
- f * (pv1->position[2] - pv0->position[2]);
-
- if (clip->leftedge)
- {
- r_leftclipped = true;
- r_leftenter = clipvert;
- }
- else if (clip->rightedge)
- {
- r_rightclipped = true;
- r_rightenter = clipvert;
- }
-
- R_ClipEdge (&clipvert, pv1, clip->next);
- return;
- }
- } while ((clip = clip->next) != NULL);
- }
-
-// add the edge
- R_EmitEdge (pv0, pv1);
-}
-
-
-/*
-================
-R_EmitCachedEdge
-================
-*/
-void R_EmitCachedEdge (void)
-{
- edge_t *pedge_t;
-
- pedge_t = (edge_t *)((uintptr)r_edges + r_pedge->cachededgeoffset);
-
- if (!pedge_t->surfs[0])
- pedge_t->surfs[0] = surface_p - surfaces;
- else
- pedge_t->surfs[1] = surface_p - surfaces;
-
- if (pedge_t->nearzi > r_nearzi) // for mipmap finding
- r_nearzi = pedge_t->nearzi;
-
- r_emitted = 1;
-}
-
-
-/*
-================
-R_RenderFace
-================
-*/
-void R_RenderFace (msurface_t *fa, int clipflags)
-{
- int i, lindex;
- unsigned mask;
- mplane_t *pplane;
- float distinv;
- vec3_t p_normal;
- medge_t *pedges, tedge;
- clipplane_t *pclip;
-
- // translucent surfaces are not drawn by the edge renderer
- if (fa->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))
- {
- fa->nextalphasurface = r_alpha_surfaces;
- r_alpha_surfaces = fa;
- return;
- }
-
- // sky surfaces encountered in the world will cause the
- // environment box surfaces to be emited
- if ( fa->texinfo->flags & SURF_SKY )
- {
- R_EmitSkyBox ();
- return;
- }
-
-// skip out if no more surfs
- if ((surface_p) >= surf_max)
- {
- r_outofsurfaces++;
- return;
- }
-
-// ditto if not enough edges left, or switch to auxedges if possible
- if ((edge_p + fa->numedges + 4) >= edge_max)
- {
- r_outofedges += fa->numedges;
- return;
- }
-
- c_faceclip++;
-
-// set up clip planes
- pclip = NULL;
-
- for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
- {
- if (clipflags & mask)
- {
- view_clipplanes[i].next = pclip;
- pclip = &view_clipplanes[i];
- }
- }
-
-// push the edges through
- r_emitted = 0;
- r_nearzi = 0;
- r_nearzionly = false;
- makeleftedge = makerightedge = false;
- pedges = currentmodel->edges;
- r_lastvertvalid = false;
-
- for (i=0 ; i<fa->numedges ; i++)
- {
- lindex = currentmodel->surfedges[fa->firstedge + i];
-
- if (lindex > 0)
- {
- r_pedge = &pedges[lindex];
-
- // if the edge is cached, we can just reuse the edge
- if (!insubmodel)
- {
- if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
- {
- if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
- r_framecount)
- {
- r_lastvertvalid = false;
- continue;
- }
- }
- else
- {
- if ((((uintptr)edge_p - (uintptr)r_edges) >
- r_pedge->cachededgeoffset) &&
- (((edge_t *)((uintptr)r_edges +
- r_pedge->cachededgeoffset))->owner == r_pedge))
- {
- R_EmitCachedEdge ();
- r_lastvertvalid = false;
- continue;
- }
- }
- }
-
- // assume it's cacheable
- cacheoffset = (byte *)edge_p - (byte *)r_edges;
- r_leftclipped = r_rightclipped = false;
- R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[0]],
- &r_pcurrentvertbase[r_pedge->v[1]],
- pclip);
- r_pedge->cachededgeoffset = cacheoffset;
-
- if (r_leftclipped)
- makeleftedge = true;
- if (r_rightclipped)
- makerightedge = true;
- r_lastvertvalid = true;
- }
- else
- {
- lindex = -lindex;
- r_pedge = &pedges[lindex];
- // if the edge is cached, we can just reuse the edge
- if (!insubmodel)
- {
- if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
- {
- if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
- r_framecount)
- {
- r_lastvertvalid = false;
- continue;
- }
- }
- else
- {
- // it's cached if the cached edge is valid and is owned
- // by this medge_t
- if ((((uintptr)edge_p - (uintptr)r_edges) >
- r_pedge->cachededgeoffset) &&
- (((edge_t *)((uintptr)r_edges +
- r_pedge->cachededgeoffset))->owner == r_pedge))
- {
- R_EmitCachedEdge ();
- r_lastvertvalid = false;
- continue;
- }
- }
- }
-
- // assume it's cacheable
- cacheoffset = (byte *)edge_p - (byte *)r_edges;
- r_leftclipped = r_rightclipped = false;
- R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[1]],
- &r_pcurrentvertbase[r_pedge->v[0]],
- pclip);
- r_pedge->cachededgeoffset = cacheoffset;
-
- if (r_leftclipped)
- makeleftedge = true;
- if (r_rightclipped)
- makerightedge = true;
- r_lastvertvalid = true;
- }
- }
-
-// if there was a clip off the left edge, add that edge too
-// FIXME: faster to do in screen space?
-// FIXME: share clipped edges?
- if (makeleftedge)
- {
- r_pedge = &tedge;
- r_lastvertvalid = false;
- R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
- }
-
-// if there was a clip off the right edge, get the right r_nearzi
- if (makerightedge)
- {
- r_pedge = &tedge;
- r_lastvertvalid = false;
- r_nearzionly = true;
- R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
- }
-
-// if no edges made it out, return without posting the surface
- if (!r_emitted)
- return;
-
- r_polycount++;
-
- surface_p->msurf = fa;
- surface_p->nearzi = r_nearzi;
- surface_p->flags = fa->flags;
- surface_p->insubmodel = insubmodel;
- surface_p->spanstate = 0;
- surface_p->entity = currententity;
- surface_p->key = r_currentkey++;
- surface_p->spans = NULL;
-
- pplane = fa->plane;
-// FIXME: cache this?
- TransformVector (pplane->normal, p_normal);
-// FIXME: cache this?
- distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
-
- surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
- surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
- surface_p->d_ziorigin = p_normal[2] * distinv -
- xcenter * surface_p->d_zistepu -
- ycenter * surface_p->d_zistepv;
-
- surface_p++;
-}
-
-
-/*
-================
-R_RenderBmodelFace
-================
-*/
-void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf)
-{
- int i;
- unsigned mask;
- mplane_t *pplane;
- float distinv;
- vec3_t p_normal;
- medge_t tedge;
- clipplane_t *pclip;
-
- if (psurf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))
- {
- psurf->nextalphasurface = r_alpha_surfaces;
- r_alpha_surfaces = psurf;
- return;
- }
-
-// skip out if no more surfs
- if (surface_p >= surf_max)
- {
- r_outofsurfaces++;
- return;
- }
-
-// ditto if not enough edges left, or switch to auxedges if possible
- if ((edge_p + psurf->numedges + 4) >= edge_max)
- {
- r_outofedges += psurf->numedges;
- return;
- }
-
- c_faceclip++;
-
-// this is a dummy to give the caching mechanism someplace to write to
- r_pedge = &tedge;
-
-// set up clip planes
- pclip = NULL;
-
- for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
- {
- if (r_clipflags & mask)
- {
- view_clipplanes[i].next = pclip;
- pclip = &view_clipplanes[i];
- }
- }
-
-// push the edges through
- r_emitted = 0;
- r_nearzi = 0;
- r_nearzionly = false;
- makeleftedge = makerightedge = false;
-// FIXME: keep clipped bmodel edges in clockwise order so last vertex caching
-// can be used?
- r_lastvertvalid = false;
-
- for ( ; pedges ; pedges = pedges->pnext)
- {
- r_leftclipped = r_rightclipped = false;
- R_ClipEdge (pedges->v[0], pedges->v[1], pclip);
-
- if (r_leftclipped)
- makeleftedge = true;
- if (r_rightclipped)
- makerightedge = true;
- }
-
-// if there was a clip off the left edge, add that edge too
-// FIXME: faster to do in screen space?
-// FIXME: share clipped edges?
- if (makeleftedge)
- {
- r_pedge = &tedge;
- R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
- }
-
-// if there was a clip off the right edge, get the right r_nearzi
- if (makerightedge)
- {
- r_pedge = &tedge;
- r_nearzionly = true;
- R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
- }
-
-// if no edges made it out, return without posting the surface
- if (!r_emitted)
- return;
-
- r_polycount++;
-
- surface_p->msurf = psurf;
- surface_p->nearzi = r_nearzi;
- surface_p->flags = psurf->flags;
- surface_p->insubmodel = true;
- surface_p->spanstate = 0;
- surface_p->entity = currententity;
- surface_p->key = r_currentbkey;
- surface_p->spans = NULL;
-
- pplane = psurf->plane;
-// FIXME: cache this?
- TransformVector (pplane->normal, p_normal);
-// FIXME: cache this?
- distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
-
- surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
- surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
- surface_p->d_ziorigin = p_normal[2] * distinv -
- xcenter * surface_p->d_zistepu -
- ycenter * surface_p->d_zistepv;
-
- surface_p++;
-}
-
--- a/ref/r_scan.c
+++ /dev/null
@@ -1,560 +1,0 @@
-// Portable C scan-level rasterization code, all pixel depths.
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-unsigned char *r_turb_pbase, *r_turb_pdest;
-fixed16_t r_turb_s, r_turb_t, r_turb_sstep, r_turb_tstep;
-int *r_turb_turb;
-int r_turb_spancount;
-
-void D_DrawTurbulent8Span (void);
-
-
-/*
-=============
-D_WarpScreen
-
-this performs a slight compression of the screen at the same time as
-the sine warp, to keep the edges from wrapping
-=============
-*/
-void D_WarpScreen (void)
-{
- int w, h;
- int u,v, u2, v2;
- byte *dest;
- int *turb;
- int *col;
- byte **row;
-
- static int cached_width, cached_height;
- static byte *rowptr[1200+AMP2*2];
- static int column[1600+AMP2*2];
-
- //
- // these are constant over resolutions, and can be saved
- //
- w = r_newrefdef.width;
- h = r_newrefdef.height;
- if (w != cached_width || h != cached_height)
- {
- cached_width = w;
- cached_height = h;
- for (v=0 ; v<h+AMP2*2 ; v++)
- {
- v2 = (int)((float)v/(h + AMP2 * 2) * r_refdef.vrect.height);
- rowptr[v] = r_warpbuffer + (WARP_WIDTH * v2);
- }
-
- for (u=0 ; u<w+AMP2*2 ; u++)
- {
- u2 = (int)((float)u/(w + AMP2 * 2) * r_refdef.vrect.width);
- column[u] = u2;
- }
- }
-
- turb = intsintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
- dest = vid.buffer + r_newrefdef.y * vid.rowbytes + r_newrefdef.x;
-
- for (v=0 ; v<h ; v++, dest += vid.rowbytes)
- {
- col = &column[turb[v]];
- row = &rowptr[v];
- for (u=0 ; u<w ; u+=4)
- {
- dest[u+0] = row[turb[u+0]][col[u+0]];
- dest[u+1] = row[turb[u+1]][col[u+1]];
- dest[u+2] = row[turb[u+2]][col[u+2]];
- dest[u+3] = row[turb[u+3]][col[u+3]];
- }
- }
-}
-
-
-/*
-=============
-D_DrawTurbulent8Span
-=============
-*/
-void D_DrawTurbulent8Span (void)
-{
- int sturb, tturb;
-
- do
- {
- sturb = ((r_turb_s + r_turb_turb[(r_turb_t>>16)&(CYCLE-1)])>>16)&63;
- tturb = ((r_turb_t + r_turb_turb[(r_turb_s>>16)&(CYCLE-1)])>>16)&63;
- *r_turb_pdest++ = *(r_turb_pbase + (tturb<<6) + sturb);
- r_turb_s += r_turb_sstep;
- r_turb_t += r_turb_tstep;
- } while (--r_turb_spancount > 0);
-}
-
-
-/*
-=============
-Turbulent8
-=============
-*/
-void Turbulent8 (espan_t *pspan)
-{
- int count;
- fixed16_t snext, tnext;
- float sdivz, tdivz, zi, z, du, dv, spancountminus1;
- float sdivz16stepu, tdivz16stepu, zi16stepu;
-
- r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
-
- r_turb_sstep = 0; // keep compiler happy
- r_turb_tstep = 0; // ditto
-
- r_turb_pbase = (unsigned char *)cacheblock;
-
- sdivz16stepu = d_sdivzstepu * 16;
- tdivz16stepu = d_tdivzstepu * 16;
- zi16stepu = d_zistepu * 16;
-
- do
- {
- r_turb_pdest = (unsigned char *)((byte *)d_viewbuffer +
- (r_screenwidth * pspan->v) + pspan->u);
-
- count = pspan->count;
-
- // calculate the initial s/z, t/z, 1/z, s, and t and clamp
- du = (float)pspan->u;
- dv = (float)pspan->v;
-
- sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
- tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
- zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
- z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
-
- r_turb_s = (int)(sdivz * z) + sadjust;
- if (r_turb_s > bbextents)
- r_turb_s = bbextents;
- else if (r_turb_s < 0)
- r_turb_s = 0;
-
- r_turb_t = (int)(tdivz * z) + tadjust;
- if (r_turb_t > bbextentt)
- r_turb_t = bbextentt;
- else if (r_turb_t < 0)
- r_turb_t = 0;
-
- do
- {
- // calculate s and t at the far end of the span
- if (count >= 16)
- r_turb_spancount = 16;
- else
- r_turb_spancount = count;
-
- count -= r_turb_spancount;
-
- if (count)
- {
- // calculate s/z, t/z, zi->fixed s and t at far end of span,
- // calculate s and t steps across span by shifting
- sdivz += sdivz16stepu;
- tdivz += tdivz16stepu;
- zi += zi16stepu;
- z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
-
- snext = (int)(sdivz * z) + sadjust;
- if (snext > bbextents)
- snext = bbextents;
- else if (snext < 16)
- snext = 16; // prevent round-off error on <0 steps from
- // from causing overstepping & running off the
- // edge of the texture
-
- tnext = (int)(tdivz * z) + tadjust;
- if (tnext > bbextentt)
- tnext = bbextentt;
- else if (tnext < 16)
- tnext = 16; // guard against round-off error on <0 steps
-
- r_turb_sstep = (snext - r_turb_s) >> 4;
- r_turb_tstep = (tnext - r_turb_t) >> 4;
- }
- else
- {
- // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
- // can't step off polygon), clamp, calculate s and t steps across
- // span by division, biasing steps low so we don't run off the
- // texture
- spancountminus1 = (float)(r_turb_spancount - 1);
- sdivz += d_sdivzstepu * spancountminus1;
- tdivz += d_tdivzstepu * spancountminus1;
- zi += d_zistepu * spancountminus1;
- z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
- snext = (int)(sdivz * z) + sadjust;
- if (snext > bbextents)
- snext = bbextents;
- else if (snext < 16)
- snext = 16; // prevent round-off error on <0 steps from
- // from causing overstepping & running off the
- // edge of the texture
-
- tnext = (int)(tdivz * z) + tadjust;
- if (tnext > bbextentt)
- tnext = bbextentt;
- else if (tnext < 16)
- tnext = 16; // guard against round-off error on <0 steps
-
- if (r_turb_spancount > 1)
- {
- r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1);
- r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1);
- }
- }
-
- r_turb_s = r_turb_s & ((CYCLE<<16)-1);
- r_turb_t = r_turb_t & ((CYCLE<<16)-1);
-
- D_DrawTurbulent8Span ();
-
- r_turb_s = snext;
- r_turb_t = tnext;
-
- } while (count > 0);
-
- } while ((pspan = pspan->pnext) != NULL);
-}
-
-//====================
-//PGM
-/*
-=============
-NonTurbulent8 - this is for drawing scrolling textures. they're warping water textures
- but the turbulence is automatically 0.
-=============
-*/
-void NonTurbulent8 (espan_t *pspan)
-{
- int count;
- fixed16_t snext, tnext;
- float sdivz, tdivz, zi, z, du, dv, spancountminus1;
- float sdivz16stepu, tdivz16stepu, zi16stepu;
-
-// r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
- r_turb_turb = blanktable;
-
- r_turb_sstep = 0; // keep compiler happy
- r_turb_tstep = 0; // ditto
-
- r_turb_pbase = (unsigned char *)cacheblock;
-
- sdivz16stepu = d_sdivzstepu * 16;
- tdivz16stepu = d_tdivzstepu * 16;
- zi16stepu = d_zistepu * 16;
-
- do
- {
- r_turb_pdest = (unsigned char *)((byte *)d_viewbuffer +
- (r_screenwidth * pspan->v) + pspan->u);
-
- count = pspan->count;
-
- // calculate the initial s/z, t/z, 1/z, s, and t and clamp
- du = (float)pspan->u;
- dv = (float)pspan->v;
-
- sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
- tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
- zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
- z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
-
- r_turb_s = (int)(sdivz * z) + sadjust;
- if (r_turb_s > bbextents)
- r_turb_s = bbextents;
- else if (r_turb_s < 0)
- r_turb_s = 0;
-
- r_turb_t = (int)(tdivz * z) + tadjust;
- if (r_turb_t > bbextentt)
- r_turb_t = bbextentt;
- else if (r_turb_t < 0)
- r_turb_t = 0;
-
- do
- {
- // calculate s and t at the far end of the span
- if (count >= 16)
- r_turb_spancount = 16;
- else
- r_turb_spancount = count;
-
- count -= r_turb_spancount;
-
- if (count)
- {
- // calculate s/z, t/z, zi->fixed s and t at far end of span,
- // calculate s and t steps across span by shifting
- sdivz += sdivz16stepu;
- tdivz += tdivz16stepu;
- zi += zi16stepu;
- z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
-
- snext = (int)(sdivz * z) + sadjust;
- if (snext > bbextents)
- snext = bbextents;
- else if (snext < 16)
- snext = 16; // prevent round-off error on <0 steps from
- // from causing overstepping & running off the
- // edge of the texture
-
- tnext = (int)(tdivz * z) + tadjust;
- if (tnext > bbextentt)
- tnext = bbextentt;
- else if (tnext < 16)
- tnext = 16; // guard against round-off error on <0 steps
-
- r_turb_sstep = (snext - r_turb_s) >> 4;
- r_turb_tstep = (tnext - r_turb_t) >> 4;
- }
- else
- {
- // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
- // can't step off polygon), clamp, calculate s and t steps across
- // span by division, biasing steps low so we don't run off the
- // texture
- spancountminus1 = (float)(r_turb_spancount - 1);
- sdivz += d_sdivzstepu * spancountminus1;
- tdivz += d_tdivzstepu * spancountminus1;
- zi += d_zistepu * spancountminus1;
- z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
- snext = (int)(sdivz * z) + sadjust;
- if (snext > bbextents)
- snext = bbextents;
- else if (snext < 16)
- snext = 16; // prevent round-off error on <0 steps from
- // from causing overstepping & running off the
- // edge of the texture
-
- tnext = (int)(tdivz * z) + tadjust;
- if (tnext > bbextentt)
- tnext = bbextentt;
- else if (tnext < 16)
- tnext = 16; // guard against round-off error on <0 steps
-
- if (r_turb_spancount > 1)
- {
- r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1);
- r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1);
- }
- }
-
- r_turb_s = r_turb_s & ((CYCLE<<16)-1);
- r_turb_t = r_turb_t & ((CYCLE<<16)-1);
-
- D_DrawTurbulent8Span ();
-
- r_turb_s = snext;
- r_turb_t = tnext;
-
- } while (count > 0);
-
- } while ((pspan = pspan->pnext) != NULL);
-}
-//PGM
-//====================
-
-
-/*
-=============
-D_DrawSpans16
-
- FIXME: actually make this subdivide by 16 instead of 8!!!
-=============
-*/
-void D_DrawSpans16 (espan_t *pspan)
-{
- int count, spancount;
- unsigned char *pbase, *pdest;
- fixed16_t s, t, snext, tnext, sstep, tstep;
- float sdivz, tdivz, zi, z, du, dv, spancountminus1;
- float sdivz8stepu, tdivz8stepu, zi8stepu;
-
- sstep = 0; // keep compiler happy
- tstep = 0; // ditto
-
- pbase = (unsigned char *)cacheblock;
-
- sdivz8stepu = d_sdivzstepu * 8;
- tdivz8stepu = d_tdivzstepu * 8;
- zi8stepu = d_zistepu * 8;
-
- do
- {
- pdest = (unsigned char *)((byte *)d_viewbuffer +
- (r_screenwidth * pspan->v) + pspan->u);
-
- count = pspan->count;
-
- // calculate the initial s/z, t/z, 1/z, s, and t and clamp
- du = (float)pspan->u;
- dv = (float)pspan->v;
-
- sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
- tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
- zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
- z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
-
- s = (int)(sdivz * z) + sadjust;
- if (s > bbextents)
- s = bbextents;
- else if (s < 0)
- s = 0;
-
- t = (int)(tdivz * z) + tadjust;
- if (t > bbextentt)
- t = bbextentt;
- else if (t < 0)
- t = 0;
-
- do
- {
- // calculate s and t at the far end of the span
- if (count >= 8)
- spancount = 8;
- else
- spancount = count;
-
- count -= spancount;
-
- if (count)
- {
- // calculate s/z, t/z, zi->fixed s and t at far end of span,
- // calculate s and t steps across span by shifting
- sdivz += sdivz8stepu;
- tdivz += tdivz8stepu;
- zi += zi8stepu;
- z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
-
- snext = (int)(sdivz * z) + sadjust;
- if (snext > bbextents)
- snext = bbextents;
- else if (snext < 8)
- snext = 8; // prevent round-off error on <0 steps from
- // from causing overstepping & running off the
- // edge of the texture
-
- tnext = (int)(tdivz * z) + tadjust;
- if (tnext > bbextentt)
- tnext = bbextentt;
- else if (tnext < 8)
- tnext = 8; // guard against round-off error on <0 steps
-
- sstep = (snext - s) >> 3;
- tstep = (tnext - t) >> 3;
- }
- else
- {
- // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
- // can't step off polygon), clamp, calculate s and t steps across
- // span by division, biasing steps low so we don't run off the
- // texture
- spancountminus1 = (float)(spancount - 1);
- sdivz += d_sdivzstepu * spancountminus1;
- tdivz += d_tdivzstepu * spancountminus1;
- zi += d_zistepu * spancountminus1;
- z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
- snext = (int)(sdivz * z) + sadjust;
- if (snext > bbextents)
- snext = bbextents;
- else if (snext < 8)
- snext = 8; // prevent round-off error on <0 steps from
- // from causing overstepping & running off the
- // edge of the texture
-
- tnext = (int)(tdivz * z) + tadjust;
- if (tnext > bbextentt)
- tnext = bbextentt;
- else if (tnext < 8)
- tnext = 8; // guard against round-off error on <0 steps
-
- if (spancount > 1)
- {
- sstep = (snext - s) / (spancount - 1);
- tstep = (tnext - t) / (spancount - 1);
- }
- }
-
- do
- {
- *pdest++ = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
- s += sstep;
- t += tstep;
- } while (--spancount > 0);
-
- s = snext;
- t = tnext;
-
- } while (count > 0);
-
- } while ((pspan = pspan->pnext) != NULL);
-}
-
-
-/*
-=============
-D_DrawZSpans
-=============
-*/
-void D_DrawZSpans (espan_t *pspan)
-{
- int count, doublecount, izistep;
- int izi;
- short *pdest;
- unsigned ltemp;
- float zi;
- float du, dv;
-
-// FIXME: check for clamping/range problems
-// we count on FP exceptions being turned off to avoid range problems
- izistep = (int)(d_zistepu * 0x8000 * 0x10000);
-
- do
- {
- pdest = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
-
- count = pspan->count;
-
- // calculate the initial 1/z
- du = (float)pspan->u;
- dv = (float)pspan->v;
-
- zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
- // we count on FP exceptions being turned off to avoid range problems
- izi = (int)(zi * 0x8000 * 0x10000);
-
- if ((uintptr)pdest & 0x02)
- {
- *pdest++ = (short)(izi >> 16);
- izi += izistep;
- count--;
- }
-
- if ((doublecount = count >> 1) > 0)
- {
- do
- {
- ltemp = izi >> 16;
- izi += izistep;
- ltemp |= izi & 0xFFFF0000;
- izi += izistep;
- *(int *)pdest = ltemp;
- pdest += 2;
- } while (--doublecount > 0);
- }
-
- if (count & 1)
- *pdest = (short)(izi >> 16);
-
- } while ((pspan = pspan->pnext) != NULL);
-}
--- a/ref/r_sprite.c
+++ /dev/null
@@ -1,106 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-extern polydesc_t r_polydesc;
-
-void R_BuildPolygonFromSurface(msurface_t *fa);
-void R_PolygonCalculateGradients (void);
-
-extern void R_PolyChooseSpanletRoutine( float alpha, qboolean isturbulent );
-
-extern vec5_t r_clip_verts[2][MAXWORKINGVERTS+2];
-
-extern void R_ClipAndDrawPoly( float alpha, qboolean isturbulent, qboolean textured );
-
-/*
-** R_DrawSprite
-**
-** Draw currententity / currentmodel as a single texture
-** mapped polygon
-*/
-void R_DrawSprite (void)
-{
- vec5_t *pverts;
- vec3_t left, up, right, down;
- dsprite_t *s_psprite;
- dsprframe_t *s_psprframe;
-
-
- s_psprite = (dsprite_t *)currentmodel->extradata;
-/*
- if (currententity->frame >= s_psprite->numframes
- || currententity->frame < 0)
- {
- ri.Con_Printf (PRINT_ALL, "No such sprite frame %i\n",
- currententity->frame);
- currententity->frame = 0;
- }
-*/
- currententity->frame %= s_psprite->numframes;
-
- s_psprframe = &s_psprite->frames[currententity->frame];
-
- r_polydesc.pixels = currentmodel->skins[currententity->frame]->pixels[0];
- r_polydesc.pixel_width = s_psprframe->width;
- r_polydesc.pixel_height = s_psprframe->height;
- r_polydesc.dist = 0;
-
- // generate the sprite's axes, completely parallel to the viewplane.
- VectorCopy (vup, r_polydesc.vup);
- VectorCopy (vright, r_polydesc.vright);
- VectorCopy (vpn, r_polydesc.vpn);
-
-// build the sprite poster in worldspace
- VectorScale (r_polydesc.vright,
- s_psprframe->width - s_psprframe->origin_x, right);
- VectorScale (r_polydesc.vup,
- s_psprframe->height - s_psprframe->origin_y, up);
- VectorScale (r_polydesc.vright,
- -s_psprframe->origin_x, left);
- VectorScale (r_polydesc.vup,
- -s_psprframe->origin_y, down);
-
- // invert UP vector for sprites
- VectorInverse( r_polydesc.vup );
-
- pverts = r_clip_verts[0];
-
- pverts[0][0] = r_entorigin[0] + up[0] + left[0];
- pverts[0][1] = r_entorigin[1] + up[1] + left[1];
- pverts[0][2] = r_entorigin[2] + up[2] + left[2];
- pverts[0][3] = 0;
- pverts[0][4] = 0;
-
- pverts[1][0] = r_entorigin[0] + up[0] + right[0];
- pverts[1][1] = r_entorigin[1] + up[1] + right[1];
- pverts[1][2] = r_entorigin[2] + up[2] + right[2];
- pverts[1][3] = s_psprframe->width;
- pverts[1][4] = 0;
-
- pverts[2][0] = r_entorigin[0] + down[0] + right[0];
- pverts[2][1] = r_entorigin[1] + down[1] + right[1];
- pverts[2][2] = r_entorigin[2] + down[2] + right[2];
- pverts[2][3] = s_psprframe->width;
- pverts[2][4] = s_psprframe->height;
-
- pverts[3][0] = r_entorigin[0] + down[0] + left[0];
- pverts[3][1] = r_entorigin[1] + down[1] + left[1];
- pverts[3][2] = r_entorigin[2] + down[2] + left[2];
- pverts[3][3] = 0;
- pverts[3][4] = s_psprframe->height;
-
- r_polydesc.nump = 4;
- r_polydesc.s_offset = ( r_polydesc.pixel_width >> 1);
- r_polydesc.t_offset = ( r_polydesc.pixel_height >> 1);
- VectorCopy( modelorg, r_polydesc.viewer_position );
-
- r_polydesc.stipple_parity = 1;
- if ( currententity->flags & RF_TRANSLUCENT )
- R_ClipAndDrawPoly ( currententity->alpha, false, true );
- else
- R_ClipAndDrawPoly ( 1.0F, false, true );
- r_polydesc.stipple_parity = 0;
-}
-
--- a/ref/r_surf.c
+++ /dev/null
@@ -1,632 +1,0 @@
-// r_surf.c: surface-related refresh code
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-drawsurf_t r_drawsurf;
-
-int lightleft, sourcesstep, blocksize, sourcetstep;
-int lightdelta, lightdeltastep;
-int lightright, lightleftstep, lightrightstep, blockdivshift;
-unsigned blockdivmask;
-void *prowdestbase;
-unsigned char *pbasesource;
-int surfrowbytes; // used by ASM files
-unsigned *r_lightptr;
-int r_stepback;
-int r_lightwidth;
-int r_numhblocks, r_numvblocks;
-unsigned char *r_source, *r_sourcemax;
-
-void R_DrawSurfaceBlock8_mip0 (void);
-void R_DrawSurfaceBlock8_mip1 (void);
-void R_DrawSurfaceBlock8_mip2 (void);
-void R_DrawSurfaceBlock8_mip3 (void);
-
-static void (*surfmiptable[4])(void) = {
- R_DrawSurfaceBlock8_mip0,
- R_DrawSurfaceBlock8_mip1,
- R_DrawSurfaceBlock8_mip2,
- R_DrawSurfaceBlock8_mip3
-};
-
-void R_BuildLightMap (void);
-extern unsigned blocklights[1024]; // allow some very large lightmaps
-
-float surfscale;
-qboolean r_cache_thrash; // set if surface cache is thrashing
-
-int sc_size;
-surfcache_t *sc_rover, *sc_base;
-
-/*
-===============
-R_TextureAnimation
-
-Returns the proper texture for a given time and base texture
-===============
-*/
-image_t *R_TextureAnimation (mtexinfo_t *tex)
-{
- int c;
-
- if (!tex->next)
- return tex->image;
-
- c = currententity->frame % tex->numframes;
- while (c)
- {
- tex = tex->next;
- c--;
- }
-
- return tex->image;
-}
-
-
-/*
-===============
-R_DrawSurface
-===============
-*/
-void R_DrawSurface (void)
-{
- unsigned char *basetptr;
- int smax, tmax, twidth;
- int u;
- int soffset, basetoffset, texwidth;
- int horzblockstep;
- unsigned char *pcolumndest;
- void (*pblockdrawer)(void);
- image_t *mt;
-
- surfrowbytes = r_drawsurf.rowbytes;
-
- mt = r_drawsurf.image;
-
- r_source = mt->pixels[r_drawsurf.surfmip];
-
-// the fractional light values should range from 0 to (VID_GRADES - 1) << 16
-// from a source range of 0 - 255
-
- texwidth = mt->width >> r_drawsurf.surfmip;
-
- blocksize = 16 >> r_drawsurf.surfmip;
- blockdivshift = 4 - r_drawsurf.surfmip;
- blockdivmask = (1 << blockdivshift) - 1;
-
- r_lightwidth = (r_drawsurf.surf->extents[0]>>4)+1;
-
- r_numhblocks = r_drawsurf.surfwidth >> blockdivshift;
- r_numvblocks = r_drawsurf.surfheight >> blockdivshift;
-
-//==============================
-
- pblockdrawer = surfmiptable[r_drawsurf.surfmip];
-// TODO: only needs to be set when there is a display settings change
- horzblockstep = blocksize;
-
- smax = mt->width >> r_drawsurf.surfmip;
- twidth = texwidth;
- tmax = mt->height >> r_drawsurf.surfmip;
- sourcetstep = texwidth;
- r_stepback = tmax * twidth;
-
- r_sourcemax = r_source + (tmax * smax);
-
- soffset = r_drawsurf.surf->texturemins[0];
- basetoffset = r_drawsurf.surf->texturemins[1];
-
-// << 16 components are to guarantee positive values for %
- soffset = ((soffset >> r_drawsurf.surfmip) + (smax << 16)) % smax;
- basetptr = &r_source[((((basetoffset >> r_drawsurf.surfmip)
- + (tmax << 16)) % tmax) * twidth)];
-
- pcolumndest = r_drawsurf.surfdat;
-
- for (u=0 ; u<r_numhblocks; u++)
- {
- r_lightptr = blocklights + u;
-
- prowdestbase = pcolumndest;
-
- pbasesource = basetptr + soffset;
-
- (*pblockdrawer)();
-
- soffset = soffset + blocksize;
- if (soffset >= smax)
- soffset = 0;
-
- pcolumndest += horzblockstep;
- }
-}
-
-
-//=============================================================================
-
-
-/*
-================
-R_DrawSurfaceBlock8_mip0
-================
-*/
-void R_DrawSurfaceBlock8_mip0 (void)
-{
- int v, i, b, lightstep, lighttemp, light;
- unsigned char pix, *psource, *prowdest;
-
- psource = pbasesource;
- prowdest = prowdestbase;
-
- for (v=0 ; v<r_numvblocks ; v++)
- {
- // FIXME: make these locals?
- // FIXME: use delta rather than both right and left, like ASM?
- lightleft = r_lightptr[0];
- lightright = r_lightptr[1];
- r_lightptr += r_lightwidth;
- lightleftstep = (r_lightptr[0] - lightleft) >> 4;
- lightrightstep = (r_lightptr[1] - lightright) >> 4;
-
- for (i=0 ; i<16 ; i++)
- {
- lighttemp = lightleft - lightright;
- lightstep = lighttemp >> 4;
-
- light = lightright;
-
- for (b=15; b>=0; b--)
- {
- pix = psource[b];
- prowdest[b] = ((unsigned char *)vid.colormap)
- [(light & 0xFF00) + pix];
- light += lightstep;
- }
-
- psource += sourcetstep;
- lightright += lightrightstep;
- lightleft += lightleftstep;
- prowdest += surfrowbytes;
- }
-
- if (psource >= r_sourcemax)
- psource -= r_stepback;
- }
-}
-
-
-/*
-================
-R_DrawSurfaceBlock8_mip1
-================
-*/
-void R_DrawSurfaceBlock8_mip1 (void)
-{
- int v, i, b, lightstep, lighttemp, light;
- unsigned char pix, *psource, *prowdest;
-
- psource = pbasesource;
- prowdest = prowdestbase;
-
- for (v=0 ; v<r_numvblocks ; v++)
- {
- // FIXME: make these locals?
- // FIXME: use delta rather than both right and left, like ASM?
- lightleft = r_lightptr[0];
- lightright = r_lightptr[1];
- r_lightptr += r_lightwidth;
- lightleftstep = (r_lightptr[0] - lightleft) >> 3;
- lightrightstep = (r_lightptr[1] - lightright) >> 3;
-
- for (i=0 ; i<8 ; i++)
- {
- lighttemp = lightleft - lightright;
- lightstep = lighttemp >> 3;
-
- light = lightright;
-
- for (b=7; b>=0; b--)
- {
- pix = psource[b];
- prowdest[b] = ((unsigned char *)vid.colormap)
- [(light & 0xFF00) + pix];
- light += lightstep;
- }
-
- psource += sourcetstep;
- lightright += lightrightstep;
- lightleft += lightleftstep;
- prowdest += surfrowbytes;
- }
-
- if (psource >= r_sourcemax)
- psource -= r_stepback;
- }
-}
-
-
-/*
-================
-R_DrawSurfaceBlock8_mip2
-================
-*/
-void R_DrawSurfaceBlock8_mip2 (void)
-{
- int v, i, b, lightstep, lighttemp, light;
- unsigned char pix, *psource, *prowdest;
-
- psource = pbasesource;
- prowdest = prowdestbase;
-
- for (v=0 ; v<r_numvblocks ; v++)
- {
- // FIXME: make these locals?
- // FIXME: use delta rather than both right and left, like ASM?
- lightleft = r_lightptr[0];
- lightright = r_lightptr[1];
- r_lightptr += r_lightwidth;
- lightleftstep = (r_lightptr[0] - lightleft) >> 2;
- lightrightstep = (r_lightptr[1] - lightright) >> 2;
-
- for (i=0 ; i<4 ; i++)
- {
- lighttemp = lightleft - lightright;
- lightstep = lighttemp >> 2;
-
- light = lightright;
-
- for (b=3; b>=0; b--)
- {
- pix = psource[b];
- prowdest[b] = ((unsigned char *)vid.colormap)
- [(light & 0xFF00) + pix];
- light += lightstep;
- }
-
- psource += sourcetstep;
- lightright += lightrightstep;
- lightleft += lightleftstep;
- prowdest += surfrowbytes;
- }
-
- if (psource >= r_sourcemax)
- psource -= r_stepback;
- }
-}
-
-
-/*
-================
-R_DrawSurfaceBlock8_mip3
-================
-*/
-void R_DrawSurfaceBlock8_mip3 (void)
-{
- int v, i, b, lightstep, lighttemp, light;
- unsigned char pix, *psource, *prowdest;
-
- psource = pbasesource;
- prowdest = prowdestbase;
-
- for (v=0 ; v<r_numvblocks ; v++)
- {
- // FIXME: make these locals?
- // FIXME: use delta rather than both right and left, like ASM?
- lightleft = r_lightptr[0];
- lightright = r_lightptr[1];
- r_lightptr += r_lightwidth;
- lightleftstep = (r_lightptr[0] - lightleft) >> 1;
- lightrightstep = (r_lightptr[1] - lightright) >> 1;
-
- for (i=0 ; i<2 ; i++)
- {
- lighttemp = lightleft - lightright;
- lightstep = lighttemp >> 1;
-
- light = lightright;
-
- for (b=1; b>=0; b--)
- {
- pix = psource[b];
- prowdest[b] = ((unsigned char *)vid.colormap)
- [(light & 0xFF00) + pix];
- light += lightstep;
- }
-
- psource += sourcetstep;
- lightright += lightrightstep;
- lightleft += lightleftstep;
- prowdest += surfrowbytes;
- }
-
- if (psource >= r_sourcemax)
- psource -= r_stepback;
- }
-}
-
-
-//============================================================================
-
-
-/*
-================
-R_InitCaches
-
-================
-*/
-void R_InitCaches (void)
-{
- int size;
- int pix;
-
- // calculate size to allocate
- if (sw_surfcacheoverride->value)
- {
- size = sw_surfcacheoverride->value;
- }
- else
- {
- size = SURFCACHE_SIZE_AT_320X240;
-
- pix = vid.width*vid.height;
- if (pix > 64000)
- size += (pix-64000)*3;
- }
-
- // round up to page size
- size = (size + 8191) & ~8191;
-
- ri.Con_Printf (PRINT_ALL,"%ik surface cache\n", size/1024);
-
- sc_size = size;
- sc_base = (surfcache_t *)malloc(size);
- sc_rover = sc_base;
-
- sc_base->next = NULL;
- sc_base->owner = NULL;
- sc_base->size = sc_size;
-}
-
-
-/*
-==================
-D_FlushCaches
-==================
-*/
-void D_FlushCaches (void)
-{
- surfcache_t *c;
-
- if (!sc_base)
- return;
-
- for (c = sc_base ; c ; c = c->next)
- {
- if (c->owner)
- *c->owner = NULL;
- }
-
- sc_rover = sc_base;
- sc_base->next = NULL;
- sc_base->owner = NULL;
- sc_base->size = sc_size;
-}
-
-/*
-=================
-D_SCAlloc
-=================
-*/
-surfcache_t *D_SCAlloc (int width, int size)
-{
- surfcache_t *new;
- qboolean wrapped_this_time;
-
- if ((width < 0) || (width > 256))
- ri.Sys_Error (ERR_FATAL,"D_SCAlloc: bad cache width %d\n", width);
-
- if ((size <= 0) || (size > 0x10000))
- ri.Sys_Error (ERR_FATAL,"D_SCAlloc: bad cache size %d\n", size);
-
- size = (int)(uintptr)&((surfcache_t *)0)->data[size];
- size = (size + 3) & ~3;
- if (size > sc_size)
- ri.Sys_Error (ERR_FATAL,"D_SCAlloc: %i > cache size of %i",size, sc_size);
-
-// if there is not size bytes after the rover, reset to the start
- wrapped_this_time = false;
-
- if ( !sc_rover || (byte *)sc_rover - (byte *)sc_base > sc_size - size)
- {
- if (sc_rover)
- {
- wrapped_this_time = true;
- }
- sc_rover = sc_base;
- }
-
-// colect and free surfcache_t blocks until the rover block is large enough
- new = sc_rover;
- if (sc_rover->owner)
- *sc_rover->owner = NULL;
-
- while (new->size < size)
- {
- // free another
- sc_rover = sc_rover->next;
- if (!sc_rover)
- ri.Sys_Error (ERR_FATAL,"D_SCAlloc: hit the end of memory");
- if (sc_rover->owner)
- *sc_rover->owner = NULL;
-
- new->size += sc_rover->size;
- new->next = sc_rover->next;
- }
-
-// create a fragment out of any leftovers
- if (new->size - size > 256)
- {
- sc_rover = (surfcache_t *)( (byte *)new + size);
- sc_rover->size = new->size - size;
- sc_rover->next = new->next;
- sc_rover->width = 0;
- sc_rover->owner = NULL;
- new->next = sc_rover;
- new->size = size;
- }
- else
- sc_rover = new->next;
-
- new->width = width;
-// DEBUG
- if (width > 0)
- new->height = (size - sizeof(*new) + sizeof(new->data)) / width;
-
- new->owner = NULL; // should be set properly after return
-
- if (d_roverwrapped)
- {
- if (wrapped_this_time || (sc_rover >= d_initial_rover))
- r_cache_thrash = true;
- }
- else if (wrapped_this_time)
- {
- d_roverwrapped = true;
- }
-
- return new;
-}
-
-
-/*
-=================
-D_SCDump
-=================
-*/
-void D_SCDump (void)
-{
- surfcache_t *test;
-
- for (test = sc_base ; test ; test = test->next)
- {
- if (test == sc_rover)
- ri.Con_Printf (PRINT_ALL,"ROVER:\n");
- ri.Con_Printf (PRINT_ALL,"%p : %i bytes %i width\n",test, test->size, test->width);
- }
-}
-
-//=============================================================================
-
-// if the num is not a power of 2, assume it will not repeat
-
-int MaskForNum (int num)
-{
- if (num==128)
- return 127;
- if (num==64)
- return 63;
- if (num==32)
- return 31;
- if (num==16)
- return 15;
- return 255;
-}
-
-int D_log2 (int num)
-{
- int c;
-
- c = 0;
-
- while (num>>=1)
- c++;
- return c;
-}
-
-//=============================================================================
-
-/*
-================
-D_CacheSurface
-================
-*/
-surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel)
-{
- surfcache_t *cache;
-
-//
-// if the surface is animating or flashing, flush the cache
-//
- r_drawsurf.image = R_TextureAnimation (surface->texinfo);
- r_drawsurf.lightadj[0] = r_newrefdef.lightstyles[surface->styles[0]].white*128;
- r_drawsurf.lightadj[1] = r_newrefdef.lightstyles[surface->styles[1]].white*128;
- r_drawsurf.lightadj[2] = r_newrefdef.lightstyles[surface->styles[2]].white*128;
- r_drawsurf.lightadj[3] = r_newrefdef.lightstyles[surface->styles[3]].white*128;
-
-//
-// see if the cache holds apropriate data
-//
- cache = surface->cachespots[miplevel];
-
- if (cache && !cache->dlight && surface->dlightframe != r_framecount
- && cache->image == r_drawsurf.image
- && cache->lightadj[0] == r_drawsurf.lightadj[0]
- && cache->lightadj[1] == r_drawsurf.lightadj[1]
- && cache->lightadj[2] == r_drawsurf.lightadj[2]
- && cache->lightadj[3] == r_drawsurf.lightadj[3] )
- return cache;
-
-//
-// determine shape of surface
-//
- surfscale = 1.0 / (1<<miplevel);
- r_drawsurf.surfmip = miplevel;
- r_drawsurf.surfwidth = surface->extents[0] >> miplevel;
- r_drawsurf.rowbytes = r_drawsurf.surfwidth;
- r_drawsurf.surfheight = surface->extents[1] >> miplevel;
-
-//
-// allocate memory if needed
-//
- if (!cache) // if a texture just animated, don't reallocate it
- {
- cache = D_SCAlloc (r_drawsurf.surfwidth,
- r_drawsurf.surfwidth * r_drawsurf.surfheight);
- surface->cachespots[miplevel] = cache;
- cache->owner = &surface->cachespots[miplevel];
- cache->mipscale = surfscale;
- }
-
- if (surface->dlightframe == r_framecount)
- cache->dlight = 1;
- else
- cache->dlight = 0;
-
- r_drawsurf.surfdat = (pixel_t *)cache->data;
-
- cache->image = r_drawsurf.image;
- cache->lightadj[0] = r_drawsurf.lightadj[0];
- cache->lightadj[1] = r_drawsurf.lightadj[1];
- cache->lightadj[2] = r_drawsurf.lightadj[2];
- cache->lightadj[3] = r_drawsurf.lightadj[3];
-
-//
-// draw and light the surface texture
-//
- r_drawsurf.surf = surface;
-
- c_surf++;
-
- // calculate the lightings
- R_BuildLightMap ();
-
- // rasterize the surface into the cache
- R_DrawSurface ();
-
- return cache;
-}
-
-
--- a/ref/rand1k.h
+++ /dev/null
@@ -1,104 +1,0 @@
-// 1K random numbers in the range 0-255
-0, 144, 49, 207, 149, 122, 89, 229, 210, 191,
-44, 219, 181, 131, 77, 3, 23, 93, 37, 42,
-253, 114, 30, 1, 2, 96, 136, 146, 154, 155,
-42, 169, 115, 90, 14, 155, 200, 205, 133, 77,
-224, 186, 244, 236, 138, 36, 118, 60, 220, 53,
-199, 215, 255, 255, 156, 100, 68, 76, 215, 6,
-96, 23, 173, 14, 2, 235, 70, 69, 150, 176,
-214, 185, 124, 52, 190, 119, 117, 242, 190, 27,
-153, 98, 188, 155, 146, 92, 38, 57, 108, 205,
-132, 253, 192, 88, 43, 168, 125, 16, 179, 129,
-37, 243, 36, 231, 177, 77, 109, 18, 247, 174,
-39, 224, 210, 149, 48, 45, 209, 121, 39, 129,
-187, 103, 71, 145, 174, 193, 184, 121, 31, 94,
-213, 8, 132, 169, 109, 26, 243, 235, 140, 88,
-120, 95, 216, 81, 116, 69, 251, 76, 189, 145,
-50, 194, 214, 101, 128, 227, 7, 254, 146, 12,
-136, 49, 215, 160, 168, 50, 215, 31, 28, 190,
-80, 240, 73, 86, 35, 187, 213, 181, 153, 191,
-64, 36, 0, 15, 206, 218, 53, 29, 141, 3,
-29, 116, 192, 175, 139, 18, 111, 51, 178, 74,
-111, 59, 147, 136, 160, 41, 129, 246, 178, 236,
-48, 86, 45, 254, 117, 255, 24, 160, 24, 112,
-238, 12, 229, 74, 58, 196, 105, 51, 160, 154,
-115, 119, 153, 162, 218, 212, 159, 184, 144, 96,
-47, 188, 142, 231, 62, 48, 154, 178, 149, 89,
-126, 20, 189, 156, 158, 176, 205, 38, 147, 222,
-233, 157, 186, 11, 170, 249, 80, 145, 78, 44,
-27, 222, 217, 190, 39, 83, 20, 19, 164, 209,
-139, 114, 104, 76, 119, 128, 39, 82, 188, 80,
-211, 245, 223, 185, 76, 241, 32, 16, 200, 134,
-156, 244, 18, 224, 167, 82, 26, 129, 58, 74,
-235, 141, 169, 29, 126, 97, 127, 203, 130, 97,
-176, 136, 155, 101, 1, 181, 25, 159, 220, 125,
-191, 127, 97, 201, 141, 91, 244, 161, 45, 95,
-33, 190, 243, 156, 7, 84, 14, 163, 33, 216,
-221, 152, 184, 218, 3, 32, 181, 157, 55, 16,
-43, 159, 87, 81, 94, 169, 205, 206, 134, 156,
-204, 230, 37, 161, 103, 64, 34, 218, 16, 109,
-146, 77, 140, 57, 79, 28, 206, 34, 72, 201,
-229, 202, 190, 157, 92, 219, 58, 221, 58, 63,
-138, 252, 13, 20, 134, 109, 24, 66, 228, 59,
-37, 32, 238, 20, 12, 15, 86, 234, 102, 110,
-242, 214, 136, 215, 177, 101, 66, 1, 134, 244,
-102, 61, 149, 65, 175, 241, 111, 227, 1, 240,
-153, 201, 147, 36, 56, 98, 1, 106, 21, 168,
-218, 16, 207, 169, 177, 205, 135, 175, 36, 176,
-186, 199, 7, 222, 164, 180, 21, 141, 242, 15,
-70, 37, 251, 158, 74, 236, 94, 177, 55, 39,
-61, 133, 230, 27, 231, 113, 20, 200, 43, 249,
-198, 222, 53, 116, 0, 192, 29, 103, 79, 254,
-9, 64, 48, 63, 39, 158, 226, 240, 50, 199,
-165, 168, 232, 116, 235, 170, 38, 162, 145, 108,
-241, 138, 148, 137, 65, 101, 89, 9, 203, 50,
-17, 99, 151, 18, 50, 39, 164, 116, 154, 178,
-112, 175, 101, 213, 151, 51, 243, 224, 100, 252,
-47, 229, 147, 113, 160, 181, 12, 73, 66, 104,
-229, 181, 186, 229, 100, 101, 231, 79, 99, 146,
-90, 187, 190, 188, 189, 35, 51, 69, 174, 233,
-94, 132, 28, 232, 51, 132, 167, 112, 176, 23,
-20, 19, 7, 90, 78, 178, 36, 101, 17, 172,
-185, 50, 177, 157, 167, 139, 25, 139, 12, 249,
-118, 248, 186, 135, 174, 177, 95, 99, 12, 207,
-43, 15, 79, 200, 54, 82, 124, 2, 112, 130,
-155, 194, 102, 89, 215, 241, 159, 255, 13, 144,
-221, 99, 78, 72, 6, 156, 100, 4, 7, 116,
-219, 239, 102, 186, 156, 206, 224, 149, 152, 20,
-203, 118, 151, 150, 145, 208, 172, 87, 2, 68,
-87, 59, 197, 95, 222, 29, 185, 161, 228, 46,
-137, 230, 199, 247, 50, 230, 204, 244, 217, 227,
-160, 47, 157, 67, 64, 187, 201, 43, 182, 123,
-20, 206, 218, 31, 78, 146, 121, 195, 49, 186,
-254, 3, 165, 177, 44, 18, 70, 173, 214, 142,
-95, 199, 59, 163, 59, 52, 248, 72, 5, 196,
-38, 12, 2, 89, 164, 87, 106, 106, 23, 139,
-179, 86, 168, 224, 137, 145, 13, 119, 66, 109,
-221, 124, 22, 144, 181, 199, 221, 217, 75, 221,
-165, 191, 212, 195, 223, 232, 233, 133, 112, 27,
-90, 210, 109, 43, 0, 168, 198, 16, 22, 98,
-175, 206, 39, 36, 12, 88, 4, 250, 165, 13,
-234, 163, 110, 5, 62, 100, 167, 200, 5, 211,
-35, 162, 140, 251, 118, 54, 76, 200, 87, 123,
-155, 26, 252, 193, 38, 116, 182, 255, 198, 164,
-159, 242, 176, 74, 145, 74, 140, 182, 63, 139,
-126, 243, 171, 195, 159, 114, 204, 190, 253, 52,
-161, 232, 151, 235, 129, 125, 115, 227, 240, 46,
-64, 51, 187, 240, 160, 10, 164, 8, 142, 139,
-114, 15, 254, 32, 153, 12, 44, 169, 85, 80,
-167, 105, 109, 56, 173, 42, 127, 129, 205, 111,
-1, 86, 96, 32, 211, 187, 228, 164, 166, 131,
-187, 188, 245, 119, 92, 28, 231, 210, 116, 27,
-222, 194, 10, 106, 239, 17, 42, 54, 29, 151,
-30, 158, 148, 176, 187, 234, 171, 76, 207, 96,
-255, 197, 52, 43, 99, 46, 148, 50, 245, 48,
-97, 77, 30, 50, 11, 197, 194, 225, 0, 114,
-109, 205, 118, 126, 191, 61, 143, 23, 236, 228,
-219, 15, 125, 161, 191, 193, 65, 232, 202, 51,
-141, 13, 133, 202, 180, 6, 187, 141, 234, 224,
-204, 78, 101, 123, 13, 166, 0, 196, 193, 56,
-39, 14, 171, 8, 88, 178, 204, 111, 251, 162,
-75, 122, 223, 20, 25, 36, 36, 235, 79, 95,
-208, 11, 208, 61, 229, 65, 68, 53, 58, 216,
-223, 227, 216, 155, 10, 44, 47, 91, 115, 47,
-228, 159, 139, 233
--- a/server/server.h
+++ /dev/null
@@ -1,314 +1,0 @@
-//#define PARANOID // speed sapping error checking
-
-#define MAX_MASTERS 8 // max recipients for heartbeat packets
-
-typedef enum {
- ss_dead, // no map loaded
- ss_loading, // spawning level edicts
- ss_game, // actively running
- ss_cinematic,
- ss_demo,
- ss_pic
-} server_state_t;
-// some qc commands are only valid before the server has finished
-// initializing (precache commands, static sounds / objects, etc)
-
-typedef struct
-{
- server_state_t state; // precache commands are only valid during load
-
- qboolean attractloop; // running cinematics and demos for the local system only
- qboolean loadgame; // client begins should reuse existing entity
-
- unsigned time; // always sv.framenum * 100 msec
- int framenum;
-
- char name[MAX_QPATH]; // map name, or cinematic name
- struct cmodel_s *models[MAX_MODELS];
-
- char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH];
- entity_state_t baselines[MAX_EDICTS];
-
- // the multicast buffer is used to send a message to a set of clients
- // it is only used to marshall data until SV_Multicast is called
- sizebuf_t multicast;
- byte multicast_buf[MAX_MSGLEN];
-
- // demo server information
- FILE *demofile;
- qboolean timedemo; // don't time sync
-} server_t;
-
-#define EDICT_NUM(n) ((edict_t *)((byte *)ge->edicts + ge->edict_size*(n)))
-#define NUM_FOR_EDICT(e) ( ((byte *)(e)-(byte *)ge->edicts ) / ge->edict_size)
-
-
-typedef enum
-{
- cs_free, // can be reused for a new connection
- cs_zombie, // client has been disconnected, but don't reuse
- // connection for a couple seconds
- cs_connected, // has been assigned to a client_t, but not in game yet
- cs_spawned // client is fully in game
-} clstate_t;
-
-typedef struct
-{
- int areabytes;
- byte areabits[MAX_MAP_AREAS/8]; // portalarea visibility bits
- player_state_t ps;
- int num_entities;
- int first_entity; // into the circular sv_packet_entities[]
- int senttime; // for ping calculations
-} client_frame_t;
-
-#define LATENCY_COUNTS 16
-#define RATE_MESSAGES 10
-
-typedef struct client_s
-{
- clstate_t state;
-
- char userinfo[MAX_INFO_STRING]; // name, etc
-
- int lastframe; // for delta compression
- usercmd_t lastcmd; // for filling in big drops
-
- int commandMsec; // every seconds this is reset, if user
- // commands exhaust it, assume time cheating
-
- int frame_latency[LATENCY_COUNTS];
- int ping;
-
- int message_size[RATE_MESSAGES]; // used to rate drop packets
- int rate;
- int surpressCount; // number of messages rate supressed
-
- edict_t *edict; // EDICT_NUM(clientnum+1)
- char name[32]; // extracted from userinfo, high bits masked
- int messagelevel; // for filtering printed messages
-
- // The datagram is written to by sound calls, prints, temp ents, etc.
- // It can be harmlessly overflowed.
- sizebuf_t datagram;
- byte datagram_buf[MAX_MSGLEN];
-
- client_frame_t frames[UPDATE_BACKUP]; // updates can be delta'd from here
-
- byte *download; // file being downloaded
- int downloadsize; // total bytes (can't use EOF because of paks)
- int downloadcount; // bytes sent
-
- int lastmessage; // sv.framenum when packet was last received
- int lastconnect;
-
- int challenge; // challenge of this user, randomly generated
-
- netchan_t netchan;
-} client_t;
-
-// a client can leave the server in one of four ways:
-// dropping properly by quiting or disconnecting
-// timing out if no valid messages are received for timeout.value seconds
-// getting kicked off by the server operator
-// a program error, like an overflowed reliable buffer
-
-//=============================================================================
-
-// MAX_CHALLENGES is made large to prevent a denial
-// of service attack that could cycle all of them
-// out before legitimate users connected
-#define MAX_CHALLENGES 1024
-
-typedef struct
-{
- netadr_t adr;
- int challenge;
- int time;
-} challenge_t;
-
-
-typedef struct
-{
- qboolean initialized; // sv_init has completed
- int realtime; // always increasing, no clamping, etc
-
- char mapcmd[MAX_TOKEN_CHARS]; // ie: *intro.cin+base
-
- int spawncount; // incremented each server start
- // used to check late spawns
-
- client_t *clients; // [maxclients->value];
- int num_client_entities; // maxclients->value*UPDATE_BACKUP*MAX_PACKET_ENTITIES
- int next_client_entities; // next client_entity to use
- entity_state_t *client_entities; // [num_client_entities]
-
- int last_heartbeat;
-
- challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting
-
- // serverrecord values
- FILE *demofile;
- sizebuf_t demo_multicast;
- byte demo_multicast_buf[MAX_MSGLEN];
-} server_static_t;
-
-//=============================================================================
-
-extern netadr_t net_from;
-extern sizebuf_t net_message;
-
-extern netadr_t master_adr[MAX_MASTERS]; // address of the master server
-
-extern server_static_t svs; // persistant server info
-extern server_t sv; // local server
-
-extern cvar_t *sv_paused;
-extern cvar_t *maxclients;
-extern cvar_t *sv_noreload; // don't reload level state when reentering
-extern cvar_t *sv_airaccelerate; // don't reload level state when reentering
- // development tool
-extern cvar_t *sv_enforcetime;
-
-extern client_t *sv_client;
-extern edict_t *sv_player;
-
-//===========================================================
-
-//
-// sv_main.c
-//
-void SV_FinalMessage (char *message, qboolean reconnect);
-void SV_DropClient (client_t *drop);
-
-int SV_ModelIndex (char *name);
-int SV_SoundIndex (char *name);
-int SV_ImageIndex (char *name);
-
-void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg);
-
-void SV_ExecuteUserCommand (char *s);
-void SV_InitOperatorCommands (void);
-
-void SV_SendServerinfo (client_t *client);
-void SV_UserinfoChanged (client_t *cl);
-
-
-void Master_Heartbeat (void);
-void Master_Packet (void);
-
-//
-// sv_init.c
-//
-void SV_InitGame (void);
-void SV_Map (qboolean attractloop, char *levelstring, qboolean loadgame);
-
-
-//
-// sv_phys.c
-//
-void SV_PrepWorldFrame (void);
-
-//
-// sv_send.c
-//
-typedef enum {RD_NONE, RD_CLIENT, RD_PACKET} redirect_t;
-#define SV_OUTPUTBUF_LENGTH (MAX_MSGLEN - 16)
-
-extern char sv_outputbuf[SV_OUTPUTBUF_LENGTH];
-
-void SV_FlushRedirect (int sv_redirected, char *outputbuf);
-
-void SV_DemoCompleted (void);
-void SV_SendClientMessages (void);
-
-void SV_Multicast (vec3_t origin, multicast_t to);
-void SV_StartSound (vec3_t origin, edict_t *entity, int channel,
- int soundindex, float volume,
- float attenuation, float timeofs);
-void SV_ClientPrintf (client_t *cl, int level, char *fmt, ...);
-void SV_BroadcastPrintf (int level, char *fmt, ...);
-void SV_BroadcastCommand (char *fmt, ...);
-
-//
-// sv_user.c
-//
-void SV_Nextserver (void);
-void SV_ExecuteClientMessage (client_t *cl);
-
-//
-// sv_ccmds.c
-//
-void SV_ReadLevelFile (void);
-void SV_Status_f (void);
-
-//
-// sv_ents.c
-//
-void SV_WriteFrameToClient (client_t *client, sizebuf_t *msg);
-void SV_RecordDemoMessage (void);
-void SV_BuildClientFrame (client_t *client);
-
-
-void SV_Error (char *error, ...);
-
-//
-// sv_game.c
-//
-extern game_export_t *ge;
-
-void SV_InitGameProgs (void);
-void SV_ShutdownGameProgs (void);
-void SV_InitEdict (edict_t *e);
-
-
-
-//============================================================
-
-//
-// high level object sorting to reduce interaction tests
-//
-
-void SV_ClearWorld (void);
-// called after the world model has been loaded, before linking any entities
-
-void SV_UnlinkEdict (edict_t *ent);
-// call before removing an entity, and before trying to move one,
-// so it doesn't clip against itself
-
-void SV_LinkEdict (edict_t *ent);
-// Needs to be called any time an entity changes origin, mins, maxs,
-// or solid. Automatically unlinks if needed.
-// sets ent->v.absmin and ent->v.absmax
-// sets ent->leafnums[] for pvs determination even if the entity
-// is not solid
-
-int SV_AreaEdicts (vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int areatype);
-// fills in a table of edict pointers with edicts that have bounding boxes
-// that intersect the given area. It is possible for a non-axial bmodel
-// to be returned that doesn't actually intersect the area on an exact
-// test.
-// returns the number of pointers filled in
-// ??? does this always return the world?
-
-//===================================================================
-
-//
-// functions that interact with everything apropriate
-//
-int SV_PointContents (vec3_t p);
-// returns the CONTENTS_* value from the world at the given point.
-// Quake 2 extends this to also check entities, to allow moving liquids
-
-
-trace_t SV_Trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask);
-// mins and maxs are relative
-
-// if the entire move stays in a solid volume, trace.allsolid will be set,
-// trace.startsolid will be set, and trace.fraction will be 0
-
-// if the starting point is in a solid, it will be allowed to move out
-// to an open area
-
-// passedict is explicitly excluded from clipping checks (normally NULL)
-
--- a/server/sv_ccmds.c
+++ /dev/null
@@ -1,1030 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-/*
-===============================================================================
-
-OPERATOR CONSOLE ONLY COMMANDS
-
-These commands can only be entered from stdin or by a remote operator datagram
-===============================================================================
-*/
-
-/*
-====================
-SV_SetMaster_f
-
-Specify a list of master servers
-====================
-*/
-void SV_SetMaster_f (void)
-{
- int i, slot;
-
- // only dedicated servers send heartbeats
- if (!dedicated->value)
- {
- Com_Printf ("Only dedicated servers use masters.\n");
- return;
- }
-
- // make sure the server is listed public
- Cvar_Set ("public", "1");
-
- for (i=1 ; i<MAX_MASTERS ; i++)
- memset (&master_adr[i], 0, sizeof(master_adr[i]));
-
- slot = 1; // slot 0 will always contain the id master
- for (i=1 ; i<Cmd_Argc() ; i++)
- {
- if (slot == MAX_MASTERS)
- break;
-
- if (!NET_StringToAdr (Cmd_Argv(i), &master_adr[i]))
- {
- Com_Printf ("Bad address: %s\n", Cmd_Argv(i));
- continue;
- }
- if (master_adr[slot].port == 0)
- master_adr[slot].port = BigShort (PORT_MASTER);
-
- Com_Printf ("Master server at %s\n", NET_AdrToString (master_adr[slot]));
-
- Com_Printf ("Sending a ping.\n");
-
- Netchan_OutOfBandPrint (NS_SERVER, master_adr[slot], "ping");
-
- slot++;
- }
-
- svs.last_heartbeat = -9999999;
-}
-
-
-
-/*
-==================
-SV_SetPlayer
-
-Sets sv_client and sv_player to the player with idnum Cmd_Argv(1)
-==================
-*/
-qboolean SV_SetPlayer (void)
-{
- client_t *cl;
- int i;
- int idnum;
- char *s;
-
- if (Cmd_Argc() < 2)
- return false;
-
- s = Cmd_Argv(1);
-
- // numeric values are just slot numbers
- if (s[0] >= '0' && s[0] <= '9')
- {
- idnum = atoi(Cmd_Argv(1));
- if (idnum < 0 || idnum >= maxclients->value)
- {
- Com_Printf ("Bad client slot: %i\n", idnum);
- return false;
- }
-
- sv_client = &svs.clients[idnum];
- sv_player = sv_client->edict;
- if (!sv_client->state)
- {
- Com_Printf ("Client %i is not active\n", idnum);
- return false;
- }
- return true;
- }
-
- // check for a name match
- for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
- {
- if (!cl->state)
- continue;
- if (!strcmp(cl->name, s))
- {
- sv_client = cl;
- sv_player = sv_client->edict;
- return true;
- }
- }
-
- Com_Printf ("Userid %s is not on the server\n", s);
- return false;
-}
-
-
-/*
-===============================================================================
-
-SAVEGAME FILES
-
-===============================================================================
-*/
-
-/*
-=====================
-SV_WipeSavegame
-
-Delete save/<XXX>/
-=====================
-*/
-void SV_WipeSavegame (char *savename)
-{
- char name[MAX_OSPATH];
- char *s;
-
- Com_DPrintf("SV_WipeSaveGame(%s)\n", savename);
-
- Com_sprintf (name, sizeof(name), "%s/save/%s/server.ssv", FS_Gamedir (), savename);
- remove (name);
- Com_sprintf (name, sizeof(name), "%s/save/%s/game.ssv", FS_Gamedir (), savename);
- remove (name);
-
- Com_sprintf (name, sizeof(name), "%s/save/%s/*.sav", FS_Gamedir (), savename);
- s = Sys_FindFirst( name, 0, 0 );
- while (s)
- {
- remove (s);
- s = Sys_FindNext( 0, 0 );
- }
- Sys_FindClose ();
- Com_sprintf (name, sizeof(name), "%s/save/%s/*.sv2", FS_Gamedir (), savename);
- s = Sys_FindFirst(name, 0, 0 );
- while (s)
- {
- remove (s);
- s = Sys_FindNext( 0, 0 );
- }
- Sys_FindClose ();
-}
-
-
-/*
-================
-CopyFile
-================
-*/
-void CopyFile (char *src, char *dst)
-{
- FILE *f1, *f2;
- int l;
- byte buffer[65536];
-
- Com_DPrintf ("CopyFile (%s, %s)\n", src, dst);
-
- f1 = fopen (src, "rb");
- if (!f1)
- return;
- f2 = fopen (dst, "wb");
- if (!f2)
- {
- fclose (f1);
- return;
- }
-
- while (1)
- {
- l = fread (buffer, 1, sizeof(buffer), f1);
- if (!l)
- break;
- fwrite (buffer, 1, l, f2);
- }
-
- fclose (f1);
- fclose (f2);
-}
-
-
-/*
-================
-SV_CopySaveGame
-================
-*/
-void SV_CopySaveGame (char *src, char *dst)
-{
- char name[MAX_OSPATH], name2[MAX_OSPATH];
- int l, len;
- char *found;
-
- Com_DPrintf("SV_CopySaveGame(%s, %s)\n", src, dst);
-
- SV_WipeSavegame (dst);
-
- // copy the savegame over
- Com_sprintf (name, sizeof(name), "%s/save/%s/server.ssv", FS_Gamedir(), src);
- Com_sprintf (name2, sizeof(name2), "%s/save/%s/server.ssv", FS_Gamedir(), dst);
- FS_CreatePath (name2);
- CopyFile (name, name2);
-
- Com_sprintf (name, sizeof(name), "%s/save/%s/game.ssv", FS_Gamedir(), src);
- Com_sprintf (name2, sizeof(name2), "%s/save/%s/game.ssv", FS_Gamedir(), dst);
- CopyFile (name, name2);
-
- Com_sprintf (name, sizeof(name), "%s/save/%s/", FS_Gamedir(), src);
- len = strlen(name);
- Com_sprintf (name, sizeof(name), "%s/save/%s/*.sav", FS_Gamedir(), src);
- found = Sys_FindFirst(name, 0, 0 );
- while (found)
- {
- strcpy (name+len, found+len);
-
- Com_sprintf (name2, sizeof(name2), "%s/save/%s/%s", FS_Gamedir(), dst, found+len);
- CopyFile (name, name2);
-
- // change sav to sv2
- l = strlen(name);
- strcpy (name+l-3, "sv2");
- l = strlen(name2);
- strcpy (name2+l-3, "sv2");
- CopyFile (name, name2);
-
- found = Sys_FindNext( 0, 0 );
- }
- Sys_FindClose ();
-}
-
-
-/*
-==============
-SV_WriteLevelFile
-
-==============
-*/
-void SV_WriteLevelFile (void)
-{
- char name[MAX_OSPATH];
- FILE *f;
-
- Com_DPrintf("SV_WriteLevelFile()\n");
-
- Com_sprintf (name, sizeof(name), "%s/save/current/%s.sv2", FS_Gamedir(), sv.name);
- f = fopen(name, "wb");
- if (!f)
- {
- Com_Printf ("Failed to open %s\n", name);
- return;
- }
- fwrite (sv.configstrings, sizeof(sv.configstrings), 1, f);
- CM_WritePortalState (f);
- fclose (f);
-
- Com_sprintf (name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name);
- ge->WriteLevel (name);
-}
-
-/*
-==============
-SV_ReadLevelFile
-
-==============
-*/
-void SV_ReadLevelFile (void)
-{
- char name[MAX_OSPATH];
- FILE *f;
-
- Com_DPrintf("SV_ReadLevelFile()\n");
-
- Com_sprintf (name, sizeof(name), "%s/save/current/%s.sv2", FS_Gamedir(), sv.name);
- f = fopen(name, "rb");
- if (!f)
- {
- Com_Printf ("Failed to open %s\n", name);
- return;
- }
- FS_Read (sv.configstrings, sizeof(sv.configstrings), f);
- CM_ReadPortalState (f);
- fclose (f);
-
- Com_sprintf (name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name);
- ge->ReadLevel (name);
-}
-
-/*
-==============
-SV_WriteServerFile
-
-==============
-*/
-void SV_WriteServerFile (qboolean autosave)
-{
- FILE *f;
- cvar_t *var;
- char name[MAX_OSPATH], string[128];
- char comment[32];
- Tm *newtime;
-
- Com_DPrintf("SV_WriteServerFile(%s)\n", autosave ? "true" : "false");
-
- Com_sprintf (name, sizeof(name), "%s/save/current/server.ssv", FS_Gamedir());
- f = fopen (name, "wb");
- if (!f)
- {
- Com_Printf ("Couldn't write %s\n", name);
- return;
- }
- // write the comment field
- memset (comment, 0, sizeof(comment));
-
- if (!autosave)
- {
- newtime = localtime (time(nil));
- Com_sprintf (comment,sizeof(comment), "%2i:%i%i %2i/%2i ", newtime->hour
- , newtime->min/10, newtime->min%10, newtime->mon+1, newtime->mday);
- strncat (comment, sv.configstrings[CS_NAME], sizeof(comment)-1-strlen(comment) );
- }
- else
- { // autosaved
- Com_sprintf (comment, sizeof(comment), "ENTERING %s", sv.configstrings[CS_NAME]);
- }
-
- fwrite (comment, 1, sizeof(comment), f);
-
- // write the mapcmd
- fwrite (svs.mapcmd, 1, sizeof(svs.mapcmd), f);
-
- // write all CVAR_LATCH cvars
- // these will be things like coop, skill, deathmatch, etc
- for (var = cvar_vars ; var ; var=var->next)
- {
- if (!(var->flags & CVAR_LATCH))
- continue;
- if (strlen(var->name) >= sizeof(name)-1
- || strlen(var->string) >= sizeof(string)-1)
- {
- Com_Printf ("Cvar too long: %s = %s\n", var->name, var->string);
- continue;
- }
- memset (name, 0, sizeof(name));
- memset (string, 0, sizeof(string));
- strcpy (name, var->name);
- strcpy (string, var->string);
- fwrite (name, 1, sizeof(name), f);
- fwrite (string, 1, sizeof(string), f);
- }
-
- fclose (f);
-
- // write game state
- Com_sprintf (name, sizeof(name), "%s/save/current/game.ssv", FS_Gamedir());
- ge->WriteGame (name, autosave);
-}
-
-/*
-==============
-SV_ReadServerFile
-
-==============
-*/
-void SV_ReadServerFile (void)
-{
- FILE *f;
- char name[MAX_OSPATH], string[128];
- char comment[32];
- char mapcmd[MAX_TOKEN_CHARS];
-
- Com_DPrintf("SV_ReadServerFile()\n");
-
- Com_sprintf (name, sizeof(name), "%s/save/current/server.ssv", FS_Gamedir());
- f = fopen (name, "rb");
- if (!f)
- {
- Com_Printf ("Couldn't read %s\n", name);
- return;
- }
- // read the comment field
- FS_Read (comment, sizeof(comment), f);
-
- // read the mapcmd
- FS_Read (mapcmd, sizeof(mapcmd), f);
-
- // read all CVAR_LATCH cvars
- // these will be things like coop, skill, deathmatch, etc
- while (1)
- {
- if (!fread (name, 1, sizeof(name), f))
- break;
- FS_Read (string, sizeof(string), f);
- Com_DPrintf ("Set %s = %s\n", name, string);
- Cvar_ForceSet (name, string);
- }
-
- fclose (f);
-
- // start a new game fresh with new cvars
- SV_InitGame ();
-
- strcpy (svs.mapcmd, mapcmd);
-
- // read game state
- Com_sprintf (name, sizeof(name), "%s/save/current/game.ssv", FS_Gamedir());
- ge->ReadGame (name);
-}
-
-
-//=========================================================
-
-
-
-
-/*
-==================
-SV_DemoMap_f
-
-Puts the server in demo mode on a specific map/cinematic
-==================
-*/
-void SV_DemoMap_f (void)
-{
- SV_Map (true, Cmd_Argv(1), false );
-}
-
-/*
-==================
-SV_GameMap_f
-
-Saves the state of the map just being exited and goes to a new map.
-
-If the initial character of the map string is '*', the next map is
-in a new unit, so the current savegame directory is cleared of
-map files.
-
-Example:
-
-*inter.cin+jail
-
-Clears the archived maps, plays the inter.cin cinematic, then
-goes to map jail.bsp.
-==================
-*/
-void SV_GameMap_f (void)
-{
- char *map;
- int i;
- client_t *cl;
- qboolean *savedInuse;
-
- if (Cmd_Argc() != 2)
- {
- Com_Printf ("USAGE: gamemap <map>\n");
- return;
- }
-
- Com_DPrintf("SV_GameMap(%s)\n", Cmd_Argv(1));
-
- FS_CreatePath (va("%s/save/current/", FS_Gamedir()));
-
- // check for clearing the current savegame
- map = Cmd_Argv(1);
- if (map[0] == '*')
- {
- // wipe all the *.sav files
- SV_WipeSavegame ("current");
- }
- else
- { // save the map just exited
- if (sv.state == ss_game)
- {
- // clear all the client inuse flags before saving so that
- // when the level is re-entered, the clients will spawn
- // at spawn points instead of occupying body shells
- savedInuse = malloc(maxclients->value * sizeof(qboolean));
- for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
- {
- savedInuse[i] = cl->edict->inuse;
- cl->edict->inuse = false;
- }
-
- SV_WriteLevelFile ();
-
- // we must restore these for clients to transfer over correctly
- for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
- cl->edict->inuse = savedInuse[i];
- free (savedInuse);
- }
- }
-
- // start up the next map
- SV_Map (false, Cmd_Argv(1), false );
-
- // archive server state
- strncpy (svs.mapcmd, Cmd_Argv(1), sizeof(svs.mapcmd)-1);
-
- // copy off the level to the autosave slot
- if (!dedicated->value)
- {
- SV_WriteServerFile (true);
- SV_CopySaveGame ("current", "save0");
- }
-}
-
-/*
-==================
-SV_Map_f
-
-Goes directly to a given map without any savegame archiving.
-For development work
-==================
-*/
-void SV_Map_f (void)
-{
- char *map;
- char expanded[MAX_QPATH];
-
- // if not a pcx, demo, or cinematic, check to make sure the level exists
- map = Cmd_Argv(1);
- if (!strstr (map, "."))
- {
- Com_sprintf (expanded, sizeof(expanded), "maps/%s.bsp", map);
- if (FS_LoadFile (expanded, NULL) == -1)
- {
- Com_Printf ("Can't find %s\n", expanded);
- return;
- }
- }
-
- sv.state = ss_dead; // don't save current level when changing
- SV_WipeSavegame("current");
- SV_GameMap_f ();
-}
-
-/*
-=====================================================================
-
- SAVEGAMES
-
-=====================================================================
-*/
-
-
-/*
-==============
-SV_Loadgame_f
-
-==============
-*/
-void SV_Loadgame_f (void)
-{
- char name[MAX_OSPATH];
- FILE *f;
- char *dir;
-
- if (Cmd_Argc() != 2)
- {
- Com_Printf ("USAGE: loadgame <directory>\n");
- return;
- }
-
- Com_Printf ("Loading game...\n");
-
- dir = Cmd_Argv(1);
- if (strstr (dir, "..") || strstr (dir, "/") || strstr (dir, "\\") )
- {
- Com_Printf ("Bad savedir.\n");
- }
-
- // make sure the server.ssv file exists
- Com_sprintf (name, sizeof(name), "%s/save/%s/server.ssv", FS_Gamedir(), Cmd_Argv(1));
- f = fopen (name, "rb");
- if (!f)
- {
- Com_Printf ("No such savegame: %s\n", name);
- return;
- }
- fclose (f);
-
- SV_CopySaveGame (Cmd_Argv(1), "current");
-
- SV_ReadServerFile ();
-
- // go to the map
- sv.state = ss_dead; // don't save current level when changing
- SV_Map (false, svs.mapcmd, true);
-}
-
-
-
-/*
-==============
-SV_Savegame_f
-
-==============
-*/
-void SV_Savegame_f (void)
-{
- char *dir;
-
- if (sv.state != ss_game)
- {
- Com_Printf ("You must be in a game to save.\n");
- return;
- }
-
- if (Cmd_Argc() != 2)
- {
- Com_Printf ("USAGE: savegame <directory>\n");
- return;
- }
-
- if (Cvar_VariableValue("deathmatch"))
- {
- Com_Printf ("Can't savegame in a deathmatch\n");
- return;
- }
-
- if (!strcmp (Cmd_Argv(1), "current"))
- {
- Com_Printf ("Can't save to 'current'\n");
- return;
- }
-
- if (maxclients->value == 1 && svs.clients[0].edict->client->ps.stats[STAT_HEALTH] <= 0)
- {
- Com_Printf ("\nCan't savegame while dead!\n");
- return;
- }
-
- dir = Cmd_Argv(1);
- if (strstr (dir, "..") || strstr (dir, "/") || strstr (dir, "\\") )
- {
- Com_Printf ("Bad savedir.\n");
- }
-
- Com_Printf ("Saving game...\n");
-
- // archive current level, including all client edicts.
- // when the level is reloaded, they will be shells awaiting
- // a connecting client
- SV_WriteLevelFile ();
-
- // save server state
- SV_WriteServerFile (false);
-
- // copy it off
- SV_CopySaveGame ("current", dir);
-
- Com_Printf ("Done.\n");
-}
-
-//===============================================================
-
-/*
-==================
-SV_Kick_f
-
-Kick a user off of the server
-==================
-*/
-void SV_Kick_f (void)
-{
- if (!svs.initialized)
- {
- Com_Printf ("No server running.\n");
- return;
- }
-
- if (Cmd_Argc() != 2)
- {
- Com_Printf ("Usage: kick <userid>\n");
- return;
- }
-
- if (!SV_SetPlayer ())
- return;
-
- SV_BroadcastPrintf (PRINT_HIGH, "%s was kicked\n", sv_client->name);
- // print directly, because the dropped client won't get the
- // SV_BroadcastPrintf message
- SV_ClientPrintf (sv_client, PRINT_HIGH, "You were kicked from the game\n");
- SV_DropClient (sv_client);
- sv_client->lastmessage = svs.realtime; // min case there is a funny zombie
-}
-
-
-/*
-================
-SV_Status_f
-================
-*/
-void SV_Status_f (void)
-{
- int i, j, l;
- client_t *cl;
- char *s;
- int ping;
- if (!svs.clients)
- {
- Com_Printf ("No server running.\n");
- return;
- }
- Com_Printf ("map : %s\n", sv.name);
-
- Com_Printf ("num score ping name lastmsg address qport \n");
- Com_Printf ("--- ----- ---- --------------- ------- --------------------- ------\n");
- for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
- {
- if (!cl->state)
- continue;
- Com_Printf ("%3i ", i);
- Com_Printf ("%5i ", cl->edict->client->ps.stats[STAT_FRAGS]);
-
- if (cl->state == cs_connected)
- Com_Printf ("CNCT ");
- else if (cl->state == cs_zombie)
- Com_Printf ("ZMBI ");
- else
- {
- ping = cl->ping < 9999 ? cl->ping : 9999;
- Com_Printf ("%4i ", ping);
- }
-
- Com_Printf ("%s", cl->name);
- l = 16 - strlen(cl->name);
- for (j=0 ; j<l ; j++)
- Com_Printf (" ");
-
- Com_Printf ("%7i ", svs.realtime - cl->lastmessage );
-
- s = NET_AdrToString ( cl->netchan.remote_address);
- Com_Printf ("%s", s);
- l = 22 - strlen(s);
- for (j=0 ; j<l ; j++)
- Com_Printf (" ");
-
- Com_Printf ("%5i", cl->netchan.qport);
-
- Com_Printf ("\n");
- }
- Com_Printf ("\n");
-}
-
-/*
-==================
-SV_ConSay_f
-==================
-*/
-void SV_ConSay_f(void)
-{
- client_t *client;
- int j;
- char *p;
- char text[1024];
-
- if (Cmd_Argc () < 2)
- return;
-
- strcpy (text, "console: ");
- p = Cmd_Args();
-
- if (*p == '"')
- {
- p++;
- p[strlen(p)-1] = 0;
- }
-
- strcat(text, p);
-
- for (j = 0, client = svs.clients; j < maxclients->value; j++, client++)
- {
- if (client->state != cs_spawned)
- continue;
- SV_ClientPrintf(client, PRINT_CHAT, "%s\n", text);
- }
-}
-
-
-/*
-==================
-SV_Heartbeat_f
-==================
-*/
-void SV_Heartbeat_f (void)
-{
- svs.last_heartbeat = -9999999;
-}
-
-
-/*
-===========
-SV_Serverinfo_f
-
- Examine or change the serverinfo string
-===========
-*/
-void SV_Serverinfo_f (void)
-{
- Com_Printf ("Server info settings:\n");
- Info_Print (Cvar_Serverinfo());
-}
-
-
-/*
-===========
-SV_DumpUser_f
-
-Examine all a users info strings
-===========
-*/
-void SV_DumpUser_f (void)
-{
- if (Cmd_Argc() != 2)
- {
- Com_Printf ("Usage: info <userid>\n");
- return;
- }
-
- if (!SV_SetPlayer ())
- return;
-
- Com_Printf ("userinfo\n");
- Com_Printf ("--------\n");
- Info_Print (sv_client->userinfo);
-
-}
-
-
-/*
-==============
-SV_ServerRecord_f
-
-Begins server demo recording. Every entity and every message will be
-recorded, but no playerinfo will be stored. Primarily for demo merging.
-==============
-*/
-void SV_ServerRecord_f (void)
-{
- char name[MAX_OSPATH];
- char buf_data[32768];
- sizebuf_t buf;
- int len;
- int i;
-
- if (Cmd_Argc() != 2)
- {
- Com_Printf ("serverrecord <demoname>\n");
- return;
- }
-
- if (svs.demofile)
- {
- Com_Printf ("Already recording.\n");
- return;
- }
-
- if (sv.state != ss_game)
- {
- Com_Printf ("You must be in a level to record.\n");
- return;
- }
-
- //
- // open the demo file
- //
- Com_sprintf (name, sizeof(name), "%s/demos/%s.dm2", FS_Gamedir(), Cmd_Argv(1));
-
- Com_Printf ("recording to %s.\n", name);
- FS_CreatePath (name);
- svs.demofile = fopen (name, "wb");
- if (!svs.demofile)
- {
- Com_Printf ("ERROR: couldn't open.\n");
- return;
- }
-
- // setup a buffer to catch all multicasts
- SZ_Init (&svs.demo_multicast, svs.demo_multicast_buf, sizeof(svs.demo_multicast_buf));
-
- //
- // write a single giant fake message with all the startup info
- //
- SZ_Init (&buf, (byte *)buf_data, sizeof(buf_data));
-
- //
- // serverdata needs to go over for all types of servers
- // to make sure the protocol is right, and to set the gamedir
- //
- // send the serverdata
- MSG_WriteByte (&buf, svc_serverdata);
- MSG_WriteLong (&buf, PROTOCOL_VERSION);
- MSG_WriteLong (&buf, svs.spawncount);
- // 2 means server demo
- MSG_WriteByte (&buf, 2); // demos are always attract loops
- MSG_WriteString (&buf, Cvar_VariableString ("gamedir"));
- MSG_WriteShort (&buf, -1);
- // send full levelname
- MSG_WriteString (&buf, sv.configstrings[CS_NAME]);
-
- for (i=0 ; i<MAX_CONFIGSTRINGS ; i++)
- if (sv.configstrings[i][0])
- {
- MSG_WriteByte (&buf, svc_configstring);
- MSG_WriteShort (&buf, i);
- MSG_WriteString (&buf, sv.configstrings[i]);
- }
-
- // write it to the demo file
- Com_DPrintf ("signon message length: %i\n", buf.cursize);
- len = LittleLong (buf.cursize);
- fwrite (&len, 4, 1, svs.demofile);
- fwrite (buf.data, buf.cursize, 1, svs.demofile);
-
- // the rest of the demo file will be individual frames
-}
-
-
-/*
-==============
-SV_ServerStop_f
-
-Ends server demo recording
-==============
-*/
-void SV_ServerStop_f (void)
-{
- if (!svs.demofile)
- {
- Com_Printf ("Not doing a serverrecord.\n");
- return;
- }
- fclose (svs.demofile);
- svs.demofile = NULL;
- Com_Printf ("Recording completed.\n");
-}
-
-
-/*
-===============
-SV_KillServer_f
-
-Kick everyone off, possibly in preparation for a new game
-
-===============
-*/
-void SV_KillServer_f (void)
-{
- if (!svs.initialized)
- return;
- SV_Shutdown ("Server was killed.\n", false);
- NET_Config ( false ); // close network sockets
-}
-
-/*
-===============
-SV_ServerCommand_f
-
-Let the game dll handle a command
-===============
-*/
-void SV_ServerCommand_f (void)
-{
- if (!ge)
- {
- Com_Printf ("No game loaded.\n");
- return;
- }
-
- ge->ServerCommand();
-}
-
-//===========================================================
-
-/*
-==================
-SV_InitOperatorCommands
-==================
-*/
-void SV_InitOperatorCommands (void)
-{
- Cmd_AddCommand ("heartbeat", SV_Heartbeat_f);
- Cmd_AddCommand ("kick", SV_Kick_f);
- Cmd_AddCommand ("status", SV_Status_f);
- Cmd_AddCommand ("serverinfo", SV_Serverinfo_f);
- Cmd_AddCommand ("dumpuser", SV_DumpUser_f);
-
- Cmd_AddCommand ("map", SV_Map_f);
- Cmd_AddCommand ("demomap", SV_DemoMap_f);
- Cmd_AddCommand ("gamemap", SV_GameMap_f);
- Cmd_AddCommand ("setmaster", SV_SetMaster_f);
-
- if ( dedicated->value )
- Cmd_AddCommand ("say", SV_ConSay_f);
-
- Cmd_AddCommand ("serverrecord", SV_ServerRecord_f);
- Cmd_AddCommand ("serverstop", SV_ServerStop_f);
-
- Cmd_AddCommand ("save", SV_Savegame_f);
- Cmd_AddCommand ("load", SV_Loadgame_f);
-
- Cmd_AddCommand ("killserver", SV_KillServer_f);
-
- Cmd_AddCommand ("sv", SV_ServerCommand_f);
-}
-
--- a/server/sv_ents.c
+++ /dev/null
@@ -1,708 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-/*
-=============================================================================
-
-Encode a client frame onto the network channel
-
-=============================================================================
-*/
-
-/* commented out in release
-
-// because there can be a lot of projectiles, there is a special
-// network protocol for them
-#define MAX_PROJECTILES 64
-edict_t *projectiles[MAX_PROJECTILES];
-int numprojs;
-cvar_t *sv_projectiles;
-
-qboolean SV_AddProjectileUpdate (edict_t *ent)
-{
- if (!sv_projectiles)
- sv_projectiles = Cvar_Get("sv_projectiles", "1", 0);
-
- if (!sv_projectiles->value)
- return false;
-
- if (!(ent->svflags & SVF_PROJECTILE))
- return false;
- if (numprojs == MAX_PROJECTILES)
- return true;
-
- projectiles[numprojs++] = ent;
- return true;
-}
-
-void SV_EmitProjectileUpdate (sizebuf_t *msg)
-{
- byte bits[16]; // [modelindex] [48 bits] xyz p y 12 12 12 8 8 [entitynum] [e2]
- int n, i;
- edict_t *ent;
- int x, y, z, p, yaw;
- int len;
-
- if (!numprojs)
- return;
-
- MSG_WriteByte (msg, numprojs);
-
- for (n=0 ; n<numprojs ; n++)
- {
- ent = projectiles[n];
- x = (int)(ent->s.origin[0]+4096)>>1;
- y = (int)(ent->s.origin[1]+4096)>>1;
- z = (int)(ent->s.origin[2]+4096)>>1;
- p = (int)(256*ent->s.angles[0]/360)&255;
- yaw = (int)(256*ent->s.angles[1]/360)&255;
-
- len = 0;
- bits[len++] = x;
- bits[len++] = (x>>8) | (y<<4);
- bits[len++] = (y>>4);
- bits[len++] = z;
- bits[len++] = (z>>8);
- if (ent->s.effects & EF_BLASTER)
- bits[len-1] |= 64;
-
- if (ent->s.old_origin[0] != ent->s.origin[0] ||
- ent->s.old_origin[1] != ent->s.origin[1] ||
- ent->s.old_origin[2] != ent->s.origin[2]) {
- bits[len-1] |= 128;
- x = (int)(ent->s.old_origin[0]+4096)>>1;
- y = (int)(ent->s.old_origin[1]+4096)>>1;
- z = (int)(ent->s.old_origin[2]+4096)>>1;
- bits[len++] = x;
- bits[len++] = (x>>8) | (y<<4);
- bits[len++] = (y>>4);
- bits[len++] = z;
- bits[len++] = (z>>8);
- }
-
- bits[len++] = p;
- bits[len++] = yaw;
- bits[len++] = ent->s.modelindex;
-
- bits[len++] = (ent->s.number & 0x7f);
- if (ent->s.number > 255) {
- bits[len-1] |= 128;
- bits[len++] = (ent->s.number >> 7);
- }
-
- for (i=0 ; i<len ; i++)
- MSG_WriteByte (msg, bits[i]);
- }
-}
-*/
-
-/*
-=============
-SV_EmitPacketEntities
-
-Writes a delta update of an entity_state_t list to the message.
-=============
-*/
-void SV_EmitPacketEntities (client_frame_t *from, client_frame_t *to, sizebuf_t *msg)
-{
- entity_state_t *oldent = nil, *newent = nil;
- int oldindex, newindex;
- int oldnum, newnum;
- int from_num_entities;
- int bits;
-
-/*
- if (numprojs)
- MSG_WriteByte (msg, svc_packetentities2);
- else
-*/
- MSG_WriteByte (msg, svc_packetentities);
-
- if (!from)
- from_num_entities = 0;
- else
- from_num_entities = from->num_entities;
-
- newindex = 0;
- oldindex = 0;
- while (newindex < to->num_entities || oldindex < from_num_entities)
- {
- if (newindex >= to->num_entities)
- newnum = 9999;
- else
- {
- newent = &svs.client_entities[(to->first_entity+newindex)%svs.num_client_entities];
- newnum = newent->number;
- }
-
- if (oldindex >= from_num_entities)
- oldnum = 9999;
- else
- {
- oldent = &svs.client_entities[(from->first_entity+oldindex)%svs.num_client_entities];
- oldnum = oldent->number;
- }
-
- if (newnum == oldnum)
- { // delta update from old position
- // because the force parm is false, this will not result
- // in any bytes being emited if the entity has not changed at all
- // note that players are always 'newentities', this updates their oldorigin always
- // and prevents warping
- MSG_WriteDeltaEntity (oldent, newent, msg, false, newent->number <= maxclients->value);
- oldindex++;
- newindex++;
- continue;
- }
-
- if (newnum < oldnum)
- { // this is a new entity, send it from the baseline
- MSG_WriteDeltaEntity (&sv.baselines[newnum], newent, msg, true, true);
- newindex++;
- continue;
- }
-
- if (newnum > oldnum)
- { // the old entity isn't present in the new message
- bits = U_REMOVE;
- if (oldnum >= 256)
- bits |= U_NUMBER16 | U_MOREBITS1;
-
- MSG_WriteByte (msg, bits&255 );
- if (bits & 0x0000ff00)
- MSG_WriteByte (msg, (bits>>8)&255 );
-
- if (bits & U_NUMBER16)
- MSG_WriteShort (msg, oldnum);
- else
- MSG_WriteByte (msg, oldnum);
-
- oldindex++;
- continue;
- }
- }
-
- MSG_WriteShort (msg, 0); // end of packetentities
-
-/*
- if (numprojs)
- SV_EmitProjectileUpdate(msg);
-*/
-}
-
-
-
-/*
-=============
-SV_WritePlayerstateToClient
-
-=============
-*/
-void SV_WritePlayerstateToClient (client_frame_t *from, client_frame_t *to, sizebuf_t *msg)
-{
- int i;
- int pflags;
- player_state_t *ps, *ops;
- player_state_t dummy;
- int statbits;
-
- ps = &to->ps;
- if (!from)
- {
- memset (&dummy, 0, sizeof(dummy));
- ops = &dummy;
- }
- else
- ops = &from->ps;
-
- //
- // determine what needs to be sent
- //
- pflags = 0;
-
- if (ps->pmove.pm_type != ops->pmove.pm_type)
- pflags |= PS_M_TYPE;
-
- if (ps->pmove.origin[0] != ops->pmove.origin[0]
- || ps->pmove.origin[1] != ops->pmove.origin[1]
- || ps->pmove.origin[2] != ops->pmove.origin[2] )
- pflags |= PS_M_ORIGIN;
-
- if (ps->pmove.velocity[0] != ops->pmove.velocity[0]
- || ps->pmove.velocity[1] != ops->pmove.velocity[1]
- || ps->pmove.velocity[2] != ops->pmove.velocity[2] )
- pflags |= PS_M_VELOCITY;
-
- if (ps->pmove.pm_time != ops->pmove.pm_time)
- pflags |= PS_M_TIME;
-
- if (ps->pmove.pm_flags != ops->pmove.pm_flags)
- pflags |= PS_M_FLAGS;
-
- if (ps->pmove.gravity != ops->pmove.gravity)
- pflags |= PS_M_GRAVITY;
-
- if (ps->pmove.delta_angles[0] != ops->pmove.delta_angles[0]
- || ps->pmove.delta_angles[1] != ops->pmove.delta_angles[1]
- || ps->pmove.delta_angles[2] != ops->pmove.delta_angles[2] )
- pflags |= PS_M_DELTA_ANGLES;
-
-
- if (ps->viewoffset[0] != ops->viewoffset[0]
- || ps->viewoffset[1] != ops->viewoffset[1]
- || ps->viewoffset[2] != ops->viewoffset[2] )
- pflags |= PS_VIEWOFFSET;
-
- if (ps->viewangles[0] != ops->viewangles[0]
- || ps->viewangles[1] != ops->viewangles[1]
- || ps->viewangles[2] != ops->viewangles[2] )
- pflags |= PS_VIEWANGLES;
-
- if (ps->kick_angles[0] != ops->kick_angles[0]
- || ps->kick_angles[1] != ops->kick_angles[1]
- || ps->kick_angles[2] != ops->kick_angles[2] )
- pflags |= PS_KICKANGLES;
-
- if (ps->blend[0] != ops->blend[0]
- || ps->blend[1] != ops->blend[1]
- || ps->blend[2] != ops->blend[2]
- || ps->blend[3] != ops->blend[3] )
- pflags |= PS_BLEND;
-
- if (ps->fov != ops->fov)
- pflags |= PS_FOV;
-
- if (ps->rdflags != ops->rdflags)
- pflags |= PS_RDFLAGS;
-
- if (ps->gunframe != ops->gunframe)
- pflags |= PS_WEAPONFRAME;
-
- pflags |= PS_WEAPONINDEX;
-
- //
- // write it
- //
- MSG_WriteByte (msg, svc_playerinfo);
- MSG_WriteShort (msg, pflags);
-
- //
- // write the pmove_state_t
- //
- if (pflags & PS_M_TYPE)
- MSG_WriteByte (msg, ps->pmove.pm_type);
-
- if (pflags & PS_M_ORIGIN)
- {
- MSG_WriteShort (msg, ps->pmove.origin[0]);
- MSG_WriteShort (msg, ps->pmove.origin[1]);
- MSG_WriteShort (msg, ps->pmove.origin[2]);
- }
-
- if (pflags & PS_M_VELOCITY)
- {
- MSG_WriteShort (msg, ps->pmove.velocity[0]);
- MSG_WriteShort (msg, ps->pmove.velocity[1]);
- MSG_WriteShort (msg, ps->pmove.velocity[2]);
- }
-
- if (pflags & PS_M_TIME)
- MSG_WriteByte (msg, ps->pmove.pm_time);
-
- if (pflags & PS_M_FLAGS)
- MSG_WriteByte (msg, ps->pmove.pm_flags);
-
- if (pflags & PS_M_GRAVITY)
- MSG_WriteShort (msg, ps->pmove.gravity);
-
- if (pflags & PS_M_DELTA_ANGLES)
- {
- MSG_WriteShort (msg, ps->pmove.delta_angles[0]);
- MSG_WriteShort (msg, ps->pmove.delta_angles[1]);
- MSG_WriteShort (msg, ps->pmove.delta_angles[2]);
- }
-
- //
- // write the rest of the player_state_t
- //
- if (pflags & PS_VIEWOFFSET)
- {
- MSG_WriteChar (msg, ps->viewoffset[0]*4);
- MSG_WriteChar (msg, ps->viewoffset[1]*4);
- MSG_WriteChar (msg, ps->viewoffset[2]*4);
- }
-
- if (pflags & PS_VIEWANGLES)
- {
- MSG_WriteAngle16 (msg, ps->viewangles[0]);
- MSG_WriteAngle16 (msg, ps->viewangles[1]);
- MSG_WriteAngle16 (msg, ps->viewangles[2]);
- }
-
- if (pflags & PS_KICKANGLES)
- {
- MSG_WriteChar (msg, ps->kick_angles[0]*4);
- MSG_WriteChar (msg, ps->kick_angles[1]*4);
- MSG_WriteChar (msg, ps->kick_angles[2]*4);
- }
-
- if (pflags & PS_WEAPONINDEX)
- {
- MSG_WriteByte (msg, ps->gunindex);
- }
-
- if (pflags & PS_WEAPONFRAME)
- {
- MSG_WriteByte (msg, ps->gunframe);
- MSG_WriteChar (msg, ps->gunoffset[0]*4);
- MSG_WriteChar (msg, ps->gunoffset[1]*4);
- MSG_WriteChar (msg, ps->gunoffset[2]*4);
- MSG_WriteChar (msg, ps->gunangles[0]*4);
- MSG_WriteChar (msg, ps->gunangles[1]*4);
- MSG_WriteChar (msg, ps->gunangles[2]*4);
- }
-
- if (pflags & PS_BLEND)
- {
- MSG_WriteByte (msg, ps->blend[0]*255);
- MSG_WriteByte (msg, ps->blend[1]*255);
- MSG_WriteByte (msg, ps->blend[2]*255);
- MSG_WriteByte (msg, ps->blend[3]*255);
- }
- if (pflags & PS_FOV)
- MSG_WriteByte (msg, ps->fov);
- if (pflags & PS_RDFLAGS)
- MSG_WriteByte (msg, ps->rdflags);
-
- // send stats
- statbits = 0;
- for (i=0 ; i<MAX_STATS ; i++)
- if (ps->stats[i] != ops->stats[i])
- statbits |= 1<<i;
- MSG_WriteLong (msg, statbits);
- for (i=0 ; i<MAX_STATS ; i++)
- if (statbits & (1<<i) )
- MSG_WriteShort (msg, ps->stats[i]);
-}
-
-
-/*
-==================
-SV_WriteFrameToClient
-==================
-*/
-void SV_WriteFrameToClient (client_t *client, sizebuf_t *msg)
-{
- client_frame_t *frame, *oldframe;
- int lastframe;
-
-//Com_Printf ("%i -> %i\n", client->lastframe, sv.framenum);
- // this is the frame we are creating
- frame = &client->frames[sv.framenum & UPDATE_MASK];
-
- if (client->lastframe <= 0)
- { // client is asking for a retransmit
- oldframe = NULL;
- lastframe = -1;
- }
- else if (sv.framenum - client->lastframe >= (UPDATE_BACKUP - 3) )
- { // client hasn't gotten a good message through in a long time
-// Com_Printf ("%s: Delta request from out-of-date packet.\n", client->name);
- oldframe = NULL;
- lastframe = -1;
- }
- else
- { // we have a valid message to delta from
- oldframe = &client->frames[client->lastframe & UPDATE_MASK];
- lastframe = client->lastframe;
- }
-
- MSG_WriteByte (msg, svc_frame);
- MSG_WriteLong (msg, sv.framenum);
- MSG_WriteLong (msg, lastframe); // what we are delta'ing from
- MSG_WriteByte (msg, client->surpressCount); // rate dropped packets
- client->surpressCount = 0;
-
- // send over the areabits
- MSG_WriteByte (msg, frame->areabytes);
- SZ_Write (msg, frame->areabits, frame->areabytes);
-
- // delta encode the playerstate
- SV_WritePlayerstateToClient (oldframe, frame, msg);
-
- // delta encode the entities
- SV_EmitPacketEntities (oldframe, frame, msg);
-}
-
-
-/*
-=============================================================================
-
-Build a client frame structure
-
-=============================================================================
-*/
-
-byte fatpvs[65536/8]; // 32767 is MAX_MAP_LEAFS
-
-/*
-============
-SV_FatPVS
-
-The client will interpolate the view position,
-so we can't use a single PVS point
-===========
-*/
-void SV_FatPVS (vec3_t org)
-{
- int leafs[64];
- int i, j, count;
- int longs;
- byte *src;
- vec3_t mins, maxs;
-
- for (i=0 ; i<3 ; i++)
- {
- mins[i] = org[i] - 8;
- maxs[i] = org[i] + 8;
- }
-
- count = CM_BoxLeafnums (mins, maxs, leafs, 64, NULL);
- if (count < 1)
- Com_Error (ERR_FATAL, "SV_FatPVS: count < 1");
- longs = (CM_NumClusters()+31)>>5;
-
- // convert leafs to clusters
- for (i=0 ; i<count ; i++)
- leafs[i] = CM_LeafCluster(leafs[i]);
-
- memcpy (fatpvs, CM_ClusterPVS(leafs[0]), longs<<2);
- // or in all the other leaf bits
- for (i=1 ; i<count ; i++)
- {
- for (j=0 ; j<i ; j++)
- if (leafs[i] == leafs[j])
- break;
- if (j != i)
- continue; // already have the cluster we want
- src = CM_ClusterPVS(leafs[i]);
- for (j=0 ; j<longs ; j++)
- ((long *)fatpvs)[j] |= ((long *)src)[j];
- }
-}
-
-
-/*
-=============
-SV_BuildClientFrame
-
-Decides which entities are going to be visible to the client, and
-copies off the playerstat and areabits.
-=============
-*/
-void SV_BuildClientFrame (client_t *client)
-{
- int e, i;
- vec3_t org;
- edict_t *ent;
- edict_t *clent;
- client_frame_t *frame;
- entity_state_t *state;
- int l;
- int clientarea, clientcluster;
- int leafnum;
- int c_fullsend;
- byte *clientphs;
- byte *bitvector;
-
- clent = client->edict;
- if (!clent->client)
- return; // not in game yet
-
- //numprojs = 0; // no projectiles yet
-
- // this is the frame we are creating
- frame = &client->frames[sv.framenum & UPDATE_MASK];
-
- frame->senttime = svs.realtime; // save it for ping calc later
-
- // find the client's PVS
- for (i=0 ; i<3 ; i++)
- org[i] = clent->client->ps.pmove.origin[i]*0.125 + clent->client->ps.viewoffset[i];
-
- leafnum = CM_PointLeafnum (org);
- clientarea = CM_LeafArea (leafnum);
- clientcluster = CM_LeafCluster (leafnum);
-
- // calculate the visible areas
- frame->areabytes = CM_WriteAreaBits (frame->areabits, clientarea);
-
- // grab the current player_state_t
- frame->ps = clent->client->ps;
-
-
- SV_FatPVS (org);
- clientphs = CM_ClusterPHS (clientcluster);
-
- // build up the list of visible entities
- frame->num_entities = 0;
- frame->first_entity = svs.next_client_entities;
-
- c_fullsend = 0;
-
- for (e=1 ; e<ge->num_edicts ; e++)
- {
- ent = EDICT_NUM(e);
-
- // ignore ents without visible models
- if (ent->svflags & SVF_NOCLIENT)
- continue;
-
- // ignore ents without visible models unless they have an effect
- if (!ent->s.modelindex && !ent->s.effects && !ent->s.sound
- && !ent->s.event)
- continue;
-
- // ignore if not touching a PV leaf
- if (ent != clent)
- {
- // check area
- if (!CM_AreasConnected (clientarea, ent->areanum))
- { // doors can legally straddle two areas, so
- // we may need to check another one
- if (!ent->areanum2
- || !CM_AreasConnected (clientarea, ent->areanum2))
- continue; // blocked by a door
- }
-
- // beams just check one point for PHS
- if (ent->s.renderfx & RF_BEAM)
- {
- l = ent->clusternums[0];
- if ( !(clientphs[l >> 3] & (1 << (l&7) )) )
- continue;
- }
- else
- {
- // FIXME: if an ent has a model and a sound, but isn't
- // in the PVS, only the PHS, clear the model
- if (ent->s.sound)
- {
- bitvector = fatpvs; //clientphs;
- }
- else
- bitvector = fatpvs;
-
- if (ent->num_clusters == -1)
- { // too many leafs for individual check, go by headnode
- if (!CM_HeadnodeVisible (ent->headnode, bitvector))
- continue;
- c_fullsend++;
- }
- else
- { // check individual leafs
- for (i=0 ; i < ent->num_clusters ; i++)
- {
- l = ent->clusternums[i];
- if (bitvector[l >> 3] & (1 << (l&7) ))
- break;
- }
- if (i == ent->num_clusters)
- continue; // not visible
- }
-
- if (!ent->s.modelindex)
- { // don't send sounds if they will be attenuated away
- vec3_t delta;
- float len;
-
- VectorSubtract (org, ent->s.origin, delta);
- len = VectorLength (delta);
- if (len > 400)
- continue;
- }
- }
- }
-
-/*
- if (SV_AddProjectileUpdate(ent))
- continue; // added as a special projectile
-*/
-
- // add it to the circular client_entities array
- state = &svs.client_entities[svs.next_client_entities%svs.num_client_entities];
- if (ent->s.number != e)
- {
- Com_DPrintf ("FIXING ENT->S.NUMBER!!!\n");
- ent->s.number = e;
- }
- *state = ent->s;
-
- // don't mark players missiles as solid
- if (ent->owner == client->edict)
- state->solid = 0;
-
- svs.next_client_entities++;
- frame->num_entities++;
- }
-}
-
-
-/*
-==================
-SV_RecordDemoMessage
-
-Save everything in the world out without deltas.
-Used for recording footage for merged or assembled demos
-==================
-*/
-void SV_RecordDemoMessage (void)
-{
- int e;
- edict_t *ent;
- entity_state_t nostate;
- sizebuf_t buf;
- byte buf_data[32768];
- int len;
-
- if (!svs.demofile)
- return;
-
- memset (&nostate, 0, sizeof(nostate));
- SZ_Init (&buf, buf_data, sizeof(buf_data));
-
- // write a frame message that doesn't contain a player_state_t
- MSG_WriteByte (&buf, svc_frame);
- MSG_WriteLong (&buf, sv.framenum);
-
- MSG_WriteByte (&buf, svc_packetentities);
-
- e = 1;
- ent = EDICT_NUM(e);
- while (e < ge->num_edicts)
- {
- // ignore ents without visible models unless they have an effect
- if (ent->inuse &&
- ent->s.number &&
- (ent->s.modelindex || ent->s.effects || ent->s.sound || ent->s.event) &&
- !(ent->svflags & SVF_NOCLIENT))
- MSG_WriteDeltaEntity (&nostate, &ent->s, &buf, false, true);
-
- e++;
- ent = EDICT_NUM(e);
- }
-
- MSG_WriteShort (&buf, 0); // end of packetentities
-
- // now add the accumulated multicast information
- SZ_Write (&buf, svs.demo_multicast.data, svs.demo_multicast.cursize);
- SZ_Clear (&svs.demo_multicast);
-
- // now write the entire message to the file, prefixed by the length
- len = LittleLong (buf.cursize);
- fwrite (&len, 4, 1, svs.demofile);
- fwrite (buf.data, buf.cursize, 1, svs.demofile);
-}
-
--- a/server/sv_game.c
+++ /dev/null
@@ -1,379 +1,0 @@
-// sv_game.c -- interface to the game dll
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-game_export_t *ge;
-
-
-/*
-===============
-PF_Unicast
-
-Sends the contents of the mutlicast buffer to a single client
-===============
-*/
-void PF_Unicast (edict_t *ent, qboolean reliable)
-{
- int p;
- client_t *client;
-
- if (!ent)
- return;
-
- p = NUM_FOR_EDICT(ent);
- if (p < 1 || p > maxclients->value)
- return;
-
- client = svs.clients + (p-1);
-
- if (reliable)
- SZ_Write (&client->netchan.message, sv.multicast.data, sv.multicast.cursize);
- else
- SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize);
-
- SZ_Clear (&sv.multicast);
-}
-
-
-/*
-===============
-PF_dprintf
-
-Debug print to server console
-===============
-*/
-void PF_dprintf (char *fmt, ...)
-{
- char msg[1024];
- va_list argptr;
-
- va_start (argptr,fmt);
- vsprintf (msg, fmt, argptr);
- va_end (argptr);
-
- Com_Printf ("%s", msg);
-}
-
-
-/*
-===============
-PF_cprintf
-
-Print to a single client
-===============
-*/
-void PF_cprintf (edict_t *ent, int level, char *fmt, ...)
-{
- char msg[1024];
- va_list argptr;
- int n = 0;
-
- if (ent)
- {
- n = NUM_FOR_EDICT(ent);
- if (n < 1 || n > maxclients->value)
- Com_Error (ERR_DROP, "cprintf to a non-client");
- }
-
- va_start (argptr,fmt);
- vsprintf (msg, fmt, argptr);
- va_end (argptr);
-
- if (ent)
- SV_ClientPrintf (svs.clients+(n-1), level, "%s", msg);
- else
- Com_Printf ("%s", msg);
-}
-
-
-/*
-===============
-PF_centerprintf
-
-centerprint to a single client
-===============
-*/
-void PF_centerprintf (edict_t *ent, char *fmt, ...)
-{
- char msg[1024];
- va_list argptr;
- int n;
-
- n = NUM_FOR_EDICT(ent);
- if (n < 1 || n > maxclients->value)
- return; // Com_Error (ERR_DROP, "centerprintf to a non-client");
-
- va_start (argptr,fmt);
- vsprintf (msg, fmt, argptr);
- va_end (argptr);
-
- MSG_WriteByte (&sv.multicast,svc_centerprint);
- MSG_WriteString (&sv.multicast,msg);
- PF_Unicast (ent, true);
-}
-
-
-/*
-===============
-PF_error
-
-Abort the server with a game error
-===============
-*/
-void PF_error (char *fmt, ...)
-{
- char msg[1024];
- va_list argptr;
-
- va_start (argptr,fmt);
- vsprintf (msg, fmt, argptr);
- va_end (argptr);
-
- Com_Error (ERR_DROP, "Game Error: %s", msg);
-}
-
-
-/*
-=================
-PF_setmodel
-
-Also sets mins and maxs for inline bmodels
-=================
-*/
-void PF_setmodel (edict_t *ent, char *name)
-{
- int i;
- cmodel_t *mod;
-
- if (!name)
- Com_Error (ERR_DROP, "PF_setmodel: NULL");
-
- i = SV_ModelIndex (name);
-
-// ent->model = name;
- ent->s.modelindex = i;
-
-// if it is an inline model, get the size information for it
- if (name[0] == '*')
- {
- mod = CM_InlineModel (name);
- VectorCopy (mod->mins, ent->mins);
- VectorCopy (mod->maxs, ent->maxs);
- SV_LinkEdict (ent);
- }
-
-}
-
-/*
-===============
-PF_Configstring
-
-===============
-*/
-void PF_Configstring (int index, char *val)
-{
- if (index < 0 || index >= MAX_CONFIGSTRINGS)
- Com_Error (ERR_DROP, "configstring: bad index %i\n", index);
-
- if (!val)
- val = "";
-
- // change the string in sv
- strcpy (sv.configstrings[index], val);
-
- if (sv.state != ss_loading)
- { // send the update to everyone
- SZ_Clear (&sv.multicast);
- MSG_WriteChar (&sv.multicast, svc_configstring);
- MSG_WriteShort (&sv.multicast, index);
- MSG_WriteString (&sv.multicast, val);
-
- SV_Multicast (vec3_origin, MULTICAST_ALL_R);
- }
-}
-
-
-
-void PF_WriteChar (int c) {MSG_WriteChar (&sv.multicast, c);}
-void PF_WriteByte (int c) {MSG_WriteByte (&sv.multicast, c);}
-void PF_WriteShort (int c) {MSG_WriteShort (&sv.multicast, c);}
-void PF_WriteLong (int c) {MSG_WriteLong (&sv.multicast, c);}
-void PF_WriteFloat (float f) {MSG_WriteFloat (&sv.multicast, f);}
-void PF_WriteString (char *s) {MSG_WriteString (&sv.multicast, s);}
-void PF_WritePos (vec3_t pos) {MSG_WritePos (&sv.multicast, pos);}
-void PF_WriteDir (vec3_t dir) {MSG_WriteDir (&sv.multicast, dir);}
-void PF_WriteAngle (float f) {MSG_WriteAngle (&sv.multicast, f);}
-
-
-/*
-=================
-PF_inPVS
-
-Also checks portalareas so that doors block sight
-=================
-*/
-qboolean PF_inPVS (vec3_t p1, vec3_t p2)
-{
- int leafnum;
- int cluster;
- int area1, area2;
- byte *mask;
-
- leafnum = CM_PointLeafnum (p1);
- cluster = CM_LeafCluster (leafnum);
- area1 = CM_LeafArea (leafnum);
- mask = CM_ClusterPVS (cluster);
-
- leafnum = CM_PointLeafnum (p2);
- cluster = CM_LeafCluster (leafnum);
- area2 = CM_LeafArea (leafnum);
- if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
- return false;
- if (!CM_AreasConnected (area1, area2))
- return false; // a door blocks sight
- return true;
-}
-
-
-/*
-=================
-PF_inPHS
-
-Also checks portalareas so that doors block sound
-=================
-*/
-qboolean PF_inPHS (vec3_t p1, vec3_t p2)
-{
- int leafnum;
- int cluster;
- int area1, area2;
- byte *mask;
-
- leafnum = CM_PointLeafnum (p1);
- cluster = CM_LeafCluster (leafnum);
- area1 = CM_LeafArea (leafnum);
- mask = CM_ClusterPHS (cluster);
-
- leafnum = CM_PointLeafnum (p2);
- cluster = CM_LeafCluster (leafnum);
- area2 = CM_LeafArea (leafnum);
- if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
- return false; // more than one bounce away
- if (!CM_AreasConnected (area1, area2))
- return false; // a door blocks hearing
-
- return true;
-}
-
-void PF_StartSound (edict_t *entity, int channel, int sound_num, float volume,
- float attenuation, float timeofs)
-{
- if (!entity)
- return;
- SV_StartSound (NULL, entity, channel, sound_num, volume, attenuation, timeofs);
-}
-
-//==============================================
-
-/*
-===============
-SV_ShutdownGameProgs
-
-Called when either the entire server is being killed, or
-it is changing to a different game directory.
-===============
-*/
-void SV_ShutdownGameProgs (void)
-{
- if (!ge)
- return;
- ge->Shutdown ();
- Sys_UnloadGame ();
- ge = NULL;
-}
-
-/*
-===============
-SV_InitGameProgs
-
-Init the game subsystem for a new map
-===============
-*/
-void SCR_DebugGraph (float value, int color);
-
-void SV_InitGameProgs (void)
-{
- game_import_t import;
-
- // unload anything we have now
- if (ge)
- SV_ShutdownGameProgs ();
-
-
- // load a new game dll
- import.multicast = SV_Multicast;
- import.unicast = PF_Unicast;
- import.bprintf = SV_BroadcastPrintf;
- import.dprintf = PF_dprintf;
- import.cprintf = PF_cprintf;
- import.centerprintf = PF_centerprintf;
- import.error = PF_error;
-
- import.linkentity = SV_LinkEdict;
- import.unlinkentity = SV_UnlinkEdict;
- import.BoxEdicts = SV_AreaEdicts;
- import.trace = SV_Trace;
- import.pointcontents = SV_PointContents;
- import.setmodel = PF_setmodel;
- import.inPVS = PF_inPVS;
- import.inPHS = PF_inPHS;
- import.Pmove = Pmove;
-
- import.modelindex = SV_ModelIndex;
- import.soundindex = SV_SoundIndex;
- import.imageindex = SV_ImageIndex;
-
- import.configstring = PF_Configstring;
- import.sound = PF_StartSound;
- import.positioned_sound = SV_StartSound;
-
- import.WriteChar = PF_WriteChar;
- import.WriteByte = PF_WriteByte;
- import.WriteShort = PF_WriteShort;
- import.WriteLong = PF_WriteLong;
- import.WriteFloat = PF_WriteFloat;
- import.WriteString = PF_WriteString;
- import.WritePosition = PF_WritePos;
- import.WriteDir = PF_WriteDir;
- import.WriteAngle = PF_WriteAngle;
-
- import.TagMalloc = Z_TagMalloc;
- import.TagFree = Z_Free;
- import.FreeTags = Z_FreeTags;
-
- import.cvar = Cvar_Get;
- import.cvar_set = Cvar_Set;
- import.cvar_forceset = Cvar_ForceSet;
-
- import.argc = Cmd_Argc;
- import.argv = Cmd_Argv;
- import.args = Cmd_Args;
- import.AddCommandString = Cbuf_AddText;
-
- import.DebugGraph = SCR_DebugGraph;
- import.SetAreaPortalState = CM_SetAreaPortalState;
- import.AreasConnected = CM_AreasConnected;
-
- ge = GetGameAPI(&import);
-
- if (!ge)
- Com_Error (ERR_DROP, "failed to load game DLL");
- if (ge->apiversion != GAME_API_VERSION)
- Com_Error (ERR_DROP, "game is version %i, not %i", ge->apiversion,
- GAME_API_VERSION);
-
- ge->Init ();
-}
--- a/server/sv_init.c
+++ /dev/null
@@ -1,448 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-server_static_t svs; // persistant server info
-server_t sv; // local server
-
-/*
-================
-SV_FindIndex
-
-================
-*/
-int SV_FindIndex (char *name, int start, int max, qboolean create)
-{
- int i;
-
- if (!name || !name[0])
- return 0;
-
- for (i=1 ; i<max && sv.configstrings[start+i][0] ; i++)
- if (!strcmp(sv.configstrings[start+i], name))
- return i;
-
- if (!create)
- return 0;
-
- if (i == max)
- Com_Error (ERR_DROP, "*Index: overflow");
-
- strncpy (sv.configstrings[start+i], name, sizeof(sv.configstrings[i]));
-
- if (sv.state != ss_loading)
- { // send the update to everyone
- SZ_Clear (&sv.multicast);
- MSG_WriteChar (&sv.multicast, svc_configstring);
- MSG_WriteShort (&sv.multicast, start+i);
- MSG_WriteString (&sv.multicast, name);
- SV_Multicast (vec3_origin, MULTICAST_ALL_R);
- }
-
- return i;
-}
-
-
-int SV_ModelIndex (char *name)
-{
- return SV_FindIndex (name, CS_MODELS, MAX_MODELS, true);
-}
-
-int SV_SoundIndex (char *name)
-{
- return SV_FindIndex (name, CS_SOUNDS, MAX_SOUNDS, true);
-}
-
-int SV_ImageIndex (char *name)
-{
- return SV_FindIndex (name, CS_IMAGES, MAX_IMAGES, true);
-}
-
-
-/*
-================
-SV_CreateBaseline
-
-Entity baselines are used to compress the update messages
-to the clients -- only the fields that differ from the
-baseline will be transmitted
-================
-*/
-void SV_CreateBaseline (void)
-{
- edict_t *svent;
- int entnum;
-
- for (entnum = 1; entnum < ge->num_edicts ; entnum++)
- {
- svent = EDICT_NUM(entnum);
- if (!svent->inuse)
- continue;
- if (!svent->s.modelindex && !svent->s.sound && !svent->s.effects)
- continue;
- svent->s.number = entnum;
-
- //
- // take current state as baseline
- //
- VectorCopy (svent->s.origin, svent->s.old_origin);
- sv.baselines[entnum] = svent->s;
- }
-}
-
-
-/*
-=================
-SV_CheckForSavegame
-=================
-*/
-void SV_CheckForSavegame (void)
-{
- char name[MAX_OSPATH];
- FILE *f;
- int i;
-
- if (sv_noreload->value)
- return;
-
- if (Cvar_VariableValue ("deathmatch"))
- return;
-
- Com_sprintf (name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name);
- f = fopen (name, "rb");
- if (!f)
- return; // no savegame
-
- fclose (f);
-
- SV_ClearWorld ();
-
- // get configstrings and areaportals
- SV_ReadLevelFile ();
-
- if (!sv.loadgame)
- { // coming back to a level after being in a different
- // level, so run it for ten seconds
-
- // rlava2 was sending too many lightstyles, and overflowing the
- // reliable data. temporarily changing the server state to loading
- // prevents these from being passed down.
- server_state_t previousState; // PGM
-
- previousState = sv.state; // PGM
- sv.state = ss_loading; // PGM
- for (i=0 ; i<100 ; i++)
- ge->RunFrame ();
-
- sv.state = previousState; // PGM
- }
-}
-
-
-/*
-================
-SV_SpawnServer
-
-Change the server to a new map, taking all connected
-clients along with it.
-
-================
-*/
-void SV_SpawnServer (char *server, char *spawnpoint, server_state_t serverstate, qboolean attractloop, qboolean loadgame)
-{
- int i;
- unsigned checksum;
-
- if (attractloop)
- Cvar_Set ("paused", "0");
-
- Com_Printf ("------- Server Initialization -------\n");
-
- Com_DPrintf ("SpawnServer: %s\n",server);
- if (sv.demofile)
- fclose (sv.demofile);
-
- svs.spawncount++; // any partially connected client will be
- // restarted
- sv.state = ss_dead;
- Com_SetServerState (sv.state);
-
- // wipe the entire per-level structure
- memset (&sv, 0, sizeof(sv));
- svs.realtime = 0;
- sv.loadgame = loadgame;
- sv.attractloop = attractloop;
-
- // save name for levels that don't set message
- strcpy (sv.configstrings[CS_NAME], server);
- if (Cvar_VariableValue ("deathmatch"))
- {
- sprintf(sv.configstrings[CS_AIRACCEL], "%g", sv_airaccelerate->value);
- pm_airaccelerate = sv_airaccelerate->value;
- }
- else
- {
- strcpy(sv.configstrings[CS_AIRACCEL], "0");
- pm_airaccelerate = 0;
- }
-
- SZ_Init (&sv.multicast, sv.multicast_buf, sizeof(sv.multicast_buf));
-
- strcpy (sv.name, server);
-
- // leave slots at start for clients only
- for (i=0 ; i<maxclients->value ; i++)
- {
- // needs to reconnect
- if (svs.clients[i].state > cs_connected)
- svs.clients[i].state = cs_connected;
- svs.clients[i].lastframe = -1;
- }
-
- sv.time = 1000;
-
- strcpy (sv.name, server);
- strcpy (sv.configstrings[CS_NAME], server);
-
- if (serverstate != ss_game)
- {
- sv.models[1] = CM_LoadMap ("", false, &checksum); // no real map
- }
- else
- {
- Com_sprintf (sv.configstrings[CS_MODELS+1],sizeof(sv.configstrings[CS_MODELS+1]),
- "maps/%s.bsp", server);
- sv.models[1] = CM_LoadMap (sv.configstrings[CS_MODELS+1], false, &checksum);
- }
- Com_sprintf (sv.configstrings[CS_MAPCHECKSUM],sizeof(sv.configstrings[CS_MAPCHECKSUM]),
- "%i", checksum);
-
- //
- // clear physics interaction links
- //
- SV_ClearWorld ();
-
- for (i=1 ; i< CM_NumInlineModels() ; i++)
- {
- Com_sprintf (sv.configstrings[CS_MODELS+1+i], sizeof(sv.configstrings[CS_MODELS+1+i]),
- "*%i", i);
- sv.models[i+1] = CM_InlineModel (sv.configstrings[CS_MODELS+1+i]);
- }
-
- //
- // spawn the rest of the entities on the map
- //
-
- // precache and static commands can be issued during
- // map initialization
- sv.state = ss_loading;
- Com_SetServerState (sv.state);
-
- // load and spawn all other entities
- ge->SpawnEntities ( sv.name, CM_EntityString(), spawnpoint );
-
- // run two frames to allow everything to settle
- ge->RunFrame ();
- ge->RunFrame ();
-
- // all precaches are complete
- sv.state = serverstate;
- Com_SetServerState (sv.state);
-
- // create a baseline for more efficient communications
- SV_CreateBaseline ();
-
- // check for a savegame
- SV_CheckForSavegame ();
-
- // set serverinfo variable
- Cvar_FullSet ("mapname", sv.name, CVAR_SERVERINFO | CVAR_NOSET);
-
- Com_Printf ("-------------------------------------\n");
-}
-
-/*
-==============
-SV_InitGame
-
-A brand new game has been started
-==============
-*/
-void SV_InitGame (void)
-{
- int i;
- edict_t *ent;
- char idmaster[32];
-
- if (svs.initialized)
- {
- // cause any connected clients to reconnect
- SV_Shutdown ("Server restarted\n", true);
- }
- else
- {
- // make sure the client is down
- CL_Drop ();
- SCR_BeginLoadingPlaque ();
- }
-
- // get any latched variable changes (maxclients, etc)
- Cvar_GetLatchedVars ();
-
- svs.initialized = true;
-
- if (Cvar_VariableValue ("coop") && Cvar_VariableValue ("deathmatch"))
- {
- Com_Printf("Deathmatch and Coop both set, disabling Coop\n");
- Cvar_FullSet ("coop", "0", CVAR_SERVERINFO | CVAR_LATCH);
- }
-
- // dedicated servers are can't be single player and are usually DM
- // so unless they explicity set coop, force it to deathmatch
- if (dedicated->value)
- {
- if (!Cvar_VariableValue ("coop"))
- Cvar_FullSet ("deathmatch", "1", CVAR_SERVERINFO | CVAR_LATCH);
- }
-
- // init clients
- if (Cvar_VariableValue ("deathmatch"))
- {
- if (maxclients->value <= 1)
- Cvar_FullSet ("maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH);
- else if (maxclients->value > MAX_CLIENTS)
- Cvar_FullSet ("maxclients", va("%i", MAX_CLIENTS), CVAR_SERVERINFO | CVAR_LATCH);
- }
- else if (Cvar_VariableValue ("coop"))
- {
- if (maxclients->value <= 1 || maxclients->value > 4)
- Cvar_FullSet ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
-#ifdef COPYPROTECT
- if (!sv.attractloop && !dedicated->value)
- Sys_CopyProtect ();
-#endif
- }
- else // non-deathmatch, non-coop is one player
- {
- Cvar_FullSet ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);
-#ifdef COPYPROTECT
- if (!sv.attractloop)
- Sys_CopyProtect ();
-#endif
- }
-
- svs.spawncount = rand();
- svs.clients = Z_Malloc (sizeof(client_t)*maxclients->value);
- svs.num_client_entities = maxclients->value*UPDATE_BACKUP*64;
- svs.client_entities = Z_Malloc (sizeof(entity_state_t)*svs.num_client_entities);
-
- // init network stuff
- NET_Config ( (maxclients->value > 1) );
-
- // heartbeats will always be sent to the id master
- svs.last_heartbeat = -99999; // send immediately
- Com_sprintf(idmaster, sizeof(idmaster), "192.246.40.37:%i", PORT_MASTER);
- NET_StringToAdr (idmaster, &master_adr[0]);
-
- // init game
- SV_InitGameProgs ();
- for (i=0 ; i<maxclients->value ; i++)
- {
- ent = EDICT_NUM(i+1);
- ent->s.number = i+1;
- svs.clients[i].edict = ent;
- memset (&svs.clients[i].lastcmd, 0, sizeof(svs.clients[i].lastcmd));
- }
-}
-
-
-/*
-======================
-SV_Map
-
- the full syntax is:
-
- map [*]<map>$<startspot>+<nextserver>
-
-command from the console or progs.
-Map can also be a.cin, .pcx, or .dm2 file
-Nextserver is used to allow a cinematic to play, then proceed to
-another level:
-
- map tram.cin+jail_e3
-======================
-*/
-void SV_Map (qboolean attractloop, char *levelstring, qboolean loadgame)
-{
- char level[MAX_QPATH];
- char *ch;
- int l;
- char spawnpoint[MAX_QPATH];
-
- sv.loadgame = loadgame;
- sv.attractloop = attractloop;
-
- if (sv.state == ss_dead && !sv.loadgame)
- SV_InitGame (); // the game is just starting
-
- strcpy (level, levelstring);
-
- // if there is a + in the map, set nextserver to the remainder
- ch = strstr(level, "+");
- if (ch)
- {
- *ch = 0;
- Cvar_Set ("nextserver", va("gamemap \"%s\"", ch+1));
- }
- else
- Cvar_Set ("nextserver", "");
-
- //ZOID special hack for end game screen in coop mode
- if (Cvar_VariableValue ("coop") && !cistrcmp(level, "victory.pcx"))
- Cvar_Set ("nextserver", "gamemap \"*base1\"");
-
- // if there is a $, use the remainder as a spawnpoint
- ch = strstr(level, "$");
- if (ch)
- {
- *ch = 0;
- strcpy (spawnpoint, ch+1);
- }
- else
- spawnpoint[0] = 0;
-
- // skip the end-of-unit flag if necessary
- if (level[0] == '*')
- strcpy (level, level+1);
-
- l = strlen(level);
- if (l > 4 && !strcmp (level+l-4, ".cin") )
- {
- SCR_BeginLoadingPlaque (); // for local system
- SV_BroadcastCommand ("changing\n");
- SV_SpawnServer (level, spawnpoint, ss_cinematic, attractloop, loadgame);
- }
- else if (l > 4 && !strcmp (level+l-4, ".dm2") )
- {
- SCR_BeginLoadingPlaque (); // for local system
- SV_BroadcastCommand ("changing\n");
- SV_SpawnServer (level, spawnpoint, ss_demo, attractloop, loadgame);
- }
- else if (l > 4 && !strcmp (level+l-4, ".pcx") )
- {
- SCR_BeginLoadingPlaque (); // for local system
- SV_BroadcastCommand ("changing\n");
- SV_SpawnServer (level, spawnpoint, ss_pic, attractloop, loadgame);
- }
- else
- {
- SCR_BeginLoadingPlaque (); // for local system
- SV_BroadcastCommand ("changing\n");
- SV_SendClientMessages ();
- SV_SpawnServer (level, spawnpoint, ss_game, attractloop, loadgame);
- Cbuf_CopyToDefer ();
- }
-
- SV_BroadcastCommand ("reconnect\n");
-}
--- a/server/sv_main.c
+++ /dev/null
@@ -1,1035 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-netadr_t master_adr[MAX_MASTERS]; // address of group servers
-
-client_t *sv_client; // current client
-
-cvar_t *sv_paused;
-cvar_t *sv_timedemo;
-
-cvar_t *sv_enforcetime;
-
-cvar_t *timeout; // seconds without any message
-cvar_t *zombietime; // seconds to sink messages after disconnect
-
-cvar_t *rcon_password; // password for remote server commands
-
-cvar_t *allow_download;
-cvar_t *allow_download_players;
-cvar_t *allow_download_models;
-cvar_t *allow_download_sounds;
-cvar_t *allow_download_maps;
-
-cvar_t *sv_airaccelerate;
-
-cvar_t *sv_noreload; // don't reload level state when reentering
-
-cvar_t *maxclients; // FIXME: rename sv_maxclients
-cvar_t *sv_showclamp;
-
-cvar_t *hostname;
-cvar_t *public_server; // should heartbeats be sent
-
-cvar_t *sv_reconnect_limit; // minimum seconds between connect messages
-
-void Master_Shutdown (void);
-
-
-//============================================================================
-
-
-/*
-=====================
-SV_DropClient
-
-Called when the player is totally leaving the server, either willingly
-or unwillingly. This is NOT called if the entire server is quiting
-or crashing.
-=====================
-*/
-void SV_DropClient (client_t *drop)
-{
- // add the disconnect
- MSG_WriteByte (&drop->netchan.message, svc_disconnect);
-
- if (drop->state == cs_spawned)
- {
- // call the prog function for removing a client
- // this will remove the body, among other things
- ge->ClientDisconnect (drop->edict);
- }
-
- if (drop->download)
- {
- FS_FreeFile (drop->download);
- drop->download = NULL;
- }
-
- drop->state = cs_zombie; // become free in a few seconds
- drop->name[0] = 0;
-}
-
-
-
-/*
-==============================================================================
-
-CONNECTIONLESS COMMANDS
-
-==============================================================================
-*/
-
-/*
-===============
-SV_StatusString
-
-Builds the string that is sent as heartbeats and status replies
-===============
-*/
-char *SV_StatusString (void)
-{
- char player[1024];
- static char status[MAX_MSGLEN - 16];
- int i;
- client_t *cl;
- int statusLength;
- int playerLength;
-
- strcpy (status, Cvar_Serverinfo());
- strcat (status, "\n");
- statusLength = strlen(status);
-
- for (i=0 ; i<maxclients->value ; i++)
- {
- cl = &svs.clients[i];
- if (cl->state == cs_connected || cl->state == cs_spawned )
- {
- Com_sprintf (player, sizeof(player), "%i %i \"%s\"\n",
- cl->edict->client->ps.stats[STAT_FRAGS], cl->ping, cl->name);
- playerLength = strlen(player);
- if (statusLength + playerLength >= sizeof(status) )
- break; // can't hold any more
- strcpy (status + statusLength, player);
- statusLength += playerLength;
- }
- }
-
- return status;
-}
-
-/*
-================
-SVC_Status
-
-Responds with all the info that qplug or qspy can see
-================
-*/
-void SVC_Status (void)
-{
- Netchan_OutOfBandPrint (NS_SERVER, net_from, "print\n%s", SV_StatusString());
-/*
- Com_BeginRedirect (RD_PACKET, sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect);
- Com_Printf (SV_StatusString());
- Com_EndRedirect ();
-*/
-}
-
-/*
-================
-SVC_Ack
-
-================
-*/
-void SVC_Ack (void)
-{
- Com_Printf ("Ping acknowledge from %s\n", NET_AdrToString(net_from));
-}
-
-/*
-================
-SVC_Info
-
-Responds with short info for broadcast scans
-The second parameter should be the current protocol version number.
-================
-*/
-void SVC_Info (void)
-{
- char string[64];
- int i, count;
- int version;
-
- if (maxclients->value == 1)
- return; // ignore in single player
-
- version = atoi (Cmd_Argv(1));
-
- if (version != PROTOCOL_VERSION)
- Com_sprintf (string, sizeof(string), "%s: wrong version\n", hostname->string, sizeof(string));
- else
- {
- count = 0;
- for (i=0 ; i<maxclients->value ; i++)
- if (svs.clients[i].state >= cs_connected)
- count++;
-
- Com_sprintf (string, sizeof(string), "%16s %8s %2i/%2i\n", hostname->string, sv.name, count, (int)maxclients->value);
- }
-
- Netchan_OutOfBandPrint (NS_SERVER, net_from, "info\n%s", string);
-}
-
-/*
-================
-SVC_Ping
-
-Just responds with an acknowledgement
-================
-*/
-void SVC_Ping (void)
-{
- Netchan_OutOfBandPrint (NS_SERVER, net_from, "ack");
-}
-
-
-/*
-=================
-SVC_GetChallenge
-
-Returns a challenge number that can be used
-in a subsequent client_connect command.
-We do this to prevent denial of service attacks that
-flood the server with invalid connection IPs. With a
-challenge, they must give a valid IP address.
-=================
-*/
-void SVC_GetChallenge (void)
-{
- int i;
- int oldest;
- int oldestTime;
-
- oldest = 0;
- oldestTime = 0x7fffffff;
-
- // see if we already have a challenge for this ip
- for (i = 0 ; i < MAX_CHALLENGES ; i++)
- {
- if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
- break;
- if (svs.challenges[i].time < oldestTime)
- {
- oldestTime = svs.challenges[i].time;
- oldest = i;
- }
- }
-
- if (i == MAX_CHALLENGES)
- {
- // overwrite the oldest
- svs.challenges[oldest].challenge = rand() & 0x7fff;
- svs.challenges[oldest].adr = net_from;
- svs.challenges[oldest].time = curtime;
- i = oldest;
- }
-
- // send it back
- Netchan_OutOfBandPrint (NS_SERVER, net_from, "challenge %i", svs.challenges[i].challenge);
-}
-
-/*
-==================
-SVC_DirectConnect
-
-A connection request that did not come from the master
-==================
-*/
-void SVC_DirectConnect (void)
-{
- char userinfo[MAX_INFO_STRING];
- netadr_t adr;
- int i;
- client_t *cl, *newcl;
- client_t temp;
- edict_t *ent;
- int edictnum;
- int version;
- int qport;
- int challenge;
-
- adr = net_from;
-
- Com_DPrintf ("SVC_DirectConnect ()\n");
-
- version = atoi(Cmd_Argv(1));
- if (version != PROTOCOL_VERSION)
- {
- Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nServer is version %4.2f.\n", VERSION);
- Com_DPrintf (" rejected connect from version %i\n", version);
- return;
- }
-
- qport = atoi(Cmd_Argv(2));
-
- challenge = atoi(Cmd_Argv(3));
-
- strncpy (userinfo, Cmd_Argv(4), sizeof(userinfo)-1);
- userinfo[sizeof(userinfo) - 1] = 0;
-
- // force the IP key/value pair so the game can filter based on ip
- Info_SetValueForKey (userinfo, "ip", NET_AdrToString(net_from));
-
- // attractloop servers are ONLY for local clients
- if (sv.attractloop)
- {
- if (!NET_IsLocalAddress (adr))
- {
- Com_Printf ("Remote connect in attract loop. Ignored.\n");
- Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nConnection refused.\n");
- return;
- }
- }
-
- // see if the challenge is valid
- if (!NET_IsLocalAddress (adr))
- {
- for (i=0 ; i<MAX_CHALLENGES ; i++)
- {
- if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
- {
- if (challenge == svs.challenges[i].challenge)
- break; // good
- Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nBad challenge.\n");
- return;
- }
- }
- if (i == MAX_CHALLENGES)
- {
- Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nNo challenge for address.\n");
- return;
- }
- }
-
- newcl = &temp;
- memset (newcl, 0, sizeof(client_t));
-
- // if there is already a slot for this ip, reuse it
- for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
- {
- if (cl->state == cs_free)
- continue;
- if (NET_CompareBaseAdr (adr, cl->netchan.remote_address)
- && ( cl->netchan.qport == qport
- || adr.port == cl->netchan.remote_address.port ) )
- {
- if (!NET_IsLocalAddress (adr) && (svs.realtime - cl->lastconnect) < ((int)sv_reconnect_limit->value * 1000))
- {
- Com_DPrintf ("%s:reconnect rejected : too soon\n", NET_AdrToString (adr));
- return;
- }
- Com_Printf ("%s:reconnect\n", NET_AdrToString (adr));
- newcl = cl;
- goto gotnewcl;
- }
- }
-
- // find a client slot
- newcl = NULL;
- for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
- {
- if (cl->state == cs_free)
- {
- newcl = cl;
- break;
- }
- }
- if (!newcl)
- {
- Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nServer is full.\n");
- Com_DPrintf ("Rejected a connection.\n");
- return;
- }
-
-gotnewcl:
- // build a new connection
- // accept the new client
- // this is the only place a client_t is ever initialized
- *newcl = temp;
- sv_client = newcl;
- edictnum = (newcl-svs.clients)+1;
- ent = EDICT_NUM(edictnum);
- newcl->edict = ent;
- newcl->challenge = challenge; // save challenge for checksumming
-
- // get the game a chance to reject this connection or modify the userinfo
- if (!(ge->ClientConnect (ent, userinfo)))
- {
- if (*Info_ValueForKey (userinfo, "rejmsg"))
- Netchan_OutOfBandPrint (NS_SERVER, adr, "print\n%s\nConnection refused.\n",
- Info_ValueForKey (userinfo, "rejmsg"));
- else
- Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nConnection refused.\n" );
- Com_DPrintf ("Game rejected a connection.\n");
- return;
- }
-
- // parse some info from the info strings
- strncpy (newcl->userinfo, userinfo, sizeof(newcl->userinfo)-1);
- SV_UserinfoChanged (newcl);
-
- // send the connect packet to the client
- Netchan_OutOfBandPrint (NS_SERVER, adr, "client_connect");
-
- Netchan_Setup (NS_SERVER, &newcl->netchan , adr, qport);
-
- newcl->state = cs_connected;
-
- SZ_Init (&newcl->datagram, newcl->datagram_buf, sizeof(newcl->datagram_buf) );
- newcl->datagram.allowoverflow = true;
- newcl->lastmessage = svs.realtime; // don't timeout
- newcl->lastconnect = svs.realtime;
-}
-
-int Rcon_Validate (void)
-{
- if (!strlen (rcon_password->string))
- return 0;
-
- if (strcmp (Cmd_Argv(1), rcon_password->string) )
- return 0;
-
- return 1;
-}
-
-/*
-===============
-SVC_RemoteCommand
-
-A client issued an rcon command.
-Shift down the remaining args
-Redirect all printfs
-===============
-*/
-void SVC_RemoteCommand (void)
-{
- int i;
- char remaining[1024];
-
- i = Rcon_Validate ();
-
- if (i == 0)
- Com_Printf ("Bad rcon from %s:\n%s\n", NET_AdrToString (net_from), net_message.data+4);
- else
- Com_Printf ("Rcon from %s:\n%s\n", NET_AdrToString (net_from), net_message.data+4);
-
- Com_BeginRedirect (RD_PACKET, sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect);
-
- if (!Rcon_Validate ())
- {
- Com_Printf ("Bad rcon_password.\n");
- }
- else
- {
- remaining[0] = 0;
-
- for (i=2 ; i<Cmd_Argc() ; i++)
- {
- strcat (remaining, Cmd_Argv(i) );
- strcat (remaining, " ");
- }
-
- Cmd_ExecuteString (remaining);
- }
-
- Com_EndRedirect ();
-}
-
-/*
-=================
-SV_ConnectionlessPacket
-
-A connectionless packet has four leading 0xff
-characters to distinguish it from a game channel.
-Clients that are in the game can still send
-connectionless packets.
-=================
-*/
-void SV_ConnectionlessPacket (void)
-{
- char *s;
- char *c;
-
- MSG_BeginReading (&net_message);
- MSG_ReadLong (&net_message); // skip the -1 marker
-
- s = MSG_ReadStringLine (&net_message);
-
- Cmd_TokenizeString (s, false);
-
- c = Cmd_Argv(0);
- Com_DPrintf ("Packet %s : %s\n", NET_AdrToString(net_from), c);
-
- if (!strcmp(c, "ping"))
- SVC_Ping ();
- else if (!strcmp(c, "ack"))
- SVC_Ack ();
- else if (!strcmp(c,"status"))
- SVC_Status ();
- else if (!strcmp(c,"info"))
- SVC_Info ();
- else if (!strcmp(c,"getchallenge"))
- SVC_GetChallenge ();
- else if (!strcmp(c,"connect"))
- SVC_DirectConnect ();
- else if (!strcmp(c, "rcon"))
- SVC_RemoteCommand ();
- else
- Com_Printf ("bad connectionless packet from %s:\n%s\n"
- , NET_AdrToString (net_from), s);
-}
-
-
-//============================================================================
-
-/*
-===================
-SV_CalcPings
-
-Updates the cl->ping variables
-===================
-*/
-void SV_CalcPings (void)
-{
- int i, j;
- client_t *cl;
- int total, count;
-
- for (i=0 ; i<maxclients->value ; i++)
- {
- cl = &svs.clients[i];
- if (cl->state != cs_spawned )
- continue;
-
-/*
- if (cl->lastframe > 0)
- cl->frame_latency[sv.framenum&(LATENCY_COUNTS-1)] = sv.framenum - cl->lastframe + 1;
- else
- cl->frame_latency[sv.framenum&(LATENCY_COUNTS-1)] = 0;
-*/
-
- total = 0;
- count = 0;
- for (j=0 ; j<LATENCY_COUNTS ; j++)
- {
- if (cl->frame_latency[j] > 0)
- {
- count++;
- total += cl->frame_latency[j];
- }
- }
- if (!count)
- cl->ping = 0;
- else
- //cl->ping = total*100/count - 100;
- cl->ping = total / count;
-
- // let the game dll know about the ping
- cl->edict->client->ping = cl->ping;
- }
-}
-
-
-/*
-===================
-SV_GiveMsec
-
-Every few frames, gives all clients an allotment of milliseconds
-for their command moves. If they exceed it, assume cheating.
-===================
-*/
-void SV_GiveMsec (void)
-{
- int i;
- client_t *cl;
-
- if (sv.framenum & 15)
- return;
-
- for (i=0 ; i<maxclients->value ; i++)
- {
- cl = &svs.clients[i];
- if (cl->state == cs_free )
- continue;
-
- cl->commandMsec = 1800; // 1600 + some slop
- }
-}
-
-
-/*
-=================
-SV_ReadPackets
-=================
-*/
-void SV_ReadPackets (void)
-{
- int i;
- client_t *cl;
- int qport;
-
- while (NET_GetPacket (NS_SERVER, &net_from, &net_message))
- {
- // check for connectionless packet (0xffffffff) first
- if (*(int *)net_message.data == -1)
- {
- SV_ConnectionlessPacket ();
- continue;
- }
-
- // read the qport out of the message so we can fix up
- // stupid address translating routers
- MSG_BeginReading (&net_message);
- MSG_ReadLong (&net_message); // sequence number
- MSG_ReadLong (&net_message); // sequence number
- qport = MSG_ReadShort (&net_message) & 0xffff;
-
- // check for packets from connected clients
- for (i=0, cl=svs.clients ; i<maxclients->value ; i++,cl++)
- {
- if (cl->state == cs_free)
- continue;
- if (!NET_CompareBaseAdr (net_from, cl->netchan.remote_address))
- continue;
- if (cl->netchan.qport != qport)
- continue;
- if (cl->netchan.remote_address.port != net_from.port)
- {
- Com_Printf ("SV_ReadPackets: fixing up a translated port\n");
- cl->netchan.remote_address.port = net_from.port;
- }
-
- if (Netchan_Process(&cl->netchan, &net_message))
- { // this is a valid, sequenced packet, so process it
- if (cl->state != cs_zombie)
- {
- cl->lastmessage = svs.realtime; // don't timeout
- SV_ExecuteClientMessage (cl);
- }
- }
- break;
- }
-
- if (i != maxclients->value)
- continue;
- }
-}
-
-/*
-==================
-SV_CheckTimeouts
-
-If a packet has not been received from a client for timeout->value
-seconds, drop the conneciton. Server frames are used instead of
-realtime to avoid dropping the local client while debugging.
-
-When a client is normally dropped, the client_t goes into a zombie state
-for a few seconds to make sure any final reliable message gets resent
-if necessary
-==================
-*/
-void SV_CheckTimeouts (void)
-{
- int i;
- client_t *cl;
- int droppoint;
- int zombiepoint;
-
- droppoint = svs.realtime - 1000*timeout->value;
- zombiepoint = svs.realtime - 1000*zombietime->value;
-
- for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
- {
- // message times may be wrong across a changelevel
- if (cl->lastmessage > svs.realtime)
- cl->lastmessage = svs.realtime;
-
- if (cl->state == cs_zombie
- && cl->lastmessage < zombiepoint)
- {
- cl->state = cs_free; // can now be reused
- continue;
- }
- if ( (cl->state == cs_connected || cl->state == cs_spawned)
- && cl->lastmessage < droppoint)
- {
- SV_BroadcastPrintf (PRINT_HIGH, "%s timed out\n", cl->name);
- SV_DropClient (cl);
- cl->state = cs_free; // don't bother with zombie state
- }
- }
-}
-
-/*
-================
-SV_PrepWorldFrame
-
-This has to be done before the world logic, because
-player processing happens outside RunWorldFrame
-================
-*/
-void SV_PrepWorldFrame (void)
-{
- edict_t *ent;
- int i;
-
- for (i=0 ; i<ge->num_edicts ; i++)
- {
- ent = EDICT_NUM(i);
- // events only last for a single message
- ent->s.event = 0;
- }
-
-}
-
-
-/*
-=================
-SV_RunGameFrame
-=================
-*/
-void SV_RunGameFrame (void)
-{
- if (host_speeds->value)
- time_before_game = Sys_Milliseconds ();
-
- // we always need to bump framenum, even if we
- // don't run the world, otherwise the delta
- // compression can get confused when a client
- // has the "current" frame
- sv.framenum++;
- sv.time = sv.framenum*100;
-
- // don't run if paused
- if (!sv_paused->value || maxclients->value > 1)
- {
- ge->RunFrame ();
-
- // never get more than one tic behind
- if (sv.time < svs.realtime)
- {
- if (sv_showclamp->value)
- Com_Printf ("sv highclamp\n");
- svs.realtime = sv.time;
- }
- }
-
- if (host_speeds->value)
- time_after_game = Sys_Milliseconds ();
-
-}
-
-/*
-==================
-SV_Frame
-
-==================
-*/
-void SV_Frame (int msec)
-{
- time_before_game = time_after_game = 0;
-
- // if server is not active, do nothing
- if (!svs.initialized)
- return;
-
- svs.realtime += msec;
-
- // keep the random time dependent
- rand ();
-
- // check timeouts
- SV_CheckTimeouts ();
-
- // get packets from clients
- SV_ReadPackets ();
-
- // move autonomous things around if enough time has passed
- if (!sv_timedemo->value && svs.realtime < sv.time)
- {
- // never let the time get too far off
- if (sv.time - svs.realtime > 100)
- {
- if (sv_showclamp->value)
- Com_Printf ("sv lowclamp\n");
- svs.realtime = sv.time - 100;
- }
- NET_Sleep(sv.time - svs.realtime);
- return;
- }
-
- // update ping based on the last known frame from all clients
- SV_CalcPings ();
-
- // give the clients some timeslices
- SV_GiveMsec ();
-
- // let everything in the world think and move
- SV_RunGameFrame ();
-
- // send messages back to the clients that had packets read this frame
- SV_SendClientMessages ();
-
- // save the entire world state if recording a serverdemo
- SV_RecordDemoMessage ();
-
- // send a heartbeat to the master if needed
- Master_Heartbeat ();
-
- // clear teleport flags, etc for next frame
- SV_PrepWorldFrame ();
-
-}
-
-//============================================================================
-
-/*
-================
-Master_Heartbeat
-
-Send a message to the master every few minutes to
-let it know we are alive, and log information
-================
-*/
-#define HEARTBEAT_SECONDS 300
-void Master_Heartbeat (void)
-{
- char *string;
- int i;
-
-
- if (!dedicated->value)
- return; // only dedicated servers send heartbeats
-
- if (!public_server->value)
- return; // a private dedicated game
-
- // check for time wraparound
- if (svs.last_heartbeat > svs.realtime)
- svs.last_heartbeat = svs.realtime;
-
- if (svs.realtime - svs.last_heartbeat < HEARTBEAT_SECONDS*1000)
- return; // not time to send yet
-
- svs.last_heartbeat = svs.realtime;
-
- // send the same string that we would give for a status OOB command
- string = SV_StatusString();
-
- // send to group master
- for (i=0 ; i<MAX_MASTERS ; i++)
- if (master_adr[i].port)
- {
- Com_Printf ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i]));
- Netchan_OutOfBandPrint (NS_SERVER, master_adr[i], "heartbeat\n%s", string);
- }
-}
-
-/*
-=================
-Master_Shutdown
-
-Informs all masters that this server is going down
-=================
-*/
-void Master_Shutdown (void)
-{
- int i;
-
- if (!dedicated->value)
- return; // only dedicated servers send heartbeats
-
- if (!public_server->value)
- return; // a private dedicated game
-
- // send to group master
- for (i=0 ; i<MAX_MASTERS ; i++)
- if (master_adr[i].port)
- {
- if (i > 0)
- Com_Printf ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i]));
- Netchan_OutOfBandPrint (NS_SERVER, master_adr[i], "shutdown");
- }
-}
-
-//============================================================================
-
-
-/*
-=================
-SV_UserinfoChanged
-
-Pull specific info from a newly changed userinfo string
-into a more C freindly form.
-=================
-*/
-void SV_UserinfoChanged (client_t *cl)
-{
- char *val;
- int i;
-
- // call prog code to allow overrides
- ge->ClientUserinfoChanged (cl->edict, cl->userinfo);
-
- // name for C code
- strncpy (cl->name, Info_ValueForKey (cl->userinfo, "name"), sizeof(cl->name)-1);
- // mask off high bit
- for (i=0 ; i<sizeof(cl->name) ; i++)
- cl->name[i] &= 127;
-
- // rate command
- val = Info_ValueForKey (cl->userinfo, "rate");
- if (strlen(val))
- {
- i = atoi(val);
- cl->rate = i;
- if (cl->rate < 100)
- cl->rate = 100;
- if (cl->rate > 15000)
- cl->rate = 15000;
- }
- else
- cl->rate = 5000;
-
- // msg command
- val = Info_ValueForKey (cl->userinfo, "msg");
- if (strlen(val))
- {
- cl->messagelevel = atoi(val);
- }
-
-}
-
-
-//============================================================================
-
-/*
-===============
-SV_Init
-
-Only called at quake2.exe startup, not for each game
-===============
-*/
-void SV_Init (void)
-{
- SV_InitOperatorCommands ();
-
- rcon_password = Cvar_Get ("rcon_password", "", 0);
- Cvar_Get ("skill", "1", 0);
- Cvar_Get ("deathmatch", "0", CVAR_LATCH);
- Cvar_Get ("coop", "0", CVAR_LATCH);
- Cvar_Get ("dmflags", va("%i", DF_INSTANT_ITEMS), CVAR_SERVERINFO);
- Cvar_Get ("fraglimit", "0", CVAR_SERVERINFO);
- Cvar_Get ("timelimit", "0", CVAR_SERVERINFO);
- Cvar_Get ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH);
- Cvar_Get ("protocol", va("%i", PROTOCOL_VERSION), CVAR_SERVERINFO|CVAR_NOSET);;
- maxclients = Cvar_Get ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);
- hostname = Cvar_Get ("hostname", "noname", CVAR_SERVERINFO | CVAR_ARCHIVE);
- timeout = Cvar_Get ("timeout", "125", 0);
- zombietime = Cvar_Get ("zombietime", "2", 0);
- sv_showclamp = Cvar_Get ("showclamp", "0", 0);
- sv_paused = Cvar_Get ("paused", "0", 0);
- sv_timedemo = Cvar_Get ("timedemo", "0", 0);
- sv_enforcetime = Cvar_Get ("sv_enforcetime", "0", 0);
- allow_download = Cvar_Get ("allow_download", "0", CVAR_ARCHIVE);
- allow_download_players = Cvar_Get ("allow_download_players", "0", CVAR_ARCHIVE);
- allow_download_models = Cvar_Get ("allow_download_models", "1", CVAR_ARCHIVE);
- allow_download_sounds = Cvar_Get ("allow_download_sounds", "1", CVAR_ARCHIVE);
- allow_download_maps = Cvar_Get ("allow_download_maps", "1", CVAR_ARCHIVE);
-
- sv_noreload = Cvar_Get ("sv_noreload", "0", 0);
-
- sv_airaccelerate = Cvar_Get("sv_airaccelerate", "0", CVAR_LATCH);
-
- public_server = Cvar_Get ("public", "0", 0);
-
- sv_reconnect_limit = Cvar_Get ("sv_reconnect_limit", "3", CVAR_ARCHIVE);
-
- SZ_Init (&net_message, net_message_buffer, sizeof(net_message_buffer));
-}
-
-/*
-==================
-SV_FinalMessage
-
-Used by SV_Shutdown to send a final message to all
-connected clients before the server goes down. The messages are sent immediately,
-not just stuck on the outgoing message list, because the server is going
-to totally exit after returning from this function.
-==================
-*/
-void SV_FinalMessage (char *message, qboolean reconnect)
-{
- int i;
- client_t *cl;
-
- SZ_Clear (&net_message);
- MSG_WriteByte (&net_message, svc_print);
- MSG_WriteByte (&net_message, PRINT_HIGH);
- MSG_WriteString (&net_message, message);
-
- if (reconnect)
- MSG_WriteByte (&net_message, svc_reconnect);
- else
- MSG_WriteByte (&net_message, svc_disconnect);
-
- // send it twice
- // stagger the packets to crutch operating system limited buffers
-
- for (i=0, cl = svs.clients ; i<maxclients->value ; i++, cl++)
- if (cl->state >= cs_connected)
- Netchan_Transmit (&cl->netchan, net_message.cursize
- , net_message.data);
-
- for (i=0, cl = svs.clients ; i<maxclients->value ; i++, cl++)
- if (cl->state >= cs_connected)
- Netchan_Transmit (&cl->netchan, net_message.cursize
- , net_message.data);
-}
-
-
-
-/*
-================
-SV_Shutdown
-
-Called when each game quits,
-before Sys_Quit or Sys_Error
-================
-*/
-void SV_Shutdown (char *finalmsg, qboolean reconnect)
-{
- if (svs.clients)
- SV_FinalMessage (finalmsg, reconnect);
-
- Master_Shutdown ();
- SV_ShutdownGameProgs ();
-
- // free current level
- if (sv.demofile)
- fclose (sv.demofile);
- memset (&sv, 0, sizeof(sv));
- Com_SetServerState (sv.state);
-
- // free server static data
- if (svs.clients)
- Z_Free (svs.clients);
- if (svs.client_entities)
- Z_Free (svs.client_entities);
- if (svs.demofile)
- fclose (svs.demofile);
- memset (&svs, 0, sizeof(svs));
-}
-
--- a/server/sv_send.c
+++ /dev/null
@@ -1,547 +1,0 @@
-// sv_main.c -- server main program
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-/*
-=============================================================================
-
-Com_Printf redirection
-
-=============================================================================
-*/
-
-char sv_outputbuf[SV_OUTPUTBUF_LENGTH];
-
-void SV_FlushRedirect (int sv_redirected, char *outputbuf)
-{
- if (sv_redirected == RD_PACKET)
- {
- Netchan_OutOfBandPrint (NS_SERVER, net_from, "print\n%s", outputbuf);
- }
- else if (sv_redirected == RD_CLIENT)
- {
- MSG_WriteByte (&sv_client->netchan.message, svc_print);
- MSG_WriteByte (&sv_client->netchan.message, PRINT_HIGH);
- MSG_WriteString (&sv_client->netchan.message, outputbuf);
- }
-}
-
-
-/*
-=============================================================================
-
-EVENT MESSAGES
-
-=============================================================================
-*/
-
-
-/*
-=================
-SV_ClientPrintf
-
-Sends text across to be displayed if the level passes
-=================
-*/
-void SV_ClientPrintf (client_t *cl, int level, char *fmt, ...)
-{
- va_list argptr;
- char string[1024];
-
- if (level < cl->messagelevel)
- return;
-
- va_start (argptr,fmt);
- vsprintf (string, fmt,argptr);
- va_end (argptr);
-
- MSG_WriteByte (&cl->netchan.message, svc_print);
- MSG_WriteByte (&cl->netchan.message, level);
- MSG_WriteString (&cl->netchan.message, string);
-}
-
-/*
-=================
-SV_BroadcastPrintf
-
-Sends text to all active clients
-=================
-*/
-void SV_BroadcastPrintf (int level, char *fmt, ...)
-{
- va_list argptr;
- char string[2048];
- client_t *cl;
- int i;
-
- va_start (argptr,fmt);
- vsprintf (string, fmt,argptr);
- va_end (argptr);
-
- // echo to console
- if (dedicated->value)
- {
- char copy[1024];
- int i;
-
- // mask off high bits
- for (i=0 ; i<1023 && string[i] ; i++)
- copy[i] = string[i]&127;
- copy[i] = 0;
- Com_Printf ("%s", copy);
- }
-
- for (i=0, cl = svs.clients ; i<maxclients->value; i++, cl++)
- {
- if (level < cl->messagelevel)
- continue;
- if (cl->state != cs_spawned)
- continue;
- MSG_WriteByte (&cl->netchan.message, svc_print);
- MSG_WriteByte (&cl->netchan.message, level);
- MSG_WriteString (&cl->netchan.message, string);
- }
-}
-
-/*
-=================
-SV_BroadcastCommand
-
-Sends text to all active clients
-=================
-*/
-void SV_BroadcastCommand (char *fmt, ...)
-{
- va_list argptr;
- char string[1024];
-
- if (!sv.state)
- return;
- va_start (argptr,fmt);
- vsprintf (string, fmt,argptr);
- va_end (argptr);
-
- MSG_WriteByte (&sv.multicast, svc_stufftext);
- MSG_WriteString (&sv.multicast, string);
- SV_Multicast (NULL, MULTICAST_ALL_R);
-}
-
-
-/*
-=================
-SV_Multicast
-
-Sends the contents of sv.multicast to a subset of the clients,
-then clears sv.multicast.
-
-MULTICAST_ALL same as broadcast (origin can be NULL)
-MULTICAST_PVS send to clients potentially visible from org
-MULTICAST_PHS send to clients potentially hearable from org
-=================
-*/
-void SV_Multicast (vec3_t origin, multicast_t to)
-{
- client_t *client;
- byte *mask;
- int leafnum, cluster;
- int j;
- qboolean reliable;
- int area1, area2;
-
- reliable = false;
-
- if (to != MULTICAST_ALL_R && to != MULTICAST_ALL)
- {
- leafnum = CM_PointLeafnum (origin);
- area1 = CM_LeafArea (leafnum);
- }
- else
- area1 = 0; // just to avoid compiler warnings
-
- // if doing a serverrecord, store everything
- if (svs.demofile)
- SZ_Write (&svs.demo_multicast, sv.multicast.data, sv.multicast.cursize);
-
- switch (to)
- {
- case MULTICAST_ALL_R:
- reliable = true; // intentional fallthrough
- case MULTICAST_ALL:
- mask = NULL;
- break;
-
- case MULTICAST_PHS_R:
- reliable = true; // intentional fallthrough
- case MULTICAST_PHS:
- leafnum = CM_PointLeafnum (origin);
- cluster = CM_LeafCluster (leafnum);
- mask = CM_ClusterPHS (cluster);
- break;
-
- case MULTICAST_PVS_R:
- reliable = true; // intentional fallthrough
- case MULTICAST_PVS:
- leafnum = CM_PointLeafnum (origin);
- cluster = CM_LeafCluster (leafnum);
- mask = CM_ClusterPVS (cluster);
- break;
-
- default:
- mask = NULL;
- Com_Error (ERR_FATAL, "SV_Multicast: bad to:%i", to);
- }
-
- // send the data to all relevent clients
- for (j = 0, client = svs.clients; j < maxclients->value; j++, client++)
- {
- if (client->state == cs_free || client->state == cs_zombie)
- continue;
- if (client->state != cs_spawned && !reliable)
- continue;
-
- if (mask)
- {
- leafnum = CM_PointLeafnum (client->edict->s.origin);
- cluster = CM_LeafCluster (leafnum);
- area2 = CM_LeafArea (leafnum);
- if (!CM_AreasConnected (area1, area2))
- continue;
- if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
- continue;
- }
-
- if (reliable)
- SZ_Write (&client->netchan.message, sv.multicast.data, sv.multicast.cursize);
- else
- SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize);
- }
-
- SZ_Clear (&sv.multicast);
-}
-
-
-/*
-==================
-SV_StartSound
-
-Each entity can have eight independant sound sources, like voice,
-weapon, feet, etc.
-
-If cahnnel & 8, the sound will be sent to everyone, not just
-things in the PHS.
-
-FIXME: if entity isn't in PHS, they must be forced to be sent or
-have the origin explicitly sent.
-
-Channel 0 is an auto-allocate channel, the others override anything
-already running on that entity/channel pair.
-
-An attenuation of 0 will play full volume everywhere in the level.
-Larger attenuations will drop off. (max 4 attenuation)
-
-Timeofs can range from 0.0 to 0.1 to cause sounds to be started
-later in the frame than they normally would.
-
-If origin is NULL, the origin is determined from the entity origin
-or the midpoint of the entity box for bmodels.
-==================
-*/
-void SV_StartSound (vec3_t origin, edict_t *entity, int channel,
- int soundindex, float volume,
- float attenuation, float timeofs)
-{
- int sendchan;
- int flags;
- int i;
- int ent;
- vec3_t origin_v;
- qboolean use_phs;
-
- if (volume < 0 || volume > 1.0)
- Com_Error (ERR_FATAL, "SV_StartSound: volume = %f", volume);
-
- if (attenuation < 0 || attenuation > 4)
- Com_Error (ERR_FATAL, "SV_StartSound: attenuation = %f", attenuation);
-
-// if (channel < 0 || channel > 15)
-// Com_Error (ERR_FATAL, "SV_StartSound: channel = %i", channel);
-
- if (timeofs < 0 || timeofs > 0.255)
- Com_Error (ERR_FATAL, "SV_StartSound: timeofs = %f", timeofs);
-
- ent = NUM_FOR_EDICT(entity);
-
- if (channel & 8) // no PHS flag
- {
- use_phs = false;
- channel &= 7;
- }
- else
- use_phs = true;
-
- sendchan = (ent<<3) | (channel&7);
-
- flags = 0;
- if (volume != DEFAULT_SOUND_PACKET_VOLUME)
- flags |= SND_VOLUME;
- if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
- flags |= SND_ATTENUATION;
-
- // the client doesn't know that bmodels have weird origins
- // the origin can also be explicitly set
- if ( (entity->svflags & SVF_NOCLIENT)
- || (entity->solid == SOLID_BSP)
- || origin )
- flags |= SND_POS;
-
- // always send the entity number for channel overrides
- flags |= SND_ENT;
-
- if (timeofs)
- flags |= SND_OFFSET;
-
- // use the entity origin unless it is a bmodel or explicitly specified
- if (!origin)
- {
- origin = origin_v;
- if (entity->solid == SOLID_BSP)
- {
- for (i=0 ; i<3 ; i++)
- origin_v[i] = entity->s.origin[i]+0.5*(entity->mins[i]+entity->maxs[i]);
- }
- else
- {
- VectorCopy (entity->s.origin, origin_v);
- }
- }
-
- MSG_WriteByte (&sv.multicast, svc_sound);
- MSG_WriteByte (&sv.multicast, flags);
- MSG_WriteByte (&sv.multicast, soundindex);
-
- if (flags & SND_VOLUME)
- MSG_WriteByte (&sv.multicast, volume*255);
- if (flags & SND_ATTENUATION)
- MSG_WriteByte (&sv.multicast, attenuation*64);
- if (flags & SND_OFFSET)
- MSG_WriteByte (&sv.multicast, timeofs*1000);
-
- if (flags & SND_ENT)
- MSG_WriteShort (&sv.multicast, sendchan);
-
- if (flags & SND_POS)
- MSG_WritePos (&sv.multicast, origin);
-
- // if the sound doesn't attenuate,send it to everyone
- // (global radio chatter, voiceovers, etc)
- if (attenuation == ATTN_NONE)
- use_phs = false;
-
- if (channel & CHAN_RELIABLE)
- {
- if (use_phs)
- SV_Multicast (origin, MULTICAST_PHS_R);
- else
- SV_Multicast (origin, MULTICAST_ALL_R);
- }
- else
- {
- if (use_phs)
- SV_Multicast (origin, MULTICAST_PHS);
- else
- SV_Multicast (origin, MULTICAST_ALL);
- }
-}
-
-
-/*
-===============================================================================
-
-FRAME UPDATES
-
-===============================================================================
-*/
-
-
-
-/*
-=======================
-SV_SendClientDatagram
-=======================
-*/
-qboolean SV_SendClientDatagram (client_t *client)
-{
- byte msg_buf[MAX_MSGLEN];
- sizebuf_t msg;
-
- SV_BuildClientFrame (client);
-
- SZ_Init (&msg, msg_buf, sizeof(msg_buf));
- msg.allowoverflow = true;
-
- // send over all the relevant entity_state_t
- // and the player_state_t
- SV_WriteFrameToClient (client, &msg);
-
- // copy the accumulated multicast datagram
- // for this client out to the message
- // it is necessary for this to be after the WriteEntities
- // so that entity references will be current
- if (client->datagram.overflowed)
- Com_Printf ("WARNING: datagram overflowed for %s\n", client->name);
- else
- SZ_Write (&msg, client->datagram.data, client->datagram.cursize);
- SZ_Clear (&client->datagram);
-
- if (msg.overflowed)
- { // must have room left for the packet header
- Com_Printf ("WARNING: msg overflowed for %s\n", client->name);
- SZ_Clear (&msg);
- }
-
- // send the datagram
- Netchan_Transmit (&client->netchan, msg.cursize, msg.data);
-
- // record the size for rate estimation
- client->message_size[sv.framenum % RATE_MESSAGES] = msg.cursize;
-
- return true;
-}
-
-
-/*
-==================
-SV_DemoCompleted
-==================
-*/
-void SV_DemoCompleted (void)
-{
- if (sv.demofile)
- {
- fclose (sv.demofile);
- sv.demofile = NULL;
- }
- SV_Nextserver ();
-}
-
-
-/*
-=======================
-SV_RateDrop
-
-Returns true if the client is over its current
-bandwidth estimation and should not be sent another packet
-=======================
-*/
-qboolean SV_RateDrop (client_t *c)
-{
- int total;
- int i;
-
- // never drop over the loopback
- if (c->netchan.remote_address.type == NA_LOOPBACK)
- return false;
-
- total = 0;
-
- for (i = 0 ; i < RATE_MESSAGES ; i++)
- {
- total += c->message_size[i];
- }
-
- if (total > c->rate)
- {
- c->surpressCount++;
- c->message_size[sv.framenum % RATE_MESSAGES] = 0;
- return true;
- }
-
- return false;
-}
-
-/*
-=======================
-SV_SendClientMessages
-=======================
-*/
-void SV_SendClientMessages (void)
-{
- int i;
- client_t *c;
- int msglen;
- byte msgbuf[MAX_MSGLEN];
- int r;
-
- msglen = 0;
-
- // read the next demo message if needed
- if (sv.state == ss_demo && sv.demofile)
- {
- if (sv_paused->value)
- msglen = 0;
- else
- {
- // get the next message
- r = fread (&msglen, 4, 1, sv.demofile);
- if (r != 1)
- {
- SV_DemoCompleted ();
- return;
- }
- msglen = LittleLong (msglen);
- if (msglen == -1)
- {
- SV_DemoCompleted ();
- return;
- }
- if (msglen > MAX_MSGLEN)
- Com_Error (ERR_DROP, "SV_SendClientMessages: msglen > MAX_MSGLEN");
- r = fread (msgbuf, msglen, 1, sv.demofile);
- if (r != 1)
- {
- SV_DemoCompleted ();
- return;
- }
- }
- }
-
- // send a message to each connected client
- for (i=0, c = svs.clients ; i<maxclients->value; i++, c++)
- {
- if (!c->state)
- continue;
- // if the reliable message overflowed,
- // drop the client
- if (c->netchan.message.overflowed)
- {
- SZ_Clear (&c->netchan.message);
- SZ_Clear (&c->datagram);
- SV_BroadcastPrintf (PRINT_HIGH, "%s overflowed\n", c->name);
- SV_DropClient (c);
- }
-
- if (sv.state == ss_cinematic
- || sv.state == ss_demo
- || sv.state == ss_pic
- )
- Netchan_Transmit (&c->netchan, msglen, msgbuf);
- else if (c->state == cs_spawned)
- {
- // don't overrun bandwidth
- if (SV_RateDrop (c))
- continue;
-
- SV_SendClientDatagram (c);
- }
- else
- {
- // just update reliable if needed
- if (c->netchan.message.cursize || curtime - c->netchan.last_sent > 1000 )
- Netchan_Transmit (&c->netchan, 0, NULL);
- }
- }
-}
-
--- a/server/sv_user.c
+++ /dev/null
@@ -1,648 +1,0 @@
-// sv_user.c -- server code for moving users
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-edict_t *sv_player;
-
-/*
-============================================================
-
-USER STRINGCMD EXECUTION
-
-sv_client and sv_player will be valid.
-============================================================
-*/
-
-/*
-==================
-SV_BeginDemoServer
-==================
-*/
-void SV_BeginDemoserver (void)
-{
- char name[MAX_OSPATH];
-
- Com_sprintf (name, sizeof(name), "demos/%s", sv.name);
- FS_FOpenFile (name, &sv.demofile);
- if (!sv.demofile)
- Com_Error (ERR_DROP, "Couldn't open %s\n", name);
-}
-
-/*
-================
-SV_New_f
-
-Sends the first message from the server to a connected client.
-This will be sent on the initial connection and upon each server load.
-================
-*/
-void SV_New_f (void)
-{
- char *gamedir;
- int playernum;
- edict_t *ent;
-
- Com_DPrintf ("New() from %s\n", sv_client->name);
-
- if (sv_client->state != cs_connected)
- {
- Com_Printf ("New not valid -- already spawned\n");
- return;
- }
-
- // demo servers just dump the file message
- if (sv.state == ss_demo)
- {
- SV_BeginDemoserver ();
- return;
- }
-
- //
- // serverdata needs to go over for all types of servers
- // to make sure the protocol is right, and to set the gamedir
- //
- gamedir = Cvar_VariableString ("gamedir");
-
- // send the serverdata
- MSG_WriteByte (&sv_client->netchan.message, svc_serverdata);
- MSG_WriteLong (&sv_client->netchan.message, PROTOCOL_VERSION);
- MSG_WriteLong (&sv_client->netchan.message, svs.spawncount);
- MSG_WriteByte (&sv_client->netchan.message, sv.attractloop);
- MSG_WriteString (&sv_client->netchan.message, gamedir);
-
- if (sv.state == ss_cinematic || sv.state == ss_pic)
- playernum = -1;
- else
- playernum = sv_client - svs.clients;
- MSG_WriteShort (&sv_client->netchan.message, playernum);
-
- // send full levelname
- MSG_WriteString (&sv_client->netchan.message, sv.configstrings[CS_NAME]);
-
- //
- // game server
- //
- if (sv.state == ss_game)
- {
- // set up the entity for the client
- ent = EDICT_NUM(playernum+1);
- ent->s.number = playernum+1;
- sv_client->edict = ent;
- memset (&sv_client->lastcmd, 0, sizeof(sv_client->lastcmd));
-
- // begin fetching configstrings
- MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
- MSG_WriteString (&sv_client->netchan.message, va("cmd configstrings %i 0\n",svs.spawncount) );
- }
-
-}
-
-/*
-==================
-SV_Configstrings_f
-==================
-*/
-void SV_Configstrings_f (void)
-{
- int start;
-
- Com_DPrintf ("Configstrings() from %s\n", sv_client->name);
-
- if (sv_client->state != cs_connected)
- {
- Com_Printf ("configstrings not valid -- already spawned\n");
- return;
- }
-
- // handle the case of a level changing while a client was connecting
- if ( atoi(Cmd_Argv(1)) != svs.spawncount )
- {
- Com_Printf ("SV_Configstrings_f from different level\n");
- SV_New_f ();
- return;
- }
-
- start = atoi(Cmd_Argv(2));
-
- // write a packet full of data
-
- while ( sv_client->netchan.message.cursize < MAX_MSGLEN/2
- && start < MAX_CONFIGSTRINGS)
- {
- if (sv.configstrings[start][0])
- {
- MSG_WriteByte (&sv_client->netchan.message, svc_configstring);
- MSG_WriteShort (&sv_client->netchan.message, start);
- MSG_WriteString (&sv_client->netchan.message, sv.configstrings[start]);
- }
- start++;
- }
-
- // send next command
-
- if (start == MAX_CONFIGSTRINGS)
- {
- MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
- MSG_WriteString (&sv_client->netchan.message, va("cmd baselines %i 0\n",svs.spawncount) );
- }
- else
- {
- MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
- MSG_WriteString (&sv_client->netchan.message, va("cmd configstrings %i %i\n",svs.spawncount, start) );
- }
-}
-
-/*
-==================
-SV_Baselines_f
-==================
-*/
-void SV_Baselines_f (void)
-{
- int start;
- entity_state_t nullstate;
- entity_state_t *base;
-
- Com_DPrintf ("Baselines() from %s\n", sv_client->name);
-
- if (sv_client->state != cs_connected)
- {
- Com_Printf ("baselines not valid -- already spawned\n");
- return;
- }
-
- // handle the case of a level changing while a client was connecting
- if ( atoi(Cmd_Argv(1)) != svs.spawncount )
- {
- Com_Printf ("SV_Baselines_f from different level\n");
- SV_New_f ();
- return;
- }
-
- start = atoi(Cmd_Argv(2));
-
- memset (&nullstate, 0, sizeof(nullstate));
-
- // write a packet full of data
-
- while ( sv_client->netchan.message.cursize < MAX_MSGLEN/2
- && start < MAX_EDICTS)
- {
- base = &sv.baselines[start];
- if (base->modelindex || base->sound || base->effects)
- {
- MSG_WriteByte (&sv_client->netchan.message, svc_spawnbaseline);
- MSG_WriteDeltaEntity (&nullstate, base, &sv_client->netchan.message, true, true);
- }
- start++;
- }
-
- // send next command
-
- if (start == MAX_EDICTS)
- {
- MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
- MSG_WriteString (&sv_client->netchan.message, va("precache %i\n", svs.spawncount) );
- }
- else
- {
- MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
- MSG_WriteString (&sv_client->netchan.message, va("cmd baselines %i %i\n",svs.spawncount, start) );
- }
-}
-
-/*
-==================
-SV_Begin_f
-==================
-*/
-void SV_Begin_f (void)
-{
- Com_DPrintf ("Begin() from %s\n", sv_client->name);
-
- // handle the case of a level changing while a client was connecting
- if ( atoi(Cmd_Argv(1)) != svs.spawncount )
- {
- Com_Printf ("SV_Begin_f from different level\n");
- SV_New_f ();
- return;
- }
-
- sv_client->state = cs_spawned;
-
- // call the game begin function
- ge->ClientBegin (sv_player);
-
- Cbuf_InsertFromDefer ();
-}
-
-//=============================================================================
-
-/*
-==================
-SV_NextDownload_f
-==================
-*/
-void SV_NextDownload_f (void)
-{
- int r;
- int percent;
- int size;
-
- if (!sv_client->download)
- return;
-
- r = sv_client->downloadsize - sv_client->downloadcount;
- if (r > 1024)
- r = 1024;
-
- MSG_WriteByte (&sv_client->netchan.message, svc_download);
- MSG_WriteShort (&sv_client->netchan.message, r);
-
- sv_client->downloadcount += r;
- size = sv_client->downloadsize;
- if (!size)
- size = 1;
- percent = sv_client->downloadcount*100/size;
- MSG_WriteByte (&sv_client->netchan.message, percent);
- SZ_Write (&sv_client->netchan.message,
- sv_client->download + sv_client->downloadcount - r, r);
-
- if (sv_client->downloadcount != sv_client->downloadsize)
- return;
-
- FS_FreeFile (sv_client->download);
- sv_client->download = NULL;
-}
-
-/*
-==================
-SV_BeginDownload_f
-==================
-*/
-void SV_BeginDownload_f(void)
-{
- char *name;
- extern cvar_t *allow_download;
- extern cvar_t *allow_download_players;
- extern cvar_t *allow_download_models;
- extern cvar_t *allow_download_sounds;
- extern cvar_t *allow_download_maps;
- extern int file_from_pak; // ZOID did file come from pak?
- int offset = 0;
-
- name = Cmd_Argv(1);
-
- if (Cmd_Argc() > 2)
- offset = atoi(Cmd_Argv(2)); // downloaded offset
-
- // hacked by zoid to allow more conrol over download
- // first off, no .. or global allow check
- if (strstr (name, "..") || !allow_download->value
- // leading dot is no good
- || *name == '.'
- // leading slash bad as well, must be in subdir
- || *name == '/'
- // next up, skin check
- || (strncmp(name, "players/", 6) == 0 && !allow_download_players->value)
- // now models
- || (strncmp(name, "models/", 6) == 0 && !allow_download_models->value)
- // now sounds
- || (strncmp(name, "sound/", 6) == 0 && !allow_download_sounds->value)
- // now maps (note special case for maps, must not be in pak)
- || (strncmp(name, "maps/", 6) == 0 && !allow_download_maps->value)
- // MUST be in a subdirectory
- || !strstr (name, "/") )
- { // don't allow anything with .. path
- MSG_WriteByte (&sv_client->netchan.message, svc_download);
- MSG_WriteShort (&sv_client->netchan.message, -1);
- MSG_WriteByte (&sv_client->netchan.message, 0);
- return;
- }
-
-
- if (sv_client->download)
- FS_FreeFile (sv_client->download);
-
- sv_client->downloadsize = FS_LoadFile (name, (void **)&sv_client->download);
- sv_client->downloadcount = offset;
-
- if (offset > sv_client->downloadsize)
- sv_client->downloadcount = sv_client->downloadsize;
-
- if (!sv_client->download
- // special check for maps, if it came from a pak file, don't allow
- // download ZOID
- || (strncmp(name, "maps/", 5) == 0 && file_from_pak))
- {
- Com_DPrintf ("Couldn't download %s to %s\n", name, sv_client->name);
- if (sv_client->download) {
- FS_FreeFile (sv_client->download);
- sv_client->download = NULL;
- }
-
- MSG_WriteByte (&sv_client->netchan.message, svc_download);
- MSG_WriteShort (&sv_client->netchan.message, -1);
- MSG_WriteByte (&sv_client->netchan.message, 0);
- return;
- }
-
- SV_NextDownload_f ();
- Com_DPrintf ("Downloading %s to %s\n", name, sv_client->name);
-}
-
-
-
-//============================================================================
-
-
-/*
-=================
-SV_Disconnect_f
-
-The client is going to disconnect, so remove the connection immediately
-=================
-*/
-void SV_Disconnect_f (void)
-{
-// SV_EndRedirect ();
- SV_DropClient (sv_client);
-}
-
-
-/*
-==================
-SV_ShowServerinfo_f
-
-Dumps the serverinfo info string
-==================
-*/
-void SV_ShowServerinfo_f (void)
-{
- Info_Print (Cvar_Serverinfo());
-}
-
-
-void SV_Nextserver (void)
-{
- char *v;
-
- //ZOID, ss_pic can be nextserver'd in coop mode
- if (sv.state == ss_game || (sv.state == ss_pic && !Cvar_VariableValue("coop")))
- return; // can't nextserver while playing a normal game
-
- svs.spawncount++; // make sure another doesn't sneak in
- v = Cvar_VariableString ("nextserver");
- if (!v[0])
- Cbuf_AddText ("killserver\n");
- else
- {
- Cbuf_AddText (v);
- Cbuf_AddText ("\n");
- }
- Cvar_Set ("nextserver","");
-}
-
-/*
-==================
-SV_Nextserver_f
-
-A cinematic has completed or been aborted by a client, so move
-to the next server,
-==================
-*/
-void SV_Nextserver_f (void)
-{
- if ( atoi(Cmd_Argv(1)) != svs.spawncount ) {
- Com_DPrintf ("Nextserver() from wrong level, from %s\n", sv_client->name);
- return; // leftover from last server
- }
-
- Com_DPrintf ("Nextserver() from %s\n", sv_client->name);
-
- SV_Nextserver ();
-}
-
-typedef struct
-{
- char *name;
- void (*func) (void);
-} ucmd_t;
-
-ucmd_t ucmds[] =
-{
- // auto issued
- {"new", SV_New_f},
- {"configstrings", SV_Configstrings_f},
- {"baselines", SV_Baselines_f},
- {"begin", SV_Begin_f},
-
- {"nextserver", SV_Nextserver_f},
-
- {"disconnect", SV_Disconnect_f},
-
- // issued by hand at client consoles
- {"info", SV_ShowServerinfo_f},
-
- {"download", SV_BeginDownload_f},
- {"nextdl", SV_NextDownload_f},
-
- {NULL, NULL}
-};
-
-/*
-==================
-SV_ExecuteUserCommand
-==================
-*/
-void SV_ExecuteUserCommand (char *s)
-{
- ucmd_t *u;
-
- Cmd_TokenizeString (s, true);
- sv_player = sv_client->edict;
-
-// SV_BeginRedirect (RD_CLIENT);
-
- for (u=ucmds ; u->name ; u++)
- if (!strcmp (Cmd_Argv(0), u->name) )
- {
- u->func ();
- break;
- }
-
- if (!u->name && sv.state == ss_game)
- ge->ClientCommand (sv_player);
-
-// SV_EndRedirect ();
-}
-
-/*
-===========================================================================
-
-USER CMD EXECUTION
-
-===========================================================================
-*/
-
-
-
-void SV_ClientThink (client_t *cl, usercmd_t *cmd)
-
-{
- cl->commandMsec -= cmd->msec;
-
- if (cl->commandMsec < 0 && sv_enforcetime->value )
- {
- Com_DPrintf ("commandMsec underflow from %s\n", cl->name);
- return;
- }
-
- ge->ClientThink (cl->edict, cmd);
-}
-
-
-
-#define MAX_STRINGCMDS 8
-/*
-===================
-SV_ExecuteClientMessage
-
-The current net_message is parsed for the given client
-===================
-*/
-void SV_ExecuteClientMessage (client_t *cl)
-{
- int c;
- char *s;
-
- usercmd_t nullcmd;
- usercmd_t oldest, oldcmd, newcmd;
- int net_drop;
- int stringCmdCount;
- int checksum, calculatedChecksum;
- int checksumIndex;
- qboolean move_issued;
- int lastframe;
-
- sv_client = cl;
- sv_player = sv_client->edict;
-
- // only allow one move command
- move_issued = false;
- stringCmdCount = 0;
-
- while (1)
- {
- if (net_message.readcount > net_message.cursize)
- {
- Com_Printf ("SV_ReadClientMessage: badread\n");
- SV_DropClient (cl);
- return;
- }
-
- c = MSG_ReadByte (&net_message);
- if (c == -1)
- break;
-
- switch (c)
- {
- default:
- Com_Printf ("SV_ReadClientMessage: unknown command char\n");
- SV_DropClient (cl);
- return;
-
- case clc_nop:
- break;
-
- case clc_userinfo:
- strncpy (cl->userinfo, MSG_ReadString (&net_message), sizeof(cl->userinfo)-1);
- SV_UserinfoChanged (cl);
- break;
-
- case clc_move:
- if (move_issued)
- return; // someone is trying to cheat...
-
- move_issued = true;
- checksumIndex = net_message.readcount;
- checksum = MSG_ReadByte (&net_message);
- lastframe = MSG_ReadLong (&net_message);
- if (lastframe != cl->lastframe) {
- cl->lastframe = lastframe;
- if (cl->lastframe > 0) {
- cl->frame_latency[cl->lastframe&(LATENCY_COUNTS-1)] =
- svs.realtime - cl->frames[cl->lastframe & UPDATE_MASK].senttime;
- }
- }
-
- memset (&nullcmd, 0, sizeof(nullcmd));
- MSG_ReadDeltaUsercmd (&net_message, &nullcmd, &oldest);
- MSG_ReadDeltaUsercmd (&net_message, &oldest, &oldcmd);
- MSG_ReadDeltaUsercmd (&net_message, &oldcmd, &newcmd);
-
- if ( cl->state != cs_spawned )
- {
- cl->lastframe = -1;
- break;
- }
-
- // if the checksum fails, ignore the rest of the packet
- calculatedChecksum = COM_BlockSequenceCRCByte (
- net_message.data + checksumIndex + 1,
- net_message.readcount - checksumIndex - 1,
- cl->netchan.incoming_sequence);
-
- if (calculatedChecksum != checksum)
- {
- Com_DPrintf ("Failed command checksum for %s (%d != %d)/%d\n",
- cl->name, calculatedChecksum, checksum,
- cl->netchan.incoming_sequence);
- return;
- }
-
- if (!sv_paused->value)
- {
- net_drop = cl->netchan.dropped;
- if (net_drop < 20)
- {
-
-//if (net_drop > 2)
-
-// Com_Printf ("drop %i\n", net_drop);
- while (net_drop > 2)
- {
- SV_ClientThink (cl, &cl->lastcmd);
-
- net_drop--;
- }
- if (net_drop > 1)
- SV_ClientThink (cl, &oldest);
-
- if (net_drop > 0)
- SV_ClientThink (cl, &oldcmd);
-
- }
- SV_ClientThink (cl, &newcmd);
- }
-
- cl->lastcmd = newcmd;
- break;
-
- case clc_stringcmd:
- s = MSG_ReadString (&net_message);
-
- // malicious users may try using too many string commands
- if (++stringCmdCount < MAX_STRINGCMDS)
- SV_ExecuteUserCommand (s);
-
- if (cl->state == cs_zombie)
- return; // disconnect command
- break;
- }
- }
-}
-
--- a/server/sv_world.c
+++ /dev/null
@@ -1,642 +1,0 @@
-// world.c -- world query functions
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "../q_shared.h"
-
-/*
-===============================================================================
-
-ENTITY AREA CHECKING
-
-FIXME: this use of "area" is different from the bsp file use
-===============================================================================
-*/
-
-// (type *)STRUCT_FROM_LINK(link_t *link, type, member)
-// ent = STRUCT_FROM_LINK(link,entity_t,order)
-// FIXME: remove this mess!
-#define STRUCT_FROM_LINK(l,t,m) ((t *)((byte *)l - (uintptr)&(((t *)0)->m)))
-
-#define EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area)
-
-typedef struct areanode_s
-{
- int axis; // -1 = leaf node
- float dist;
- struct areanode_s *children[2];
- link_t trigger_edicts;
- link_t solid_edicts;
-} areanode_t;
-
-#define AREA_DEPTH 4
-#define AREA_NODES 32
-
-areanode_t sv_areanodes[AREA_NODES];
-int sv_numareanodes;
-
-float *area_mins, *area_maxs;
-edict_t **area_list;
-int area_count, area_maxcount;
-int area_type;
-
-int SV_HullForEntity (edict_t *ent);
-
-
-// ClearLink is used for new headnodes
-void ClearLink (link_t *l)
-{
- l->prev = l->next = l;
-}
-
-void RemoveLink (link_t *l)
-{
- l->next->prev = l->prev;
- l->prev->next = l->next;
-}
-
-void InsertLinkBefore (link_t *l, link_t *before)
-{
- l->next = before;
- l->prev = before->prev;
- l->prev->next = l;
- l->next->prev = l;
-}
-
-/*
-===============
-SV_CreateAreaNode
-
-Builds a uniformly subdivided tree for the given world size
-===============
-*/
-areanode_t *SV_CreateAreaNode (int depth, vec3_t mins, vec3_t maxs)
-{
- areanode_t *anode;
- vec3_t size;
- vec3_t mins1, maxs1, mins2, maxs2;
-
- anode = &sv_areanodes[sv_numareanodes];
- sv_numareanodes++;
-
- ClearLink (&anode->trigger_edicts);
- ClearLink (&anode->solid_edicts);
-
- if (depth == AREA_DEPTH)
- {
- anode->axis = -1;
- anode->children[0] = anode->children[1] = NULL;
- return anode;
- }
-
- VectorSubtract (maxs, mins, size);
- if (size[0] > size[1])
- anode->axis = 0;
- else
- anode->axis = 1;
-
- anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);
- VectorCopy (mins, mins1);
- VectorCopy (mins, mins2);
- VectorCopy (maxs, maxs1);
- VectorCopy (maxs, maxs2);
-
- maxs1[anode->axis] = mins2[anode->axis] = anode->dist;
-
- anode->children[0] = SV_CreateAreaNode (depth+1, mins2, maxs2);
- anode->children[1] = SV_CreateAreaNode (depth+1, mins1, maxs1);
-
- return anode;
-}
-
-/*
-===============
-SV_ClearWorld
-
-===============
-*/
-void SV_ClearWorld (void)
-{
- memset (sv_areanodes, 0, sizeof(sv_areanodes));
- sv_numareanodes = 0;
- SV_CreateAreaNode (0, sv.models[1]->mins, sv.models[1]->maxs);
-}
-
-
-/*
-===============
-SV_UnlinkEdict
-
-===============
-*/
-void SV_UnlinkEdict (edict_t *ent)
-{
- if (!ent->area.prev)
- return; // not linked in anywhere
- RemoveLink (&ent->area);
- ent->area.prev = ent->area.next = NULL;
-}
-
-
-/*
-===============
-SV_LinkEdict
-
-===============
-*/
-#define MAX_TOTAL_ENT_LEAFS 128
-void SV_LinkEdict (edict_t *ent)
-{
- areanode_t *node;
- int leafs[MAX_TOTAL_ENT_LEAFS];
- int clusters[MAX_TOTAL_ENT_LEAFS];
- int num_leafs;
- int i, j, k;
- int area;
- int topnode;
-
- if (ent->area.prev)
- SV_UnlinkEdict (ent); // unlink from old position
-
- if (ent == ge->edicts)
- return; // don't add the world
-
- if (!ent->inuse)
- return;
-
- // set the size
- VectorSubtract (ent->maxs, ent->mins, ent->size);
-
- // encode the size into the entity_state for client prediction
- if (ent->solid == SOLID_BBOX && !(ent->svflags & SVF_DEADMONSTER))
- { // assume that x/y are equal and symetric
- i = ent->maxs[0]/8;
- if (i<1)
- i = 1;
- if (i>31)
- i = 31;
-
- // z is not symetric
- j = (-ent->mins[2])/8;
- if (j<1)
- j = 1;
- if (j>31)
- j = 31;
-
- // and z maxs can be negative...
- k = (ent->maxs[2]+32)/8;
- if (k<1)
- k = 1;
- if (k>63)
- k = 63;
-
- ent->s.solid = (k<<10) | (j<<5) | i;
- }
- else if (ent->solid == SOLID_BSP)
- {
- ent->s.solid = 31; // a solid_bbox will never create this value
- }
- else
- ent->s.solid = 0;
-
- // set the abs box
- if (ent->solid == SOLID_BSP &&
- (ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2]) )
- { // expand for rotation
- float max, v;
- int i;
-
- max = 0;
- for (i=0 ; i<3 ; i++)
- {
- v =fabs( ent->mins[i]);
- if (v > max)
- max = v;
- v =fabs( ent->maxs[i]);
- if (v > max)
- max = v;
- }
- for (i=0 ; i<3 ; i++)
- {
- ent->absmin[i] = ent->s.origin[i] - max;
- ent->absmax[i] = ent->s.origin[i] + max;
- }
- }
- else
- { // normal
- VectorAdd (ent->s.origin, ent->mins, ent->absmin);
- VectorAdd (ent->s.origin, ent->maxs, ent->absmax);
- }
-
- // because movement is clipped an epsilon away from an actual edge,
- // we must fully check even when bounding boxes don't quite touch
- ent->absmin[0] -= 1;
- ent->absmin[1] -= 1;
- ent->absmin[2] -= 1;
- ent->absmax[0] += 1;
- ent->absmax[1] += 1;
- ent->absmax[2] += 1;
-
-// link to PVS leafs
- ent->num_clusters = 0;
- ent->areanum = 0;
- ent->areanum2 = 0;
-
- //get all leafs, including solids
- num_leafs = CM_BoxLeafnums (ent->absmin, ent->absmax,
- leafs, MAX_TOTAL_ENT_LEAFS, &topnode);
-
- // set areas
- for (i=0 ; i<num_leafs ; i++)
- {
- clusters[i] = CM_LeafCluster (leafs[i]);
- area = CM_LeafArea (leafs[i]);
- if (area)
- { // doors may legally straggle two areas,
- // but nothing should evern need more than that
- if (ent->areanum && ent->areanum != area)
- {
- if (ent->areanum2 && ent->areanum2 != area && sv.state == ss_loading)
- Com_DPrintf ("Object touching 3 areas at %f %f %f\n",
- ent->absmin[0], ent->absmin[1], ent->absmin[2]);
- ent->areanum2 = area;
- }
- else
- ent->areanum = area;
- }
- }
-
- if (num_leafs >= MAX_TOTAL_ENT_LEAFS)
- { // assume we missed some leafs, and mark by headnode
- ent->num_clusters = -1;
- ent->headnode = topnode;
- }
- else
- {
- ent->num_clusters = 0;
- for (i=0 ; i<num_leafs ; i++)
- {
- if (clusters[i] == -1)
- continue; // not a visible leaf
- for (j=0 ; j<i ; j++)
- if (clusters[j] == clusters[i])
- break;
- if (j == i)
- {
- if (ent->num_clusters == MAX_ENT_CLUSTERS)
- { // assume we missed some leafs, and mark by headnode
- ent->num_clusters = -1;
- ent->headnode = topnode;
- break;
- }
-
- ent->clusternums[ent->num_clusters++] = clusters[i];
- }
- }
- }
-
- // if first time, make sure old_origin is valid
- if (!ent->linkcount)
- {
- VectorCopy (ent->s.origin, ent->s.old_origin);
- }
- ent->linkcount++;
-
- if (ent->solid == SOLID_NOT)
- return;
-
-// find the first node that the ent's box crosses
- node = sv_areanodes;
- while (1)
- {
- if (node->axis == -1)
- break;
- if (ent->absmin[node->axis] > node->dist)
- node = node->children[0];
- else if (ent->absmax[node->axis] < node->dist)
- node = node->children[1];
- else
- break; // crosses the node
- }
-
- // link it in
- if (ent->solid == SOLID_TRIGGER)
- InsertLinkBefore (&ent->area, &node->trigger_edicts);
- else
- InsertLinkBefore (&ent->area, &node->solid_edicts);
-
-}
-
-
-/*
-====================
-SV_AreaEdicts_r
-
-====================
-*/
-void SV_AreaEdicts_r (areanode_t *node)
-{
- link_t *l, *next, *start;
- edict_t *check;
-
- // touch linked edicts
- if (area_type == AREA_SOLID)
- start = &node->solid_edicts;
- else
- start = &node->trigger_edicts;
-
- for (l=start->next ; l != start ; l = next)
- {
- next = l->next;
- check = EDICT_FROM_AREA(l);
-
- if (check->solid == SOLID_NOT)
- continue; // deactivated
- if (check->absmin[0] > area_maxs[0]
- || check->absmin[1] > area_maxs[1]
- || check->absmin[2] > area_maxs[2]
- || check->absmax[0] < area_mins[0]
- || check->absmax[1] < area_mins[1]
- || check->absmax[2] < area_mins[2])
- continue; // not touching
-
- if (area_count == area_maxcount)
- {
- Com_Printf ("SV_AreaEdicts: MAXCOUNT\n");
- return;
- }
-
- area_list[area_count] = check;
- area_count++;
- }
-
- if (node->axis == -1)
- return; // terminal node
-
- // recurse down both sides
- if ( area_maxs[node->axis] > node->dist )
- SV_AreaEdicts_r ( node->children[0] );
- if ( area_mins[node->axis] < node->dist )
- SV_AreaEdicts_r ( node->children[1] );
-}
-
-/*
-================
-SV_AreaEdicts
-================
-*/
-int SV_AreaEdicts (vec3_t mins, vec3_t maxs, edict_t **list,
- int maxcount, int areatype)
-{
- area_mins = mins;
- area_maxs = maxs;
- area_list = list;
- area_count = 0;
- area_maxcount = maxcount;
- area_type = areatype;
-
- SV_AreaEdicts_r (sv_areanodes);
-
- return area_count;
-}
-
-
-//===========================================================================
-
-/*
-=============
-SV_PointContents
-=============
-*/
-int SV_PointContents (vec3_t p)
-{
- edict_t *touch[MAX_EDICTS], *hit;
- int i, num;
- int contents, c2;
- int headnode;
-
- // get base contents from world
- contents = CM_PointContents (p, sv.models[1]->headnode);
-
- // or in contents from all the other entities
- num = SV_AreaEdicts (p, p, touch, MAX_EDICTS, AREA_SOLID);
-
- for (i=0 ; i<num ; i++)
- {
- hit = touch[i];
-
- // might intersect, so do an exact clip
- headnode = SV_HullForEntity (hit);
-
- /* unused
- float *angles;
- angles = hit->s.angles;
- if (hit->solid != SOLID_BSP)
- angles = vec3_origin; // boxes don't rotate
- */
-
- c2 = CM_TransformedPointContents (p, headnode, hit->s.origin, hit->s.angles);
-
- contents |= c2;
- }
-
- return contents;
-}
-
-
-
-typedef struct
-{
- vec3_t boxmins, boxmaxs;// enclose the test object along entire move
- float *mins, *maxs; // size of the moving object
- vec3_t mins2, maxs2; // size when clipping against mosnters
- float *start, *end;
- trace_t trace;
- edict_t *passedict;
- int contentmask;
-} moveclip_t;
-
-
-
-/*
-================
-SV_HullForEntity
-
-Returns a headnode that can be used for testing or clipping an
-object of mins/maxs size.
-Offset is filled in to contain the adjustment that must be added to the
-testing object's origin to get a point to use with the returned hull.
-================
-*/
-int SV_HullForEntity (edict_t *ent)
-{
- cmodel_t *model;
-
-// decide which clipping hull to use, based on the size
- if (ent->solid == SOLID_BSP)
- { // explicit hulls in the BSP model
- model = sv.models[ ent->s.modelindex ];
-
- if (!model)
- Com_Error (ERR_FATAL, "MOVETYPE_PUSH with a non bsp model");
-
- return model->headnode;
- }
-
- // create a temp hull from bounding box sizes
-
- return CM_HeadnodeForBox (ent->mins, ent->maxs);
-}
-
-
-//===========================================================================
-
-/*
-====================
-SV_ClipMoveToEntities
-
-====================
-*/
-void SV_ClipMoveToEntities ( moveclip_t *clip )
-{
- int i, num;
- edict_t *touchlist[MAX_EDICTS], *touch;
- trace_t trace;
- int headnode;
- float *angles;
-
- num = SV_AreaEdicts (clip->boxmins, clip->boxmaxs, touchlist
- , MAX_EDICTS, AREA_SOLID);
-
- // be careful, it is possible to have an entity in this
- // list removed before we get to it (killtriggered)
- for (i=0 ; i<num ; i++)
- {
- touch = touchlist[i];
- if (touch->solid == SOLID_NOT)
- continue;
- if (touch == clip->passedict)
- continue;
- if (clip->trace.allsolid)
- return;
- if (clip->passedict)
- {
- if (touch->owner == clip->passedict)
- continue; // don't clip against own missiles
- if (clip->passedict->owner == touch)
- continue; // don't clip against owner
- }
-
- if ( !(clip->contentmask & CONTENTS_DEADMONSTER)
- && (touch->svflags & SVF_DEADMONSTER) )
- continue;
-
- // might intersect, so do an exact clip
- headnode = SV_HullForEntity (touch);
- angles = touch->s.angles;
- if (touch->solid != SOLID_BSP)
- angles = vec3_origin; // boxes don't rotate
-
- if (touch->svflags & SVF_MONSTER)
- trace = CM_TransformedBoxTrace (clip->start, clip->end,
- clip->mins2, clip->maxs2, headnode, clip->contentmask,
- touch->s.origin, angles);
- else
- trace = CM_TransformedBoxTrace (clip->start, clip->end,
- clip->mins, clip->maxs, headnode, clip->contentmask,
- touch->s.origin, angles);
-
- if (trace.allsolid || trace.startsolid ||
- trace.fraction < clip->trace.fraction)
- {
- trace.ent = touch;
- if (clip->trace.startsolid)
- {
- clip->trace = trace;
- clip->trace.startsolid = true;
- }
- else
- clip->trace = trace;
- }
- else if (trace.startsolid)
- clip->trace.startsolid = true;
- }
-}
-
-
-/*
-==================
-SV_TraceBounds
-==================
-*/
-void SV_TraceBounds (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t boxmins, vec3_t boxmaxs)
-{
-/*
- // debug to test against everything
- boxmins[0] = boxmins[1] = boxmins[2] = -9999;
- boxmaxs[0] = boxmaxs[1] = boxmaxs[2] = 9999;
-*/
- int i;
-
- for (i=0 ; i<3 ; i++)
- {
- if (end[i] > start[i])
- {
- boxmins[i] = start[i] + mins[i] - 1;
- boxmaxs[i] = end[i] + maxs[i] + 1;
- }
- else
- {
- boxmins[i] = end[i] + mins[i] - 1;
- boxmaxs[i] = start[i] + maxs[i] + 1;
- }
- }
-}
-
-/*
-==================
-SV_Trace
-
-Moves the given mins/maxs volume through the world from start to end.
-
-Passedict and edicts owned by passedict are explicitly not checked.
-
-==================
-*/
-trace_t SV_Trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask)
-{
- moveclip_t clip;
-
- if (!mins)
- mins = vec3_origin;
- if (!maxs)
- maxs = vec3_origin;
-
- memset ( &clip, 0, sizeof ( moveclip_t ) );
-
- // clip to world
- clip.trace = CM_BoxTrace (start, end, mins, maxs, 0, contentmask);
- clip.trace.ent = ge->edicts;
- if (clip.trace.fraction == 0)
- return clip.trace; // blocked by the world
-
- clip.contentmask = contentmask;
- clip.start = start;
- clip.end = end;
- clip.mins = mins;
- clip.maxs = maxs;
- clip.passedict = passedict;
-
- VectorCopy (mins, clip.mins2);
- VectorCopy (maxs, clip.maxs2);
-
- // create the bounding box of the entire move
- SV_TraceBounds ( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs );
-
- // clip to other solid entities
- SV_ClipMoveToEntities ( &clip );
-
- return clip.trace;
-}
-
--- /dev/null
+++ b/snd.c
@@ -1,0 +1,129 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include <thread.h>
+#include "dat.h"
+#include "fns.h"
+
+static cvar_t *sndbits;
+static cvar_t *sndspeed;
+static cvar_t *sndchannels;
+static cvar_t *snddev;
+
+static int afd, sndon, wpos;
+enum{
+ Nbuf = 32
+};
+static Channel *schan;
+static QLock sndlock;
+
+
+static void
+sproc(void *)
+{
+ int n;
+
+ threadsetgrp(THsnd);
+
+ for(;;){
+ if(recv(schan, nil) < 0){
+ fprint(2, "sproc:recv %r\n");
+ break;
+ }
+ if((n = write(afd, dma.buffer, dma.samplebits/8 * dma.samples)) < 0){
+ fprint(2, "sproc:write %r\n");
+ break;
+ }
+ qlock(&sndlock);
+ wpos += n;
+ qunlock(&sndlock);
+ }
+ fprint(2, "sproc %d: %r\n", threadpid(threadid()));
+}
+
+qboolean
+SNDDMA_Init(void)
+{
+ if(sndon)
+ return false;
+
+ if(COM_CheckParm("-nosound"))
+ return false;
+
+ if(snddev == nil){
+ sndbits = Cvar_Get("sndbits", "16", CVAR_ARCHIVE);
+ sndspeed = Cvar_Get("sndspeed", "44100", CVAR_ARCHIVE);
+ sndchannels = Cvar_Get("sndchannels", "2", CVAR_ARCHIVE);
+ snddev = Cvar_Get("snddev", "/dev/audio", CVAR_ARCHIVE);
+ }
+
+ if((afd = open(snddev->string, OWRITE)) < 0){
+ fprint(2, "SNDDMA_Init:open %r\n");
+ return false;
+ }
+
+ dma.samplebits = (int)sndbits->value;
+ if(dma.samplebits != 16 && dma.samplebits != 8)
+ dma.samplebits = 16;
+ dma.speed = (int)sndspeed->value;
+ if(dma.speed != 44100)
+ dma.speed = 44100;
+ dma.channels = (int)sndchannels->value;
+ if(dma.channels < 1 || dma.channels > 2)
+ dma.channels = 2;
+ dma.samples = 8192;
+ dma.submission_chunk = 1;
+ if((dma.buffer = mallocz(dma.samplebits/8 * dma.samples, 1)) == nil)
+ sysfatal("SNDDMA_Init:mallocz: %r\n");
+ dma.samplepos = 0;
+ sndon = 1;
+ wpos = 0;
+
+ schan = chancreate(sizeof(int), Nbuf);
+ if(proccreate(sproc, nil, 8192) < 0){
+ SNDDMA_Shutdown();
+ sysfatal("SNDDMA_Init:proccreate: %r\n");
+ }
+ return true;
+}
+
+int
+SNDDMA_GetDMAPos(void)
+{
+ if(!sndon)
+ return 0;
+ qlock(&sndlock);
+ dma.samplepos = wpos / (dma.samplebits/8);
+ qunlock(&sndlock);
+ return dma.samplepos;
+}
+
+void
+SNDDMA_Shutdown(void)
+{
+ if(!sndon)
+ return;
+
+ threadkillgrp(THsnd);
+ close(afd);
+ if(schan != nil){
+ chanfree(schan);
+ schan = nil;
+ }
+ free(dma.buffer);
+ sndon = 0;
+}
+
+void
+SNDDMA_Submit(void)
+{
+ if(nbsend(schan, nil) < 0){
+ fprint(2, "SNDDMA_Submit:nbsend: %r\n");
+ SNDDMA_Shutdown();
+ }
+}
+
+void
+SNDDMA_BeginPainting(void)
+{
+}
--- /dev/null
+++ b/snd_dma.c
@@ -1,0 +1,1196 @@
+// snd_dma.c -- main control for any streaming sound output device
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+void S_Play(void);
+void S_SoundList(void);
+void S_Update_(void);
+void S_StopAllSounds(void);
+
+
+// =======================================================================
+// Internal sound data & structures
+// =======================================================================
+
+// only begin attenuating sound volumes when outside the FULLVOLUME range
+#define SOUND_FULLVOLUME 80
+
+#define SOUND_LOOPATTENUATE 0.003
+
+int s_registration_sequence;
+
+channel_t channels[MAX_CHANNELS];
+
+qboolean snd_initialized = false;
+int sound_started=0;
+
+dma_t dma;
+
+vec3_t listener_origin;
+vec3_t listener_forward;
+vec3_t listener_right;
+vec3_t listener_up;
+
+qboolean s_registering;
+
+int soundtime; // sample PAIRS
+int paintedtime; // sample PAIRS
+
+// during registration it is possible to have more sounds
+// than could actually be referenced during gameplay,
+// because we don't want to free anything until we are
+// sure we won't need it.
+#define MAX_SFX (MAX_SOUNDS*2)
+sfx_t known_sfx[MAX_SFX];
+int num_sfx;
+
+#define MAX_PLAYSOUNDS 128
+playsound_t s_playsounds[MAX_PLAYSOUNDS];
+playsound_t s_freeplays;
+playsound_t s_pendingplays;
+
+int s_beginofs;
+
+cvar_t *s_volume;
+cvar_t *s_testsound;
+cvar_t *s_loadas8bit;
+cvar_t *s_khz;
+cvar_t *s_show;
+cvar_t *s_mixahead;
+cvar_t *s_primary;
+
+
+int s_rawend;
+portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
+
+
+// ====================================================================
+// User-setable variables
+// ====================================================================
+
+
+void S_SoundInfo_f(void)
+{
+ if (!sound_started)
+ {
+ Com_Printf ("sound system not started\n");
+ return;
+ }
+
+ Com_Printf("%5d stereo\n", dma.channels - 1);
+ Com_Printf("%5d samples\n", dma.samples);
+ Com_Printf("%5d samplepos\n", dma.samplepos);
+ Com_Printf("%5d samplebits\n", dma.samplebits);
+ Com_Printf("%5d submission_chunk\n", dma.submission_chunk);
+ Com_Printf("%5d speed\n", dma.speed);
+ Com_Printf("0x%x dma buffer\n", dma.buffer);
+}
+
+
+
+/*
+================
+S_Init
+================
+*/
+void S_Init (void)
+{
+ cvar_t *cv;
+
+ Com_Printf("\n------- sound initialization -------\n");
+
+ cv = Cvar_Get ("s_initsound", "1", 0);
+ if (!cv->value)
+ Com_Printf ("not initializing.\n");
+ else
+ {
+ s_volume = Cvar_Get ("s_volume", "0.7", CVAR_ARCHIVE);
+ s_khz = Cvar_Get ("s_khz", "11", CVAR_ARCHIVE);
+ s_loadas8bit = Cvar_Get ("s_loadas8bit", "1", CVAR_ARCHIVE);
+ s_mixahead = Cvar_Get ("s_mixahead", "0.2", CVAR_ARCHIVE);
+ s_show = Cvar_Get ("s_show", "0", 0);
+ s_testsound = Cvar_Get ("s_testsound", "0", 0);
+ s_primary = Cvar_Get ("s_primary", "0", CVAR_ARCHIVE); // win32 specific
+
+ Cmd_AddCommand("play", S_Play);
+ Cmd_AddCommand("stopsound", S_StopAllSounds);
+ Cmd_AddCommand("soundlist", S_SoundList);
+ Cmd_AddCommand("soundinfo", S_SoundInfo_f);
+
+ if (!SNDDMA_Init())
+ return;
+
+ S_InitScaletable ();
+
+ sound_started = 1;
+ num_sfx = 0;
+
+ soundtime = 0;
+ paintedtime = 0;
+
+ Com_Printf ("sound sampling rate: %i\n", dma.speed);
+
+ S_StopAllSounds ();
+ }
+
+ Com_Printf("------------------------------------\n");
+}
+
+
+// =======================================================================
+// Shutdown sound engine
+// =======================================================================
+
+void S_Shutdown(void)
+{
+ int i;
+ sfx_t *sfx;
+
+ if (!sound_started)
+ return;
+
+ SNDDMA_Shutdown();
+
+ sound_started = 0;
+
+ Cmd_RemoveCommand("play");
+ Cmd_RemoveCommand("stopsound");
+ Cmd_RemoveCommand("soundlist");
+ Cmd_RemoveCommand("soundinfo");
+
+ // free all sounds
+ for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
+ {
+ if (!sfx->name[0])
+ continue;
+ if (sfx->cache)
+ Z_Free (sfx->cache);
+ memset (sfx, 0, sizeof(*sfx));
+ }
+
+ num_sfx = 0;
+}
+
+
+// =======================================================================
+// Load a sound
+// =======================================================================
+
+/*
+==================
+S_FindName
+
+==================
+*/
+sfx_t *S_FindName (char *name, qboolean create)
+{
+ int i;
+ sfx_t *sfx;
+
+ if (!name)
+ Com_Error (ERR_FATAL, "S_FindName: NULL\n");
+ if (!name[0])
+ Com_Error (ERR_FATAL, "S_FindName: empty name\n");
+
+ if (strlen(name) >= MAX_QPATH)
+ Com_Error (ERR_FATAL, "Sound name too long: %s", name);
+
+ // see if already loaded
+ for (i=0 ; i < num_sfx ; i++)
+ if (!strcmp(known_sfx[i].name, name))
+ {
+ return &known_sfx[i];
+ }
+
+ if (!create)
+ return NULL;
+
+ // find a free sfx
+ for (i=0 ; i < num_sfx ; i++)
+ if (!known_sfx[i].name[0])
+// registration_sequence < s_registration_sequence)
+ break;
+
+ if (i == num_sfx)
+ {
+ if (num_sfx == MAX_SFX)
+ Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
+ num_sfx++;
+ }
+
+ sfx = &known_sfx[i];
+ memset (sfx, 0, sizeof(*sfx));
+ strcpy (sfx->name, name);
+ sfx->registration_sequence = s_registration_sequence;
+
+ return sfx;
+}
+
+
+/*
+==================
+S_AliasName
+
+==================
+*/
+sfx_t *S_AliasName (char *aliasname, char *truename)
+{
+ sfx_t *sfx;
+ char *s;
+ int i;
+
+ s = Z_Malloc (MAX_QPATH);
+ strcpy (s, truename);
+
+ // find a free sfx
+ for (i=0 ; i < num_sfx ; i++)
+ if (!known_sfx[i].name[0])
+ break;
+
+ if (i == num_sfx)
+ {
+ if (num_sfx == MAX_SFX)
+ Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
+ num_sfx++;
+ }
+
+ sfx = &known_sfx[i];
+ memset (sfx, 0, sizeof(*sfx));
+ strcpy (sfx->name, aliasname);
+ sfx->registration_sequence = s_registration_sequence;
+ sfx->truename = s;
+
+ return sfx;
+}
+
+
+/*
+=====================
+S_BeginRegistration
+
+=====================
+*/
+void S_BeginRegistration (void)
+{
+ s_registration_sequence++;
+ s_registering = true;
+}
+
+/*
+==================
+S_RegisterSound
+
+==================
+*/
+sfx_t *S_RegisterSound (char *name)
+{
+ sfx_t *sfx;
+
+ if (!sound_started)
+ return NULL;
+
+ sfx = S_FindName (name, true);
+ sfx->registration_sequence = s_registration_sequence;
+
+ if (!s_registering)
+ S_LoadSound (sfx);
+
+ return sfx;
+}
+
+
+/*
+=====================
+S_EndRegistration
+
+=====================
+*/
+void S_EndRegistration (void)
+{
+ int i;
+ sfx_t *sfx;
+ int size;
+
+ // free any sounds not from this registration sequence
+ for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
+ {
+ if (!sfx->name[0])
+ continue;
+ if (sfx->registration_sequence != s_registration_sequence)
+ { // don't need this sound
+ if (sfx->cache) // it is possible to have a leftover
+ Z_Free (sfx->cache); // from a server that didn't finish loading
+ memset (sfx, 0, sizeof(*sfx));
+ }
+ else
+ { // make sure it is paged in
+ if (sfx->cache)
+ {
+ size = sfx->cache->length*sfx->cache->width;
+ Com_PageInMemory ((byte *)sfx->cache, size);
+ }
+ }
+
+ }
+
+ // load everything in
+ for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
+ {
+ if (!sfx->name[0])
+ continue;
+ S_LoadSound (sfx);
+ }
+
+ s_registering = false;
+}
+
+
+//=============================================================================
+
+/*
+=================
+S_PickChannel
+=================
+*/
+channel_t *S_PickChannel(int entnum, int entchannel)
+{
+ int ch_idx;
+ int first_to_die;
+ int life_left;
+ channel_t *ch;
+
+ if (entchannel<0)
+ Com_Error (ERR_DROP, "S_PickChannel: entchannel<0");
+
+// Check for replacement sound, or find the best one to replace
+ first_to_die = -1;
+ life_left = 0x7fffffff;
+ for (ch_idx=0 ; ch_idx < MAX_CHANNELS ; ch_idx++)
+ {
+ if (entchannel != 0 // channel 0 never overrides
+ && channels[ch_idx].entnum == entnum
+ && channels[ch_idx].entchannel == entchannel)
+ { // always override sound from same entity
+ first_to_die = ch_idx;
+ break;
+ }
+
+ // don't let monster sounds override player sounds
+ if (channels[ch_idx].entnum == cl.playernum+1 && entnum != cl.playernum+1 && channels[ch_idx].sfx)
+ continue;
+
+ if (channels[ch_idx].end - paintedtime < life_left)
+ {
+ life_left = channels[ch_idx].end - paintedtime;
+ first_to_die = ch_idx;
+ }
+ }
+
+ if (first_to_die == -1)
+ return NULL;
+
+ ch = &channels[first_to_die];
+ memset (ch, 0, sizeof(*ch));
+
+ return ch;
+}
+
+/*
+=================
+S_SpatializeOrigin
+
+Used for spatializing channels and autosounds
+=================
+*/
+void S_SpatializeOrigin (vec3_t origin, float master_vol, float dist_mult, int *left_vol, int *right_vol)
+{
+ vec_t dot;
+ vec_t dist;
+ vec_t lscale, rscale, scale;
+ vec3_t source_vec;
+
+ if (cls.state != ca_active)
+ {
+ *left_vol = *right_vol = 255;
+ return;
+ }
+
+// calculate stereo seperation and distance attenuation
+ VectorSubtract(origin, listener_origin, source_vec);
+
+ dist = VectorNormalize(source_vec);
+ dist -= SOUND_FULLVOLUME;
+ if (dist < 0)
+ dist = 0; // close enough to be at full volume
+ dist *= dist_mult; // different attenuation levels
+
+ dot = DotProduct(listener_right, source_vec);
+
+ if (dma.channels == 1 || !dist_mult)
+ { // no attenuation = no spatialization
+ rscale = 1.0;
+ lscale = 1.0;
+ }
+ else
+ {
+ rscale = 0.5 * (1.0 + dot);
+ lscale = 0.5*(1.0 - dot);
+ }
+
+ // add in distance effect
+ scale = (1.0 - dist) * rscale;
+ *right_vol = (int) (master_vol * scale);
+ if (*right_vol < 0)
+ *right_vol = 0;
+
+ scale = (1.0 - dist) * lscale;
+ *left_vol = (int) (master_vol * scale);
+ if (*left_vol < 0)
+ *left_vol = 0;
+}
+
+/*
+=================
+S_Spatialize
+=================
+*/
+void S_Spatialize(channel_t *ch)
+{
+ vec3_t origin;
+
+ // anything coming from the view entity will always be full volume
+ if (ch->entnum == cl.playernum+1)
+ {
+ ch->leftvol = ch->master_vol;
+ ch->rightvol = ch->master_vol;
+ return;
+ }
+
+ if (ch->fixed_origin)
+ {
+ VectorCopy (ch->origin, origin);
+ }
+ else
+ CL_GetEntitySoundOrigin (ch->entnum, origin);
+
+ S_SpatializeOrigin (origin, ch->master_vol, ch->dist_mult, &ch->leftvol, &ch->rightvol);
+}
+
+
+/*
+=================
+S_AllocPlaysound
+=================
+*/
+playsound_t *S_AllocPlaysound (void)
+{
+ playsound_t *ps;
+
+ ps = s_freeplays.next;
+ if (ps == &s_freeplays)
+ return NULL; // no free playsounds
+
+ // unlink from freelist
+ ps->prev->next = ps->next;
+ ps->next->prev = ps->prev;
+
+ return ps;
+}
+
+
+/*
+=================
+S_FreePlaysound
+=================
+*/
+void S_FreePlaysound (playsound_t *ps)
+{
+ // unlink from channel
+ ps->prev->next = ps->next;
+ ps->next->prev = ps->prev;
+
+ // add to free list
+ ps->next = s_freeplays.next;
+ s_freeplays.next->prev = ps;
+ ps->prev = &s_freeplays;
+ s_freeplays.next = ps;
+}
+
+
+
+/*
+===============
+S_IssuePlaysound
+
+Take the next playsound and begin it on the channel
+This is never called directly by S_Play*, but only
+by the update loop.
+===============
+*/
+void S_IssuePlaysound (playsound_t *ps)
+{
+ channel_t *ch;
+ sfxcache_t *sc;
+
+ if (s_show->value)
+ Com_Printf ("Issue %i\n", ps->begin);
+ // pick a channel to play on
+ ch = S_PickChannel(ps->entnum, ps->entchannel);
+ if (!ch)
+ {
+ S_FreePlaysound (ps);
+ return;
+ }
+
+ // spatialize
+ if (ps->attenuation == ATTN_STATIC)
+ ch->dist_mult = ps->attenuation * 0.001;
+ else
+ ch->dist_mult = ps->attenuation * 0.0005;
+ ch->master_vol = ps->volume;
+ ch->entnum = ps->entnum;
+ ch->entchannel = ps->entchannel;
+ ch->sfx = ps->sfx;
+ VectorCopy (ps->origin, ch->origin);
+ ch->fixed_origin = ps->fixed_origin;
+
+ S_Spatialize(ch);
+
+ ch->pos = 0;
+ sc = S_LoadSound (ch->sfx);
+ ch->end = paintedtime + sc->length;
+
+ // free the playsound
+ S_FreePlaysound (ps);
+}
+
+sfx_t *
+S_RegisterSexedSound(entity_state_t *ent, char *base)
+{
+ int n;
+ char *p;
+ sfx_t *sfx;
+ FILE *f;
+ char model[MAX_QPATH];
+ char sexedFilename[MAX_QPATH];
+ char maleFilename[MAX_QPATH];
+
+ // determine what model the client is using
+ model[0] = 0;
+ n = CS_PLAYERSKINS + ent->number - 1;
+ if (cl.configstrings[n][0])
+ {
+ p = strchr(cl.configstrings[n], '\\');
+ if (p)
+ {
+ p += 1;
+ strcpy(model, p);
+ p = strchr(model, '/');
+ if (p)
+ *p = 0;
+ }
+ }
+ // if we can't figure it out, they're male
+ if (!model[0])
+ strcpy(model, "male");
+
+ // see if we already know of the model specific sound
+ Com_sprintf (sexedFilename, sizeof(sexedFilename), "#players/%s/%s", model, base+1);
+ sfx = S_FindName (sexedFilename, false);
+
+ if (!sfx)
+ {
+ // no, so see if it exists
+ FS_FOpenFile (&sexedFilename[1], &f);
+ if (f)
+ {
+ // yes, close the file and register it
+ FS_FCloseFile (f);
+ sfx = S_RegisterSound (sexedFilename);
+ }
+ else
+ {
+ // no, revert to the male sound in the pak0.pak
+ Com_sprintf (maleFilename, sizeof(maleFilename), "player/%s/%s", "male", base+1);
+ sfx = S_AliasName (sexedFilename, maleFilename);
+ }
+ }
+
+ return sfx;
+}
+
+
+// =======================================================================
+// Start a sound effect
+// =======================================================================
+
+/*
+====================
+S_StartSound
+
+Validates the parms and ques the sound up
+if pos is NULL, the sound will be dynamically sourced from the entity
+Entchannel 0 will never override a playing sound
+====================
+*/
+void S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float timeofs)
+{
+ sfxcache_t *sc;
+ int vol;
+ playsound_t *ps, *sort;
+ int start;
+
+ if (!sound_started)
+ return;
+
+ if (!sfx)
+ return;
+
+ if (sfx->name[0] == '*')
+ sfx = S_RegisterSexedSound(&cl_entities[entnum].current, sfx->name);
+
+ // make sure the sound is loaded
+ sc = S_LoadSound (sfx);
+ if (!sc)
+ return; // couldn't load the sound's data
+
+ vol = fvol*255;
+
+ // make the playsound_t
+ ps = S_AllocPlaysound ();
+ if (!ps)
+ return;
+
+ if (origin)
+ {
+ VectorCopy (origin, ps->origin);
+ ps->fixed_origin = true;
+ }
+ else
+ ps->fixed_origin = false;
+
+ ps->entnum = entnum;
+ ps->entchannel = entchannel;
+ ps->attenuation = attenuation;
+ ps->volume = vol;
+ ps->sfx = sfx;
+
+ // drift s_beginofs
+ start = cl.frame.servertime * 0.001 * dma.speed + s_beginofs;
+ if (start < paintedtime)
+ {
+ start = paintedtime;
+ s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed);
+ }
+ else if (start > paintedtime + 0.3 * dma.speed)
+ {
+ start = paintedtime + 0.1 * dma.speed;
+ s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed);
+ }
+ else
+ {
+ s_beginofs-=10;
+ }
+
+ if (!timeofs)
+ ps->begin = paintedtime;
+ else
+ ps->begin = start + timeofs * dma.speed;
+
+ // sort into the pending sound list
+ for (sort = s_pendingplays.next ;
+ sort != &s_pendingplays && sort->begin < ps->begin ;
+ sort = sort->next)
+ ;
+
+ ps->next = sort;
+ ps->prev = sort->prev;
+
+ ps->next->prev = ps;
+ ps->prev->next = ps;
+}
+
+
+/*
+==================
+S_StartLocalSound
+==================
+*/
+void S_StartLocalSound (char *sound)
+{
+ sfx_t *sfx;
+
+ if (!sound_started)
+ return;
+
+ sfx = S_RegisterSound (sound);
+ if (!sfx)
+ {
+ Com_Printf ("S_StartLocalSound: can't cache %s\n", sound);
+ return;
+ }
+ S_StartSound (NULL, cl.playernum+1, 0, sfx, 1, 1, 0);
+}
+
+
+/*
+==================
+S_ClearBuffer
+==================
+*/
+void S_ClearBuffer (void)
+{
+ int clear;
+
+ if (!sound_started)
+ return;
+
+ s_rawend = 0;
+
+ if (dma.samplebits == 8)
+ clear = 0x80;
+ else
+ clear = 0;
+
+ SNDDMA_BeginPainting ();
+ if (dma.buffer)
+ memset(dma.buffer, clear, dma.samples * dma.samplebits/8);
+ SNDDMA_Submit ();
+}
+
+/*
+==================
+S_StopAllSounds
+==================
+*/
+void S_StopAllSounds(void)
+{
+ int i;
+
+ if (!sound_started)
+ return;
+
+ // clear all the playsounds
+ memset(s_playsounds, 0, sizeof(s_playsounds));
+ s_freeplays.next = s_freeplays.prev = &s_freeplays;
+ s_pendingplays.next = s_pendingplays.prev = &s_pendingplays;
+
+ for (i=0 ; i<MAX_PLAYSOUNDS ; i++)
+ {
+ s_playsounds[i].prev = &s_freeplays;
+ s_playsounds[i].next = s_freeplays.next;
+ s_playsounds[i].prev->next = &s_playsounds[i];
+ s_playsounds[i].next->prev = &s_playsounds[i];
+ }
+
+ // clear all the channels
+ memset(channels, 0, sizeof(channels));
+
+ S_ClearBuffer ();
+}
+
+/*
+==================
+S_AddLoopSounds
+
+Entities with a ->sound field will generated looped sounds
+that are automatically started, stopped, and merged together
+as the entities are sent to the client
+==================
+*/
+void S_AddLoopSounds (void)
+{
+ int i, j;
+ int sounds[MAX_EDICTS];
+ int left, right, left_total, right_total;
+ channel_t *ch;
+ sfx_t *sfx;
+ sfxcache_t *sc;
+ int num;
+ entity_state_t *ent;
+
+ if (cl_paused->value)
+ return;
+
+ if (cls.state != ca_active)
+ return;
+
+ if (!cl.sound_prepped)
+ return;
+
+ for (i=0 ; i<cl.frame.num_entities ; i++)
+ {
+ num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
+ ent = &cl_parse_entities[num];
+ sounds[i] = ent->sound;
+ }
+
+ for (i=0 ; i<cl.frame.num_entities ; i++)
+ {
+ if (!sounds[i])
+ continue;
+
+ sfx = cl.sound_precache[sounds[i]];
+ if (!sfx)
+ continue; // bad sound effect
+ sc = sfx->cache;
+ if (!sc)
+ continue;
+
+ num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
+ ent = &cl_parse_entities[num];
+
+ // find the total contribution of all sounds of this type
+ S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE,
+ &left_total, &right_total);
+ for (j=i+1 ; j<cl.frame.num_entities ; j++)
+ {
+ if (sounds[j] != sounds[i])
+ continue;
+ sounds[j] = 0; // don't check this again later
+
+ num = (cl.frame.parse_entities + j)&(MAX_PARSE_ENTITIES-1);
+ ent = &cl_parse_entities[num];
+
+ S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE,
+ &left, &right);
+ left_total += left;
+ right_total += right;
+ }
+
+ if (left_total == 0 && right_total == 0)
+ continue; // not audible
+
+ // allocate a channel
+ ch = S_PickChannel(0, 0);
+ if (!ch)
+ return;
+
+ if (left_total > 255)
+ left_total = 255;
+ if (right_total > 255)
+ right_total = 255;
+ ch->leftvol = left_total;
+ ch->rightvol = right_total;
+ ch->autosound = true; // remove next frame
+ ch->sfx = sfx;
+ ch->pos = paintedtime % sc->length;
+ ch->end = paintedtime + sc->length - ch->pos;
+ }
+}
+
+//=============================================================================
+
+/*
+============
+S_RawSamples
+
+Cinematic streaming and voice over network
+============
+*/
+void S_RawSamples (int samples, int rate, int width, int channels, byte *data)
+{
+ int i;
+ int src, dst;
+ float scale;
+
+ if (!sound_started)
+ return;
+
+ if (s_rawend < paintedtime)
+ s_rawend = paintedtime;
+ scale = (float)rate / dma.speed;
+
+//Com_Printf ("%i < %i < %i\n", soundtime, paintedtime, s_rawend);
+ if (channels == 2 && width == 2)
+ {
+ if (scale == 1.0)
+ { // optimized case
+ for (i=0 ; i<samples ; i++)
+ {
+ dst = s_rawend&(MAX_RAW_SAMPLES-1);
+ s_rawend++;
+ s_rawsamples[dst].left =
+ LittleShort(((short *)data)[i*2]) << 8;
+ s_rawsamples[dst].right =
+ LittleShort(((short *)data)[i*2+1]) << 8;
+ }
+ }
+ else
+ {
+ for (i=0 ; ; i++)
+ {
+ src = i*scale;
+ if (src >= samples)
+ break;
+ dst = s_rawend&(MAX_RAW_SAMPLES-1);
+ s_rawend++;
+ s_rawsamples[dst].left =
+ LittleShort(((short *)data)[src*2]) << 8;
+ s_rawsamples[dst].right =
+ LittleShort(((short *)data)[src*2+1]) << 8;
+ }
+ }
+ }
+ else if (channels == 1 && width == 2)
+ {
+ for (i=0 ; ; i++)
+ {
+ src = i*scale;
+ if (src >= samples)
+ break;
+ dst = s_rawend&(MAX_RAW_SAMPLES-1);
+ s_rawend++;
+ s_rawsamples[dst].left =
+ LittleShort(((short *)data)[src]) << 8;
+ s_rawsamples[dst].right =
+ LittleShort(((short *)data)[src]) << 8;
+ }
+ }
+ else if (channels == 2 && width == 1)
+ {
+ for (i=0 ; ; i++)
+ {
+ src = i*scale;
+ if (src >= samples)
+ break;
+ dst = s_rawend&(MAX_RAW_SAMPLES-1);
+ s_rawend++;
+ s_rawsamples[dst].left =
+ ((char *)data)[src*2] << 16;
+ s_rawsamples[dst].right =
+ ((char *)data)[src*2+1] << 16;
+ }
+ }
+ else if (channels == 1 && width == 1)
+ {
+ for (i=0 ; ; i++)
+ {
+ src = i*scale;
+ if (src >= samples)
+ break;
+ dst = s_rawend&(MAX_RAW_SAMPLES-1);
+ s_rawend++;
+ s_rawsamples[dst].left =
+ (((byte *)data)[src]-128) << 16;
+ s_rawsamples[dst].right = (((byte *)data)[src]-128) << 16;
+ }
+ }
+}
+
+//=============================================================================
+
+/*
+============
+S_Update
+
+Called once each time through the main loop
+============
+*/
+void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
+{
+ int i;
+ int total;
+ channel_t *ch;
+
+ if (!sound_started)
+ return;
+
+ // if the laoding plaque is up, clear everything
+ // out to make sure we aren't looping a dirty
+ // dma buffer while loading
+ if (cls.disable_screen)
+ {
+ S_ClearBuffer ();
+ return;
+ }
+
+ // rebuild scale tables if volume is modified
+ if (s_volume->modified)
+ S_InitScaletable ();
+
+ VectorCopy(origin, listener_origin);
+ VectorCopy(forward, listener_forward);
+ VectorCopy(right, listener_right);
+ VectorCopy(up, listener_up);
+
+ // update spatialization for dynamic sounds
+ ch = channels;
+ for (i=0 ; i<MAX_CHANNELS; i++, ch++)
+ {
+ if (!ch->sfx)
+ continue;
+ if (ch->autosound)
+ { // autosounds are regenerated fresh each frame
+ memset (ch, 0, sizeof(*ch));
+ continue;
+ }
+ S_Spatialize(ch); // respatialize channel
+ if (!ch->leftvol && !ch->rightvol)
+ {
+ memset (ch, 0, sizeof(*ch));
+ continue;
+ }
+ }
+
+ // add loopsounds
+ S_AddLoopSounds ();
+
+ //
+ // debugging output
+ //
+ if (s_show->value)
+ {
+ total = 0;
+ ch = channels;
+ for (i=0 ; i<MAX_CHANNELS; i++, ch++)
+ if (ch->sfx && (ch->leftvol || ch->rightvol) )
+ {
+ Com_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);
+ total++;
+ }
+
+ Com_Printf ("----(%i)---- painted: %i\n", total, paintedtime);
+ }
+
+// mix some sound
+ S_Update_();
+}
+
+void GetSoundtime(void)
+{
+ int samplepos;
+ static int buffers;
+ static int oldsamplepos;
+ int fullsamples;
+
+ fullsamples = dma.samples / dma.channels;
+
+// it is possible to miscount buffers if it has wrapped twice between
+// calls to S_Update. Oh well.
+ samplepos = SNDDMA_GetDMAPos();
+
+ if (samplepos < oldsamplepos)
+ {
+ buffers++; // buffer wrapped
+
+ if (paintedtime > 0x40000000)
+ { // time to chop things off to avoid 32 bit limits
+ buffers = 0;
+ paintedtime = fullsamples;
+ S_StopAllSounds ();
+ }
+ }
+ oldsamplepos = samplepos;
+
+ soundtime = buffers*fullsamples + samplepos/dma.channels;
+}
+
+
+void S_Update_(void)
+{
+ unsigned endtime;
+ int samps;
+
+ if (!sound_started)
+ return;
+
+ SNDDMA_BeginPainting ();
+
+ if (!dma.buffer)
+ return;
+
+// Updates DMA time
+ GetSoundtime();
+
+// check to make sure that we haven't overshot
+ if (paintedtime < soundtime)
+ {
+ Com_DPrintf ("S_Update_ : overflow\n");
+ paintedtime = soundtime;
+ }
+
+// mix ahead of current position
+ endtime = soundtime + s_mixahead->value * dma.speed;
+//endtime = (soundtime + 4096) & ~4095;
+
+ // mix to an even submission block size
+ endtime = (endtime + dma.submission_chunk-1)
+ & ~(dma.submission_chunk-1);
+ samps = dma.samples >> (dma.channels-1);
+ if (endtime - soundtime > samps)
+ endtime = soundtime + samps;
+
+ S_PaintChannels (endtime);
+
+ SNDDMA_Submit ();
+}
+
+/*
+===============================================================================
+
+console functions
+
+===============================================================================
+*/
+
+void S_Play(void)
+{
+ int i;
+ char name[256];
+ sfx_t *sfx;
+
+ i = 1;
+ while (i<Cmd_Argc())
+ {
+ if (!strrchr(Cmd_Argv(i), '.'))
+ {
+ strcpy(name, Cmd_Argv(i));
+ strcat(name, ".wav");
+ }
+ else
+ strcpy(name, Cmd_Argv(i));
+ sfx = S_RegisterSound(name);
+ S_StartSound(NULL, cl.playernum+1, 0, sfx, 1.0, 1.0, 0);
+ i++;
+ }
+}
+
+void S_SoundList(void)
+{
+ int i;
+ sfx_t *sfx;
+ sfxcache_t *sc;
+ int size, total;
+
+ total = 0;
+ for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)
+ {
+ if (!sfx->registration_sequence)
+ continue;
+ sc = sfx->cache;
+ if (sc)
+ {
+ size = sc->length*sc->width*(sc->stereo+1);
+ total += size;
+ if (sc->loopstart >= 0)
+ Com_Printf ("L");
+ else
+ Com_Printf (" ");
+ Com_Printf("(%2db) %6i : %s\n",sc->width*8, size, sfx->name);
+ }
+ else
+ {
+ if (sfx->name[0] == '*')
+ Com_Printf(" placeholder : %s\n", sfx->name);
+ else
+ Com_Printf(" not loaded : %s\n", sfx->name);
+ }
+ }
+ Com_Printf ("Total resident: %i\n", total);
+}
+
--- /dev/null
+++ b/snd_mem.c
@@ -1,0 +1,342 @@
+// snd_mem.c: sound caching
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+int cache_full_cycle;
+
+byte *S_Alloc (int size);
+
+/*
+================
+ResampleSfx
+================
+*/
+void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data)
+{
+ int outcount;
+ int srcsample;
+ float stepscale;
+ int i;
+ int sample, samplefrac, fracstep;
+ sfxcache_t *sc;
+
+ sc = sfx->cache;
+ if (!sc)
+ return;
+
+ stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
+
+ outcount = sc->length / stepscale;
+ sc->length = outcount;
+ if (sc->loopstart != -1)
+ sc->loopstart = sc->loopstart / stepscale;
+
+ sc->speed = dma.speed;
+ if (s_loadas8bit->value)
+ sc->width = 1;
+ else
+ sc->width = inwidth;
+ sc->stereo = 0;
+
+// resample / decimate to the current source rate
+
+ if (stepscale == 1 && inwidth == 1 && sc->width == 1)
+ {
+// fast special case
+ for (i=0 ; i<outcount ; i++)
+ ((signed char *)sc->data)[i]
+ = (int)( (unsigned char)(data[i]) - 128);
+ }
+ else
+ {
+// general case
+ samplefrac = 0;
+ fracstep = stepscale*256;
+ for (i=0 ; i<outcount ; i++)
+ {
+ srcsample = samplefrac >> 8;
+ samplefrac += fracstep;
+ if (inwidth == 2)
+ sample = LittleShort ( ((short *)data)[srcsample] );
+ else
+ sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
+ if (sc->width == 2)
+ ((short *)sc->data)[i] = sample;
+ else
+ ((signed char *)sc->data)[i] = sample >> 8;
+ }
+ }
+}
+
+//=============================================================================
+
+/*
+==============
+S_LoadSound
+==============
+*/
+sfxcache_t *S_LoadSound (sfx_t *s)
+{
+ char namebuffer[MAX_QPATH];
+ byte *data;
+ wavinfo_t info;
+ int len;
+ float stepscale;
+ sfxcache_t *sc;
+ int size;
+ char *name;
+
+ if (s->name[0] == '*')
+ return NULL;
+
+// see if still in memory
+ sc = s->cache;
+ if (sc)
+ return sc;
+
+//Com_Printf ("S_LoadSound: %x\n", (int)stackbuf);
+// load it in
+ if (s->truename)
+ name = s->truename;
+ else
+ name = s->name;
+
+ if (name[0] == '#')
+ strcpy(namebuffer, &name[1]);
+ else
+ Com_sprintf (namebuffer, sizeof(namebuffer), "sound/%s", name);
+
+// Com_Printf ("loading %s\n",namebuffer);
+
+ size = FS_LoadFile (namebuffer, (void **)&data);
+
+ if (!data)
+ {
+ Com_DPrintf ("Couldn't load %s\n", namebuffer);
+ return NULL;
+ }
+
+ info = GetWavinfo (s->name, data, size);
+ if (info.channels != 1)
+ {
+ Com_Printf ("%s is a stereo sample\n",s->name);
+ FS_FreeFile (data);
+ return NULL;
+ }
+
+ stepscale = (float)info.rate / dma.speed;
+ len = info.samples / stepscale;
+
+ len = len * info.width * info.channels;
+
+ sc = s->cache = Z_Malloc (len + sizeof(sfxcache_t));
+ if (!sc)
+ {
+ FS_FreeFile (data);
+ return NULL;
+ }
+
+ sc->length = info.samples;
+ sc->loopstart = info.loopstart;
+ sc->speed = info.rate;
+ sc->width = info.width;
+ sc->stereo = info.channels;
+
+ ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);
+
+ FS_FreeFile (data);
+
+ return sc;
+}
+
+
+
+/*
+===============================================================================
+
+WAV loading
+
+===============================================================================
+*/
+
+
+byte *data_p;
+byte *iff_end;
+byte *last_chunk;
+byte *iff_data;
+int iff_chunk_len;
+
+
+short GetLittleShort(void)
+{
+ short val;
+ val = *data_p;
+ val = val + (*(data_p+1)<<8);
+ data_p += 2;
+ return val;
+}
+
+int GetLittleLong(void)
+{
+ int val;
+ val = *data_p;
+ val = val + (*(data_p+1)<<8);
+ val = val + (*(data_p+2)<<16);
+ val = val + (*(data_p+3)<<24);
+ data_p += 4;
+ return val;
+}
+
+void FindNextChunk(char *name)
+{
+ while (1)
+ {
+ data_p=last_chunk;
+
+ if (data_p >= iff_end)
+ { // didn't find the chunk
+ data_p = NULL;
+ return;
+ }
+
+ data_p += 4;
+ iff_chunk_len = GetLittleLong();
+ if (iff_chunk_len < 0)
+ {
+ data_p = NULL;
+ return;
+ }
+// if (iff_chunk_len > 1024*1024)
+// Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
+ data_p -= 8;
+ last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
+ if (!strncmp((char *)data_p, name, 4))
+ return;
+ }
+}
+
+void FindChunk(char *name)
+{
+ last_chunk = iff_data;
+ FindNextChunk (name);
+}
+
+
+void DumpChunks(void)
+{
+ char str[5];
+
+ str[4] = 0;
+ data_p=iff_data;
+ do
+ {
+ memcpy (str, data_p, 4);
+ data_p += 4;
+ iff_chunk_len = GetLittleLong();
+ Com_Printf ("0x%x : %s (%p)\n", (uintptr)(data_p - 4), str, iff_chunk_len);
+ data_p += (iff_chunk_len + 1) & ~1;
+ } while (data_p < iff_end);
+}
+
+/*
+============
+GetWavinfo
+============
+*/
+wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
+{
+ wavinfo_t info;
+ int i;
+ int format;
+ int samples;
+
+ memset (&info, 0, sizeof(info));
+
+ if (!wav)
+ return info;
+
+ iff_data = wav;
+ iff_end = wav + wavlength;
+
+// find "RIFF" chunk
+ FindChunk("RIFF");
+ if (!(data_p && !strncmp((char *)data_p+8, "WAVE", 4)))
+ {
+ Com_Printf("Missing RIFF/WAVE chunks\n");
+ return info;
+ }
+
+// get "fmt " chunk
+ iff_data = data_p + 12;
+// DumpChunks ();
+
+ FindChunk("fmt ");
+ if (!data_p)
+ {
+ Com_Printf("Missing fmt chunk\n");
+ return info;
+ }
+ data_p += 8;
+ format = GetLittleShort();
+ if (format != 1)
+ {
+ Com_Printf("Microsoft PCM format only\n");
+ return info;
+ }
+
+ info.channels = GetLittleShort();
+ info.rate = GetLittleLong();
+ data_p += 4+2;
+ info.width = GetLittleShort() / 8;
+
+// get cue chunk
+ FindChunk("cue ");
+ if (data_p)
+ {
+ data_p += 32;
+ info.loopstart = GetLittleLong();
+// Com_Printf("loopstart=%d\n", sfx->loopstart);
+
+ // if the next chunk is a LIST chunk, look for a cue length marker
+ FindNextChunk ("LIST");
+ if (data_p)
+ {
+ if (!strncmp ((char *)data_p + 28, "mark", 4))
+ { // this is not a proper parse, but it works with cooledit...
+ data_p += 24;
+ i = GetLittleLong (); // samples in loop
+ info.samples = info.loopstart + i;
+// Com_Printf("looped length: %i\n", i);
+ }
+ }
+ }
+ else
+ info.loopstart = -1;
+
+// find data chunk
+ FindChunk("data");
+ if (!data_p)
+ {
+ Com_Printf("Missing data chunk\n");
+ return info;
+ }
+
+ data_p += 4;
+ samples = GetLittleLong () / info.width;
+
+ if (info.samples)
+ {
+ if (samples < info.samples)
+ Com_Error (ERR_DROP, "Sound %s has a bad loop length", name);
+ }
+ else
+ info.samples = samples;
+
+ info.dataofs = data_p - wav;
+
+ return info;
+}
+
--- /dev/null
+++ b/snd_mix.c
@@ -1,0 +1,350 @@
+// snd_mix.c -- portable code to mix sounds for snd_dma.c
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+#define PAINTBUFFER_SIZE 2048
+portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
+int snd_scaletable[32][256];
+int *snd_p, snd_linear_count, snd_vol;
+short *snd_out;
+
+
+void S_WriteLinearBlastStereo16 (void)
+{
+ int i;
+ int val;
+
+ for (i=0 ; i<snd_linear_count ; i+=2)
+ {
+ val = snd_p[i]>>8;
+ if (val > 0x7fff)
+ snd_out[i] = 0x7fff;
+ else if (val < (short)0x8000)
+ snd_out[i] = (short)0x8000;
+ else
+ snd_out[i] = val;
+
+ val = snd_p[i+1]>>8;
+ if (val > 0x7fff)
+ snd_out[i+1] = 0x7fff;
+ else if (val < (short)0x8000)
+ snd_out[i+1] = (short)0x8000;
+ else
+ snd_out[i+1] = val;
+ }
+}
+
+void S_TransferStereo16 (unsigned long *pbuf, int endtime)
+{
+ int lpos;
+ int lpaintedtime;
+
+ snd_p = (int *) paintbuffer;
+ lpaintedtime = paintedtime;
+
+ while (lpaintedtime < endtime)
+ {
+ // handle recirculating buffer issues
+ lpos = lpaintedtime & ((dma.samples>>1)-1);
+
+ snd_out = (short *) pbuf + (lpos<<1);
+
+ snd_linear_count = (dma.samples>>1) - lpos;
+ if (lpaintedtime + snd_linear_count > endtime)
+ snd_linear_count = endtime - lpaintedtime;
+
+ snd_linear_count <<= 1;
+
+ // write a linear blast of samples
+ S_WriteLinearBlastStereo16 ();
+
+ snd_p += snd_linear_count;
+ lpaintedtime += (snd_linear_count>>1);
+ }
+}
+
+/*
+===================
+S_TransferPaintBuffer
+
+===================
+*/
+void S_TransferPaintBuffer(int endtime)
+{
+ int out_idx;
+ int count;
+ int out_mask;
+ int *p;
+ int step;
+ int val;
+ unsigned long *pbuf;
+
+ pbuf = (unsigned long *)dma.buffer;
+
+ if (s_testsound->value)
+ {
+ int i;
+ int count;
+
+ // write a fixed sine wave
+ count = (endtime - paintedtime);
+ for (i=0 ; i<count ; i++)
+ paintbuffer[i].left = paintbuffer[i].right = sin((paintedtime+i)*0.1)*20000*256;
+ }
+
+
+ if (dma.samplebits == 16 && dma.channels == 2)
+ { // optimized case
+ S_TransferStereo16 (pbuf, endtime);
+ }
+ else
+ { // general case
+ p = (int *) paintbuffer;
+ count = (endtime - paintedtime) * dma.channels;
+ out_mask = dma.samples - 1;
+ out_idx = paintedtime * dma.channels & out_mask;
+ step = 3 - dma.channels;
+
+ if (dma.samplebits == 16)
+ {
+ short *out = (short *) pbuf;
+ while (count--)
+ {
+ val = *p >> 8;
+ p+= step;
+ if (val > 0x7fff)
+ val = 0x7fff;
+ else if (val < (short)0x8000)
+ val = (short)0x8000;
+ out[out_idx] = val;
+ out_idx = (out_idx + 1) & out_mask;
+ }
+ }
+ else if (dma.samplebits == 8)
+ {
+ unsigned char *out = (unsigned char *) pbuf;
+ while (count--)
+ {
+ val = *p >> 8;
+ p+= step;
+ if (val > 0x7fff)
+ val = 0x7fff;
+ else if (val < (short)0x8000)
+ val = (short)0x8000;
+ out[out_idx] = (val>>8) + 128;
+ out_idx = (out_idx + 1) & out_mask;
+ }
+ }
+ }
+}
+
+
+/*
+===============================================================================
+
+CHANNEL MIXING
+
+===============================================================================
+*/
+
+void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime, int offset);
+void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime, int offset);
+
+void S_PaintChannels(int endtime)
+{
+ int i;
+ int end;
+ channel_t *ch;
+ sfxcache_t *sc;
+ int ltime, count;
+ playsound_t *ps;
+
+ snd_vol = s_volume->value*256;
+
+//Com_Printf ("%i to %i\n", paintedtime, endtime);
+ while (paintedtime < endtime)
+ {
+ // if paintbuffer is smaller than DMA buffer
+ end = endtime;
+ if (endtime - paintedtime > PAINTBUFFER_SIZE)
+ end = paintedtime + PAINTBUFFER_SIZE;
+
+ // start any playsounds
+ while (1)
+ {
+ ps = s_pendingplays.next;
+ if (ps == &s_pendingplays)
+ break; // no more pending sounds
+ if (ps->begin <= paintedtime)
+ {
+ S_IssuePlaysound (ps);
+ continue;
+ }
+
+ if (ps->begin < end)
+ end = ps->begin; // stop here
+ break;
+ }
+
+ // clear the paint buffer
+ if (s_rawend < paintedtime)
+ {
+// Com_Printf ("clear\n");
+ memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t));
+ }
+ else
+ { // copy from the streaming sound source
+ int s;
+ int stop;
+
+ stop = (end < s_rawend) ? end : s_rawend;
+
+ for (i=paintedtime ; i<stop ; i++)
+ {
+ s = i&(MAX_RAW_SAMPLES-1);
+ paintbuffer[i-paintedtime] = s_rawsamples[s];
+ }
+// if (i != end)
+// Com_Printf ("partial stream\n");
+// else
+// Com_Printf ("full stream\n");
+ for ( ; i<end ; i++)
+ {
+ paintbuffer[i-paintedtime].left =
+ paintbuffer[i-paintedtime].right = 0;
+ }
+ }
+
+
+ // paint in the channels.
+ ch = channels;
+ for (i=0; i<MAX_CHANNELS ; i++, ch++)
+ {
+ ltime = paintedtime;
+
+ while (ltime < end)
+ {
+ if (!ch->sfx || (!ch->leftvol && !ch->rightvol) )
+ break;
+
+ // max painting is to the end of the buffer
+ count = end - ltime;
+
+ // might be stopped by running out of data
+ if (ch->end - ltime < count)
+ count = ch->end - ltime;
+
+ sc = S_LoadSound (ch->sfx);
+ if (!sc)
+ break;
+
+ if (count > 0 && ch->sfx)
+ {
+ if (sc->width == 1)// FIXME; 8 bit asm is wrong now
+ S_PaintChannelFrom8(ch, sc, count, ltime - paintedtime);
+ else
+ S_PaintChannelFrom16(ch, sc, count, ltime - paintedtime);
+
+ ltime += count;
+ }
+
+ // if at end of loop, restart
+ if (ltime >= ch->end)
+ {
+ if (ch->autosound)
+ { // autolooping sounds always go back to start
+ ch->pos = 0;
+ ch->end = ltime + sc->length;
+ }
+ else if (sc->loopstart >= 0)
+ {
+ ch->pos = sc->loopstart;
+ ch->end = ltime + sc->length - ch->pos;
+ }
+ else
+ { // channel just stopped
+ ch->sfx = NULL;
+ }
+ }
+ }
+
+ }
+
+ // transfer out according to DMA format
+ S_TransferPaintBuffer(end);
+ paintedtime = end;
+ }
+}
+
+void S_InitScaletable (void)
+{
+ int i, j;
+ int scale;
+
+ s_volume->modified = false;
+ for (i=0 ; i<32 ; i++)
+ {
+ scale = i * 8 * 256 * s_volume->value;
+ for (j=0 ; j<256 ; j++)
+ snd_scaletable[i][j] = ((signed char)j) * scale;
+ }
+}
+
+void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count, int offset)
+{
+ int data;
+ int *lscale, *rscale;
+ unsigned char *sfx;
+ int i;
+ portable_samplepair_t *samp;
+
+ if (ch->leftvol > 255)
+ ch->leftvol = 255;
+ if (ch->rightvol > 255)
+ ch->rightvol = 255;
+
+ lscale = snd_scaletable[ ch->leftvol >> 11];
+ rscale = snd_scaletable[ ch->rightvol >> 11];
+ sfx = (uchar *)sc->data + ch->pos;
+
+ samp = &paintbuffer[offset];
+
+ for (i=0 ; i<count ; i++, samp++)
+ {
+ data = sfx[i];
+ samp->left += lscale[data];
+ samp->right += rscale[data];
+ }
+
+ ch->pos += count;
+}
+
+void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count, int offset)
+{
+ int data;
+ int left, right;
+ int leftvol, rightvol;
+ signed short *sfx;
+ int i;
+ portable_samplepair_t *samp;
+
+ leftvol = ch->leftvol*snd_vol;
+ rightvol = ch->rightvol*snd_vol;
+ sfx = (signed short *)sc->data + ch->pos;
+
+ samp = &paintbuffer[offset];
+ for (i=0 ; i<count ; i++, samp++)
+ {
+ data = sfx[i];
+ left = (data * leftvol)>>8;
+ right = (data * rightvol)>>8;
+ samp->left += left;
+ samp->right += right;
+ }
+
+ ch->pos += count;
+}
--- /dev/null
+++ b/sv_ccmds.c
@@ -1,0 +1,1031 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/*
+===============================================================================
+
+OPERATOR CONSOLE ONLY COMMANDS
+
+These commands can only be entered from stdin or by a remote operator datagram
+===============================================================================
+*/
+
+/*
+====================
+SV_SetMaster_f
+
+Specify a list of master servers
+====================
+*/
+void SV_SetMaster_f (void)
+{
+ int i, slot;
+
+ // only dedicated servers send heartbeats
+ if (!dedicated->value)
+ {
+ Com_Printf ("Only dedicated servers use masters.\n");
+ return;
+ }
+
+ // make sure the server is listed public
+ Cvar_Set ("public", "1");
+
+ for (i=1 ; i<MAX_MASTERS ; i++)
+ memset (&master_adr[i], 0, sizeof(master_adr[i]));
+
+ slot = 1; // slot 0 will always contain the id master
+ for (i=1 ; i<Cmd_Argc() ; i++)
+ {
+ if (slot == MAX_MASTERS)
+ break;
+
+ if (!NET_StringToAdr (Cmd_Argv(i), &master_adr[i]))
+ {
+ Com_Printf ("Bad address: %s\n", Cmd_Argv(i));
+ continue;
+ }
+ if (master_adr[slot].port == 0)
+ master_adr[slot].port = BigShort (PORT_MASTER);
+
+ Com_Printf ("Master server at %s\n", NET_AdrToString (master_adr[slot]));
+
+ Com_Printf ("Sending a ping.\n");
+
+ Netchan_OutOfBandPrint (NS_SERVER, master_adr[slot], "ping");
+
+ slot++;
+ }
+
+ svs.last_heartbeat = -9999999;
+}
+
+
+
+/*
+==================
+SV_SetPlayer
+
+Sets sv_client and sv_player to the player with idnum Cmd_Argv(1)
+==================
+*/
+qboolean SV_SetPlayer (void)
+{
+ client_t *cl;
+ int i;
+ int idnum;
+ char *s;
+
+ if (Cmd_Argc() < 2)
+ return false;
+
+ s = Cmd_Argv(1);
+
+ // numeric values are just slot numbers
+ if (s[0] >= '0' && s[0] <= '9')
+ {
+ idnum = atoi(Cmd_Argv(1));
+ if (idnum < 0 || idnum >= maxclients->value)
+ {
+ Com_Printf ("Bad client slot: %i\n", idnum);
+ return false;
+ }
+
+ sv_client = &svs.clients[idnum];
+ sv_player = sv_client->edict;
+ if (!sv_client->state)
+ {
+ Com_Printf ("Client %i is not active\n", idnum);
+ return false;
+ }
+ return true;
+ }
+
+ // check for a name match
+ for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
+ {
+ if (!cl->state)
+ continue;
+ if (!strcmp(cl->name, s))
+ {
+ sv_client = cl;
+ sv_player = sv_client->edict;
+ return true;
+ }
+ }
+
+ Com_Printf ("Userid %s is not on the server\n", s);
+ return false;
+}
+
+
+/*
+===============================================================================
+
+SAVEGAME FILES
+
+===============================================================================
+*/
+
+/*
+=====================
+SV_WipeSavegame
+
+Delete save/<XXX>/
+=====================
+*/
+void SV_WipeSavegame (char *savename)
+{
+ char name[MAX_OSPATH];
+ char *s;
+
+ Com_DPrintf("SV_WipeSaveGame(%s)\n", savename);
+
+ Com_sprintf (name, sizeof(name), "%s/save/%s/server.ssv", FS_Gamedir (), savename);
+ remove (name);
+ Com_sprintf (name, sizeof(name), "%s/save/%s/game.ssv", FS_Gamedir (), savename);
+ remove (name);
+
+ Com_sprintf (name, sizeof(name), "%s/save/%s/*.sav", FS_Gamedir (), savename);
+ s = Sys_FindFirst( name, 0, 0 );
+ while (s)
+ {
+ remove (s);
+ s = Sys_FindNext( 0, 0 );
+ }
+ Sys_FindClose ();
+ Com_sprintf (name, sizeof(name), "%s/save/%s/*.sv2", FS_Gamedir (), savename);
+ s = Sys_FindFirst(name, 0, 0 );
+ while (s)
+ {
+ remove (s);
+ s = Sys_FindNext( 0, 0 );
+ }
+ Sys_FindClose ();
+}
+
+
+/*
+================
+CopyFile
+================
+*/
+void CopyFile (char *src, char *dst)
+{
+ FILE *f1, *f2;
+ int l;
+ byte buffer[65536];
+
+ Com_DPrintf ("CopyFile (%s, %s)\n", src, dst);
+
+ f1 = fopen (src, "rb");
+ if (!f1)
+ return;
+ f2 = fopen (dst, "wb");
+ if (!f2)
+ {
+ fclose (f1);
+ return;
+ }
+
+ while (1)
+ {
+ l = fread (buffer, 1, sizeof(buffer), f1);
+ if (!l)
+ break;
+ fwrite (buffer, 1, l, f2);
+ }
+
+ fclose (f1);
+ fclose (f2);
+}
+
+
+/*
+================
+SV_CopySaveGame
+================
+*/
+void SV_CopySaveGame (char *src, char *dst)
+{
+ char name[MAX_OSPATH], name2[MAX_OSPATH];
+ int l, len;
+ char *found;
+
+ Com_DPrintf("SV_CopySaveGame(%s, %s)\n", src, dst);
+
+ SV_WipeSavegame (dst);
+
+ // copy the savegame over
+ Com_sprintf (name, sizeof(name), "%s/save/%s/server.ssv", FS_Gamedir(), src);
+ Com_sprintf (name2, sizeof(name2), "%s/save/%s/server.ssv", FS_Gamedir(), dst);
+ FS_CreatePath (name2);
+ CopyFile (name, name2);
+
+ Com_sprintf (name, sizeof(name), "%s/save/%s/game.ssv", FS_Gamedir(), src);
+ Com_sprintf (name2, sizeof(name2), "%s/save/%s/game.ssv", FS_Gamedir(), dst);
+ CopyFile (name, name2);
+
+ Com_sprintf (name, sizeof(name), "%s/save/%s/", FS_Gamedir(), src);
+ len = strlen(name);
+ Com_sprintf (name, sizeof(name), "%s/save/%s/*.sav", FS_Gamedir(), src);
+ found = Sys_FindFirst(name, 0, 0 );
+ while (found)
+ {
+ strcpy (name+len, found+len);
+
+ Com_sprintf (name2, sizeof(name2), "%s/save/%s/%s", FS_Gamedir(), dst, found+len);
+ CopyFile (name, name2);
+
+ // change sav to sv2
+ l = strlen(name);
+ strcpy (name+l-3, "sv2");
+ l = strlen(name2);
+ strcpy (name2+l-3, "sv2");
+ CopyFile (name, name2);
+
+ found = Sys_FindNext( 0, 0 );
+ }
+ Sys_FindClose ();
+}
+
+
+/*
+==============
+SV_WriteLevelFile
+
+==============
+*/
+void SV_WriteLevelFile (void)
+{
+ char name[MAX_OSPATH];
+ FILE *f;
+
+ Com_DPrintf("SV_WriteLevelFile()\n");
+
+ Com_sprintf (name, sizeof(name), "%s/save/current/%s.sv2", FS_Gamedir(), sv.name);
+ f = fopen(name, "wb");
+ if (!f)
+ {
+ Com_Printf ("Failed to open %s\n", name);
+ return;
+ }
+ fwrite (sv.configstrings, sizeof(sv.configstrings), 1, f);
+ CM_WritePortalState (f);
+ fclose (f);
+
+ Com_sprintf (name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name);
+ ge->WriteLevel (name);
+}
+
+/*
+==============
+SV_ReadLevelFile
+
+==============
+*/
+void SV_ReadLevelFile (void)
+{
+ char name[MAX_OSPATH];
+ FILE *f;
+
+ Com_DPrintf("SV_ReadLevelFile()\n");
+
+ Com_sprintf (name, sizeof(name), "%s/save/current/%s.sv2", FS_Gamedir(), sv.name);
+ f = fopen(name, "rb");
+ if (!f)
+ {
+ Com_Printf ("Failed to open %s\n", name);
+ return;
+ }
+ FS_Read (sv.configstrings, sizeof(sv.configstrings), f);
+ CM_ReadPortalState (f);
+ fclose (f);
+
+ Com_sprintf (name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name);
+ ge->ReadLevel (name);
+}
+
+/*
+==============
+SV_WriteServerFile
+
+==============
+*/
+void SV_WriteServerFile (qboolean autosave)
+{
+ FILE *f;
+ cvar_t *var;
+ char name[MAX_OSPATH], string[128];
+ char comment[32];
+ Tm *newtime;
+
+ Com_DPrintf("SV_WriteServerFile(%s)\n", autosave ? "true" : "false");
+
+ Com_sprintf (name, sizeof(name), "%s/save/current/server.ssv", FS_Gamedir());
+ f = fopen (name, "wb");
+ if (!f)
+ {
+ Com_Printf ("Couldn't write %s\n", name);
+ return;
+ }
+ // write the comment field
+ memset (comment, 0, sizeof(comment));
+
+ if (!autosave)
+ {
+ newtime = localtime (time(nil));
+ Com_sprintf (comment,sizeof(comment), "%2i:%i%i %2i/%2i ", newtime->hour
+ , newtime->min/10, newtime->min%10, newtime->mon+1, newtime->mday);
+ strncat (comment, sv.configstrings[CS_NAME], sizeof(comment)-1-strlen(comment) );
+ }
+ else
+ { // autosaved
+ Com_sprintf (comment, sizeof(comment), "ENTERING %s", sv.configstrings[CS_NAME]);
+ }
+
+ fwrite (comment, 1, sizeof(comment), f);
+
+ // write the mapcmd
+ fwrite (svs.mapcmd, 1, sizeof(svs.mapcmd), f);
+
+ // write all CVAR_LATCH cvars
+ // these will be things like coop, skill, deathmatch, etc
+ for (var = cvar_vars ; var ; var=var->next)
+ {
+ if (!(var->flags & CVAR_LATCH))
+ continue;
+ if (strlen(var->name) >= sizeof(name)-1
+ || strlen(var->string) >= sizeof(string)-1)
+ {
+ Com_Printf ("Cvar too long: %s = %s\n", var->name, var->string);
+ continue;
+ }
+ memset (name, 0, sizeof(name));
+ memset (string, 0, sizeof(string));
+ strcpy (name, var->name);
+ strcpy (string, var->string);
+ fwrite (name, 1, sizeof(name), f);
+ fwrite (string, 1, sizeof(string), f);
+ }
+
+ fclose (f);
+
+ // write game state
+ Com_sprintf (name, sizeof(name), "%s/save/current/game.ssv", FS_Gamedir());
+ ge->WriteGame (name, autosave);
+}
+
+/*
+==============
+SV_ReadServerFile
+
+==============
+*/
+void SV_ReadServerFile (void)
+{
+ FILE *f;
+ char name[MAX_OSPATH], string[128];
+ char comment[32];
+ char mapcmd[MAX_TOKEN_CHARS];
+
+ Com_DPrintf("SV_ReadServerFile()\n");
+
+ Com_sprintf (name, sizeof(name), "%s/save/current/server.ssv", FS_Gamedir());
+ f = fopen (name, "rb");
+ if (!f)
+ {
+ Com_Printf ("Couldn't read %s\n", name);
+ return;
+ }
+ // read the comment field
+ FS_Read (comment, sizeof(comment), f);
+
+ // read the mapcmd
+ FS_Read (mapcmd, sizeof(mapcmd), f);
+
+ // read all CVAR_LATCH cvars
+ // these will be things like coop, skill, deathmatch, etc
+ while (1)
+ {
+ if (!fread (name, 1, sizeof(name), f))
+ break;
+ FS_Read (string, sizeof(string), f);
+ Com_DPrintf ("Set %s = %s\n", name, string);
+ Cvar_ForceSet (name, string);
+ }
+
+ fclose (f);
+
+ // start a new game fresh with new cvars
+ SV_InitGame ();
+
+ strcpy (svs.mapcmd, mapcmd);
+
+ // read game state
+ Com_sprintf (name, sizeof(name), "%s/save/current/game.ssv", FS_Gamedir());
+ ge->ReadGame (name);
+}
+
+
+//=========================================================
+
+
+
+
+/*
+==================
+SV_DemoMap_f
+
+Puts the server in demo mode on a specific map/cinematic
+==================
+*/
+void SV_DemoMap_f (void)
+{
+ SV_Map (true, Cmd_Argv(1), false );
+}
+
+/*
+==================
+SV_GameMap_f
+
+Saves the state of the map just being exited and goes to a new map.
+
+If the initial character of the map string is '*', the next map is
+in a new unit, so the current savegame directory is cleared of
+map files.
+
+Example:
+
+*inter.cin+jail
+
+Clears the archived maps, plays the inter.cin cinematic, then
+goes to map jail.bsp.
+==================
+*/
+void SV_GameMap_f (void)
+{
+ char *map;
+ int i;
+ client_t *cl;
+ qboolean *savedInuse;
+
+ if (Cmd_Argc() != 2)
+ {
+ Com_Printf ("USAGE: gamemap <map>\n");
+ return;
+ }
+
+ Com_DPrintf("SV_GameMap(%s)\n", Cmd_Argv(1));
+
+ FS_CreatePath (va("%s/save/current/", FS_Gamedir()));
+
+ // check for clearing the current savegame
+ map = Cmd_Argv(1);
+ if (map[0] == '*')
+ {
+ // wipe all the *.sav files
+ SV_WipeSavegame ("current");
+ }
+ else
+ { // save the map just exited
+ if (sv.state == ss_game)
+ {
+ // clear all the client inuse flags before saving so that
+ // when the level is re-entered, the clients will spawn
+ // at spawn points instead of occupying body shells
+ savedInuse = malloc(maxclients->value * sizeof(qboolean));
+ for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
+ {
+ savedInuse[i] = cl->edict->inuse;
+ cl->edict->inuse = false;
+ }
+
+ SV_WriteLevelFile ();
+
+ // we must restore these for clients to transfer over correctly
+ for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
+ cl->edict->inuse = savedInuse[i];
+ free (savedInuse);
+ }
+ }
+
+ // start up the next map
+ SV_Map (false, Cmd_Argv(1), false );
+
+ // archive server state
+ strncpy (svs.mapcmd, Cmd_Argv(1), sizeof(svs.mapcmd)-1);
+
+ // copy off the level to the autosave slot
+ if (!dedicated->value)
+ {
+ SV_WriteServerFile (true);
+ SV_CopySaveGame ("current", "save0");
+ }
+}
+
+/*
+==================
+SV_Map_f
+
+Goes directly to a given map without any savegame archiving.
+For development work
+==================
+*/
+void SV_Map_f (void)
+{
+ char *map;
+ char expanded[MAX_QPATH];
+
+ // if not a pcx, demo, or cinematic, check to make sure the level exists
+ map = Cmd_Argv(1);
+ if (!strstr (map, "."))
+ {
+ Com_sprintf (expanded, sizeof(expanded), "maps/%s.bsp", map);
+ if (FS_LoadFile (expanded, NULL) == -1)
+ {
+ Com_Printf ("Can't find %s\n", expanded);
+ return;
+ }
+ }
+
+ sv.state = ss_dead; // don't save current level when changing
+ SV_WipeSavegame("current");
+ SV_GameMap_f ();
+}
+
+/*
+=====================================================================
+
+ SAVEGAMES
+
+=====================================================================
+*/
+
+
+/*
+==============
+SV_Loadgame_f
+
+==============
+*/
+void SV_Loadgame_f (void)
+{
+ char name[MAX_OSPATH];
+ FILE *f;
+ char *dir;
+
+ if (Cmd_Argc() != 2)
+ {
+ Com_Printf ("USAGE: loadgame <directory>\n");
+ return;
+ }
+
+ Com_Printf ("Loading game...\n");
+
+ dir = Cmd_Argv(1);
+ if (strstr (dir, "..") || strstr (dir, "/") || strstr (dir, "\\") )
+ {
+ Com_Printf ("Bad savedir.\n");
+ }
+
+ // make sure the server.ssv file exists
+ Com_sprintf (name, sizeof(name), "%s/save/%s/server.ssv", FS_Gamedir(), Cmd_Argv(1));
+ f = fopen (name, "rb");
+ if (!f)
+ {
+ Com_Printf ("No such savegame: %s\n", name);
+ return;
+ }
+ fclose (f);
+
+ SV_CopySaveGame (Cmd_Argv(1), "current");
+
+ SV_ReadServerFile ();
+
+ // go to the map
+ sv.state = ss_dead; // don't save current level when changing
+ SV_Map (false, svs.mapcmd, true);
+}
+
+
+
+/*
+==============
+SV_Savegame_f
+
+==============
+*/
+void SV_Savegame_f (void)
+{
+ char *dir;
+
+ if (sv.state != ss_game)
+ {
+ Com_Printf ("You must be in a game to save.\n");
+ return;
+ }
+
+ if (Cmd_Argc() != 2)
+ {
+ Com_Printf ("USAGE: savegame <directory>\n");
+ return;
+ }
+
+ if (Cvar_VariableValue("deathmatch"))
+ {
+ Com_Printf ("Can't savegame in a deathmatch\n");
+ return;
+ }
+
+ if (!strcmp (Cmd_Argv(1), "current"))
+ {
+ Com_Printf ("Can't save to 'current'\n");
+ return;
+ }
+
+ if (maxclients->value == 1 && svs.clients[0].edict->client->ps.stats[STAT_HEALTH] <= 0)
+ {
+ Com_Printf ("\nCan't savegame while dead!\n");
+ return;
+ }
+
+ dir = Cmd_Argv(1);
+ if (strstr (dir, "..") || strstr (dir, "/") || strstr (dir, "\\") )
+ {
+ Com_Printf ("Bad savedir.\n");
+ }
+
+ Com_Printf ("Saving game...\n");
+
+ // archive current level, including all client edicts.
+ // when the level is reloaded, they will be shells awaiting
+ // a connecting client
+ SV_WriteLevelFile ();
+
+ // save server state
+ SV_WriteServerFile (false);
+
+ // copy it off
+ SV_CopySaveGame ("current", dir);
+
+ Com_Printf ("Done.\n");
+}
+
+//===============================================================
+
+/*
+==================
+SV_Kick_f
+
+Kick a user off of the server
+==================
+*/
+void SV_Kick_f (void)
+{
+ if (!svs.initialized)
+ {
+ Com_Printf ("No server running.\n");
+ return;
+ }
+
+ if (Cmd_Argc() != 2)
+ {
+ Com_Printf ("Usage: kick <userid>\n");
+ return;
+ }
+
+ if (!SV_SetPlayer ())
+ return;
+
+ SV_BroadcastPrintf (PRINT_HIGH, "%s was kicked\n", sv_client->name);
+ // print directly, because the dropped client won't get the
+ // SV_BroadcastPrintf message
+ SV_ClientPrintf (sv_client, PRINT_HIGH, "You were kicked from the game\n");
+ SV_DropClient (sv_client);
+ sv_client->lastmessage = svs.realtime; // min case there is a funny zombie
+}
+
+
+/*
+================
+SV_Status_f
+================
+*/
+void SV_Status_f (void)
+{
+ int i, j, l;
+ client_t *cl;
+ char *s;
+ int ping;
+ if (!svs.clients)
+ {
+ Com_Printf ("No server running.\n");
+ return;
+ }
+ Com_Printf ("map : %s\n", sv.name);
+
+ Com_Printf ("num score ping name lastmsg address qport \n");
+ Com_Printf ("--- ----- ---- --------------- ------- --------------------- ------\n");
+ for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
+ {
+ if (!cl->state)
+ continue;
+ Com_Printf ("%3i ", i);
+ Com_Printf ("%5i ", cl->edict->client->ps.stats[STAT_FRAGS]);
+
+ if (cl->state == cs_connected)
+ Com_Printf ("CNCT ");
+ else if (cl->state == cs_zombie)
+ Com_Printf ("ZMBI ");
+ else
+ {
+ ping = cl->ping < 9999 ? cl->ping : 9999;
+ Com_Printf ("%4i ", ping);
+ }
+
+ Com_Printf ("%s", cl->name);
+ l = 16 - strlen(cl->name);
+ for (j=0 ; j<l ; j++)
+ Com_Printf (" ");
+
+ Com_Printf ("%7i ", svs.realtime - cl->lastmessage );
+
+ s = NET_AdrToString ( cl->netchan.remote_address);
+ Com_Printf ("%s", s);
+ l = 22 - strlen(s);
+ for (j=0 ; j<l ; j++)
+ Com_Printf (" ");
+
+ Com_Printf ("%5i", cl->netchan.qport);
+
+ Com_Printf ("\n");
+ }
+ Com_Printf ("\n");
+}
+
+/*
+==================
+SV_ConSay_f
+==================
+*/
+void SV_ConSay_f(void)
+{
+ client_t *client;
+ int j;
+ char *p;
+ char text[1024];
+
+ if (Cmd_Argc () < 2)
+ return;
+
+ strcpy (text, "console: ");
+ p = Cmd_Args();
+
+ if (*p == '"')
+ {
+ p++;
+ p[strlen(p)-1] = 0;
+ }
+
+ strcat(text, p);
+
+ for (j = 0, client = svs.clients; j < maxclients->value; j++, client++)
+ {
+ if (client->state != cs_spawned)
+ continue;
+ SV_ClientPrintf(client, PRINT_CHAT, "%s\n", text);
+ }
+}
+
+
+/*
+==================
+SV_Heartbeat_f
+==================
+*/
+void SV_Heartbeat_f (void)
+{
+ svs.last_heartbeat = -9999999;
+}
+
+
+/*
+===========
+SV_Serverinfo_f
+
+ Examine or change the serverinfo string
+===========
+*/
+void SV_Serverinfo_f (void)
+{
+ Com_Printf ("Server info settings:\n");
+ Info_Print (Cvar_Serverinfo());
+}
+
+
+/*
+===========
+SV_DumpUser_f
+
+Examine all a users info strings
+===========
+*/
+void SV_DumpUser_f (void)
+{
+ if (Cmd_Argc() != 2)
+ {
+ Com_Printf ("Usage: info <userid>\n");
+ return;
+ }
+
+ if (!SV_SetPlayer ())
+ return;
+
+ Com_Printf ("userinfo\n");
+ Com_Printf ("--------\n");
+ Info_Print (sv_client->userinfo);
+
+}
+
+
+/*
+==============
+SV_ServerRecord_f
+
+Begins server demo recording. Every entity and every message will be
+recorded, but no playerinfo will be stored. Primarily for demo merging.
+==============
+*/
+void SV_ServerRecord_f (void)
+{
+ char name[MAX_OSPATH];
+ char buf_data[32768];
+ sizebuf_t buf;
+ int len;
+ int i;
+
+ if (Cmd_Argc() != 2)
+ {
+ Com_Printf ("serverrecord <demoname>\n");
+ return;
+ }
+
+ if (svs.demofile)
+ {
+ Com_Printf ("Already recording.\n");
+ return;
+ }
+
+ if (sv.state != ss_game)
+ {
+ Com_Printf ("You must be in a level to record.\n");
+ return;
+ }
+
+ //
+ // open the demo file
+ //
+ Com_sprintf (name, sizeof(name), "%s/demos/%s.dm2", FS_Gamedir(), Cmd_Argv(1));
+
+ Com_Printf ("recording to %s.\n", name);
+ FS_CreatePath (name);
+ svs.demofile = fopen (name, "wb");
+ if (!svs.demofile)
+ {
+ Com_Printf ("ERROR: couldn't open.\n");
+ return;
+ }
+
+ // setup a buffer to catch all multicasts
+ SZ_Init (&svs.demo_multicast, svs.demo_multicast_buf, sizeof(svs.demo_multicast_buf));
+
+ //
+ // write a single giant fake message with all the startup info
+ //
+ SZ_Init (&buf, (byte *)buf_data, sizeof(buf_data));
+
+ //
+ // serverdata needs to go over for all types of servers
+ // to make sure the protocol is right, and to set the gamedir
+ //
+ // send the serverdata
+ MSG_WriteByte (&buf, svc_serverdata);
+ MSG_WriteLong (&buf, PROTOCOL_VERSION);
+ MSG_WriteLong (&buf, svs.spawncount);
+ // 2 means server demo
+ MSG_WriteByte (&buf, 2); // demos are always attract loops
+ MSG_WriteString (&buf, Cvar_VariableString ("gamedir"));
+ MSG_WriteShort (&buf, -1);
+ // send full levelname
+ MSG_WriteString (&buf, sv.configstrings[CS_NAME]);
+
+ for (i=0 ; i<MAX_CONFIGSTRINGS ; i++)
+ if (sv.configstrings[i][0])
+ {
+ MSG_WriteByte (&buf, svc_configstring);
+ MSG_WriteShort (&buf, i);
+ MSG_WriteString (&buf, sv.configstrings[i]);
+ }
+
+ // write it to the demo file
+ Com_DPrintf ("signon message length: %i\n", buf.cursize);
+ len = LittleLong (buf.cursize);
+ fwrite (&len, 4, 1, svs.demofile);
+ fwrite (buf.data, buf.cursize, 1, svs.demofile);
+
+ // the rest of the demo file will be individual frames
+}
+
+
+/*
+==============
+SV_ServerStop_f
+
+Ends server demo recording
+==============
+*/
+void SV_ServerStop_f (void)
+{
+ if (!svs.demofile)
+ {
+ Com_Printf ("Not doing a serverrecord.\n");
+ return;
+ }
+ fclose (svs.demofile);
+ svs.demofile = NULL;
+ Com_Printf ("Recording completed.\n");
+}
+
+
+/*
+===============
+SV_KillServer_f
+
+Kick everyone off, possibly in preparation for a new game
+
+===============
+*/
+void SV_KillServer_f (void)
+{
+ if (!svs.initialized)
+ return;
+ SV_Shutdown ("Server was killed.\n", false);
+ NET_Config ( false ); // close network sockets
+}
+
+/*
+===============
+SV_ServerCommand_f
+
+Let the game dll handle a command
+===============
+*/
+void SV_ServerCommand_f (void)
+{
+ if (!ge)
+ {
+ Com_Printf ("No game loaded.\n");
+ return;
+ }
+
+ ge->ServerCommand();
+}
+
+//===========================================================
+
+/*
+==================
+SV_InitOperatorCommands
+==================
+*/
+void SV_InitOperatorCommands (void)
+{
+ Cmd_AddCommand ("heartbeat", SV_Heartbeat_f);
+ Cmd_AddCommand ("kick", SV_Kick_f);
+ Cmd_AddCommand ("status", SV_Status_f);
+ Cmd_AddCommand ("serverinfo", SV_Serverinfo_f);
+ Cmd_AddCommand ("dumpuser", SV_DumpUser_f);
+
+ Cmd_AddCommand ("map", SV_Map_f);
+ Cmd_AddCommand ("demomap", SV_DemoMap_f);
+ Cmd_AddCommand ("gamemap", SV_GameMap_f);
+ Cmd_AddCommand ("setmaster", SV_SetMaster_f);
+
+ if ( dedicated->value )
+ Cmd_AddCommand ("say", SV_ConSay_f);
+
+ Cmd_AddCommand ("serverrecord", SV_ServerRecord_f);
+ Cmd_AddCommand ("serverstop", SV_ServerStop_f);
+
+ Cmd_AddCommand ("save", SV_Savegame_f);
+ Cmd_AddCommand ("load", SV_Loadgame_f);
+
+ Cmd_AddCommand ("killserver", SV_KillServer_f);
+
+ Cmd_AddCommand ("sv", SV_ServerCommand_f);
+}
+
--- /dev/null
+++ b/sv_ents.c
@@ -1,0 +1,709 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/*
+=============================================================================
+
+Encode a client frame onto the network channel
+
+=============================================================================
+*/
+
+/* commented out in release
+
+// because there can be a lot of projectiles, there is a special
+// network protocol for them
+#define MAX_PROJECTILES 64
+edict_t *projectiles[MAX_PROJECTILES];
+int numprojs;
+cvar_t *sv_projectiles;
+
+qboolean SV_AddProjectileUpdate (edict_t *ent)
+{
+ if (!sv_projectiles)
+ sv_projectiles = Cvar_Get("sv_projectiles", "1", 0);
+
+ if (!sv_projectiles->value)
+ return false;
+
+ if (!(ent->svflags & SVF_PROJECTILE))
+ return false;
+ if (numprojs == MAX_PROJECTILES)
+ return true;
+
+ projectiles[numprojs++] = ent;
+ return true;
+}
+
+void SV_EmitProjectileUpdate (sizebuf_t *msg)
+{
+ byte bits[16]; // [modelindex] [48 bits] xyz p y 12 12 12 8 8 [entitynum] [e2]
+ int n, i;
+ edict_t *ent;
+ int x, y, z, p, yaw;
+ int len;
+
+ if (!numprojs)
+ return;
+
+ MSG_WriteByte (msg, numprojs);
+
+ for (n=0 ; n<numprojs ; n++)
+ {
+ ent = projectiles[n];
+ x = (int)(ent->s.origin[0]+4096)>>1;
+ y = (int)(ent->s.origin[1]+4096)>>1;
+ z = (int)(ent->s.origin[2]+4096)>>1;
+ p = (int)(256*ent->s.angles[0]/360)&255;
+ yaw = (int)(256*ent->s.angles[1]/360)&255;
+
+ len = 0;
+ bits[len++] = x;
+ bits[len++] = (x>>8) | (y<<4);
+ bits[len++] = (y>>4);
+ bits[len++] = z;
+ bits[len++] = (z>>8);
+ if (ent->s.effects & EF_BLASTER)
+ bits[len-1] |= 64;
+
+ if (ent->s.old_origin[0] != ent->s.origin[0] ||
+ ent->s.old_origin[1] != ent->s.origin[1] ||
+ ent->s.old_origin[2] != ent->s.origin[2]) {
+ bits[len-1] |= 128;
+ x = (int)(ent->s.old_origin[0]+4096)>>1;
+ y = (int)(ent->s.old_origin[1]+4096)>>1;
+ z = (int)(ent->s.old_origin[2]+4096)>>1;
+ bits[len++] = x;
+ bits[len++] = (x>>8) | (y<<4);
+ bits[len++] = (y>>4);
+ bits[len++] = z;
+ bits[len++] = (z>>8);
+ }
+
+ bits[len++] = p;
+ bits[len++] = yaw;
+ bits[len++] = ent->s.modelindex;
+
+ bits[len++] = (ent->s.number & 0x7f);
+ if (ent->s.number > 255) {
+ bits[len-1] |= 128;
+ bits[len++] = (ent->s.number >> 7);
+ }
+
+ for (i=0 ; i<len ; i++)
+ MSG_WriteByte (msg, bits[i]);
+ }
+}
+*/
+
+/*
+=============
+SV_EmitPacketEntities
+
+Writes a delta update of an entity_state_t list to the message.
+=============
+*/
+void SV_EmitPacketEntities (client_frame_t *from, client_frame_t *to, sizebuf_t *msg)
+{
+ entity_state_t *oldent = nil, *newent = nil;
+ int oldindex, newindex;
+ int oldnum, newnum;
+ int from_num_entities;
+ int bits;
+
+/*
+ if (numprojs)
+ MSG_WriteByte (msg, svc_packetentities2);
+ else
+*/
+ MSG_WriteByte (msg, svc_packetentities);
+
+ if (!from)
+ from_num_entities = 0;
+ else
+ from_num_entities = from->num_entities;
+
+ newindex = 0;
+ oldindex = 0;
+ while (newindex < to->num_entities || oldindex < from_num_entities)
+ {
+ if (newindex >= to->num_entities)
+ newnum = 9999;
+ else
+ {
+ newent = &svs.client_entities[(to->first_entity+newindex)%svs.num_client_entities];
+ newnum = newent->number;
+ }
+
+ if (oldindex >= from_num_entities)
+ oldnum = 9999;
+ else
+ {
+ oldent = &svs.client_entities[(from->first_entity+oldindex)%svs.num_client_entities];
+ oldnum = oldent->number;
+ }
+
+ if (newnum == oldnum)
+ { // delta update from old position
+ // because the force parm is false, this will not result
+ // in any bytes being emited if the entity has not changed at all
+ // note that players are always 'newentities', this updates their oldorigin always
+ // and prevents warping
+ MSG_WriteDeltaEntity (oldent, newent, msg, false, newent->number <= maxclients->value);
+ oldindex++;
+ newindex++;
+ continue;
+ }
+
+ if (newnum < oldnum)
+ { // this is a new entity, send it from the baseline
+ MSG_WriteDeltaEntity (&sv.baselines[newnum], newent, msg, true, true);
+ newindex++;
+ continue;
+ }
+
+ if (newnum > oldnum)
+ { // the old entity isn't present in the new message
+ bits = U_REMOVE;
+ if (oldnum >= 256)
+ bits |= U_NUMBER16 | U_MOREBITS1;
+
+ MSG_WriteByte (msg, bits&255 );
+ if (bits & 0x0000ff00)
+ MSG_WriteByte (msg, (bits>>8)&255 );
+
+ if (bits & U_NUMBER16)
+ MSG_WriteShort (msg, oldnum);
+ else
+ MSG_WriteByte (msg, oldnum);
+
+ oldindex++;
+ continue;
+ }
+ }
+
+ MSG_WriteShort (msg, 0); // end of packetentities
+
+/*
+ if (numprojs)
+ SV_EmitProjectileUpdate(msg);
+*/
+}
+
+
+
+/*
+=============
+SV_WritePlayerstateToClient
+
+=============
+*/
+void SV_WritePlayerstateToClient (client_frame_t *from, client_frame_t *to, sizebuf_t *msg)
+{
+ int i;
+ int pflags;
+ player_state_t *ps, *ops;
+ player_state_t dummy;
+ int statbits;
+
+ ps = &to->ps;
+ if (!from)
+ {
+ memset (&dummy, 0, sizeof(dummy));
+ ops = &dummy;
+ }
+ else
+ ops = &from->ps;
+
+ //
+ // determine what needs to be sent
+ //
+ pflags = 0;
+
+ if (ps->pmove.pm_type != ops->pmove.pm_type)
+ pflags |= PS_M_TYPE;
+
+ if (ps->pmove.origin[0] != ops->pmove.origin[0]
+ || ps->pmove.origin[1] != ops->pmove.origin[1]
+ || ps->pmove.origin[2] != ops->pmove.origin[2] )
+ pflags |= PS_M_ORIGIN;
+
+ if (ps->pmove.velocity[0] != ops->pmove.velocity[0]
+ || ps->pmove.velocity[1] != ops->pmove.velocity[1]
+ || ps->pmove.velocity[2] != ops->pmove.velocity[2] )
+ pflags |= PS_M_VELOCITY;
+
+ if (ps->pmove.pm_time != ops->pmove.pm_time)
+ pflags |= PS_M_TIME;
+
+ if (ps->pmove.pm_flags != ops->pmove.pm_flags)
+ pflags |= PS_M_FLAGS;
+
+ if (ps->pmove.gravity != ops->pmove.gravity)
+ pflags |= PS_M_GRAVITY;
+
+ if (ps->pmove.delta_angles[0] != ops->pmove.delta_angles[0]
+ || ps->pmove.delta_angles[1] != ops->pmove.delta_angles[1]
+ || ps->pmove.delta_angles[2] != ops->pmove.delta_angles[2] )
+ pflags |= PS_M_DELTA_ANGLES;
+
+
+ if (ps->viewoffset[0] != ops->viewoffset[0]
+ || ps->viewoffset[1] != ops->viewoffset[1]
+ || ps->viewoffset[2] != ops->viewoffset[2] )
+ pflags |= PS_VIEWOFFSET;
+
+ if (ps->viewangles[0] != ops->viewangles[0]
+ || ps->viewangles[1] != ops->viewangles[1]
+ || ps->viewangles[2] != ops->viewangles[2] )
+ pflags |= PS_VIEWANGLES;
+
+ if (ps->kick_angles[0] != ops->kick_angles[0]
+ || ps->kick_angles[1] != ops->kick_angles[1]
+ || ps->kick_angles[2] != ops->kick_angles[2] )
+ pflags |= PS_KICKANGLES;
+
+ if (ps->blend[0] != ops->blend[0]
+ || ps->blend[1] != ops->blend[1]
+ || ps->blend[2] != ops->blend[2]
+ || ps->blend[3] != ops->blend[3] )
+ pflags |= PS_BLEND;
+
+ if (ps->fov != ops->fov)
+ pflags |= PS_FOV;
+
+ if (ps->rdflags != ops->rdflags)
+ pflags |= PS_RDFLAGS;
+
+ if (ps->gunframe != ops->gunframe)
+ pflags |= PS_WEAPONFRAME;
+
+ pflags |= PS_WEAPONINDEX;
+
+ //
+ // write it
+ //
+ MSG_WriteByte (msg, svc_playerinfo);
+ MSG_WriteShort (msg, pflags);
+
+ //
+ // write the pmove_state_t
+ //
+ if (pflags & PS_M_TYPE)
+ MSG_WriteByte (msg, ps->pmove.pm_type);
+
+ if (pflags & PS_M_ORIGIN)
+ {
+ MSG_WriteShort (msg, ps->pmove.origin[0]);
+ MSG_WriteShort (msg, ps->pmove.origin[1]);
+ MSG_WriteShort (msg, ps->pmove.origin[2]);
+ }
+
+ if (pflags & PS_M_VELOCITY)
+ {
+ MSG_WriteShort (msg, ps->pmove.velocity[0]);
+ MSG_WriteShort (msg, ps->pmove.velocity[1]);
+ MSG_WriteShort (msg, ps->pmove.velocity[2]);
+ }
+
+ if (pflags & PS_M_TIME)
+ MSG_WriteByte (msg, ps->pmove.pm_time);
+
+ if (pflags & PS_M_FLAGS)
+ MSG_WriteByte (msg, ps->pmove.pm_flags);
+
+ if (pflags & PS_M_GRAVITY)
+ MSG_WriteShort (msg, ps->pmove.gravity);
+
+ if (pflags & PS_M_DELTA_ANGLES)
+ {
+ MSG_WriteShort (msg, ps->pmove.delta_angles[0]);
+ MSG_WriteShort (msg, ps->pmove.delta_angles[1]);
+ MSG_WriteShort (msg, ps->pmove.delta_angles[2]);
+ }
+
+ //
+ // write the rest of the player_state_t
+ //
+ if (pflags & PS_VIEWOFFSET)
+ {
+ MSG_WriteChar (msg, ps->viewoffset[0]*4);
+ MSG_WriteChar (msg, ps->viewoffset[1]*4);
+ MSG_WriteChar (msg, ps->viewoffset[2]*4);
+ }
+
+ if (pflags & PS_VIEWANGLES)
+ {
+ MSG_WriteAngle16 (msg, ps->viewangles[0]);
+ MSG_WriteAngle16 (msg, ps->viewangles[1]);
+ MSG_WriteAngle16 (msg, ps->viewangles[2]);
+ }
+
+ if (pflags & PS_KICKANGLES)
+ {
+ MSG_WriteChar (msg, ps->kick_angles[0]*4);
+ MSG_WriteChar (msg, ps->kick_angles[1]*4);
+ MSG_WriteChar (msg, ps->kick_angles[2]*4);
+ }
+
+ if (pflags & PS_WEAPONINDEX)
+ {
+ MSG_WriteByte (msg, ps->gunindex);
+ }
+
+ if (pflags & PS_WEAPONFRAME)
+ {
+ MSG_WriteByte (msg, ps->gunframe);
+ MSG_WriteChar (msg, ps->gunoffset[0]*4);
+ MSG_WriteChar (msg, ps->gunoffset[1]*4);
+ MSG_WriteChar (msg, ps->gunoffset[2]*4);
+ MSG_WriteChar (msg, ps->gunangles[0]*4);
+ MSG_WriteChar (msg, ps->gunangles[1]*4);
+ MSG_WriteChar (msg, ps->gunangles[2]*4);
+ }
+
+ if (pflags & PS_BLEND)
+ {
+ MSG_WriteByte (msg, ps->blend[0]*255);
+ MSG_WriteByte (msg, ps->blend[1]*255);
+ MSG_WriteByte (msg, ps->blend[2]*255);
+ MSG_WriteByte (msg, ps->blend[3]*255);
+ }
+ if (pflags & PS_FOV)
+ MSG_WriteByte (msg, ps->fov);
+ if (pflags & PS_RDFLAGS)
+ MSG_WriteByte (msg, ps->rdflags);
+
+ // send stats
+ statbits = 0;
+ for (i=0 ; i<MAX_STATS ; i++)
+ if (ps->stats[i] != ops->stats[i])
+ statbits |= 1<<i;
+ MSG_WriteLong (msg, statbits);
+ for (i=0 ; i<MAX_STATS ; i++)
+ if (statbits & (1<<i) )
+ MSG_WriteShort (msg, ps->stats[i]);
+}
+
+
+/*
+==================
+SV_WriteFrameToClient
+==================
+*/
+void SV_WriteFrameToClient (client_t *client, sizebuf_t *msg)
+{
+ client_frame_t *frame, *oldframe;
+ int lastframe;
+
+//Com_Printf ("%i -> %i\n", client->lastframe, sv.framenum);
+ // this is the frame we are creating
+ frame = &client->frames[sv.framenum & UPDATE_MASK];
+
+ if (client->lastframe <= 0)
+ { // client is asking for a retransmit
+ oldframe = NULL;
+ lastframe = -1;
+ }
+ else if (sv.framenum - client->lastframe >= (UPDATE_BACKUP - 3) )
+ { // client hasn't gotten a good message through in a long time
+// Com_Printf ("%s: Delta request from out-of-date packet.\n", client->name);
+ oldframe = NULL;
+ lastframe = -1;
+ }
+ else
+ { // we have a valid message to delta from
+ oldframe = &client->frames[client->lastframe & UPDATE_MASK];
+ lastframe = client->lastframe;
+ }
+
+ MSG_WriteByte (msg, svc_frame);
+ MSG_WriteLong (msg, sv.framenum);
+ MSG_WriteLong (msg, lastframe); // what we are delta'ing from
+ MSG_WriteByte (msg, client->surpressCount); // rate dropped packets
+ client->surpressCount = 0;
+
+ // send over the areabits
+ MSG_WriteByte (msg, frame->areabytes);
+ SZ_Write (msg, frame->areabits, frame->areabytes);
+
+ // delta encode the playerstate
+ SV_WritePlayerstateToClient (oldframe, frame, msg);
+
+ // delta encode the entities
+ SV_EmitPacketEntities (oldframe, frame, msg);
+}
+
+
+/*
+=============================================================================
+
+Build a client frame structure
+
+=============================================================================
+*/
+
+byte fatpvs[65536/8]; // 32767 is MAX_MAP_LEAFS
+
+/*
+============
+SV_FatPVS
+
+The client will interpolate the view position,
+so we can't use a single PVS point
+===========
+*/
+void SV_FatPVS (vec3_t org)
+{
+ int leafs[64];
+ int i, j, count;
+ int longs;
+ byte *src;
+ vec3_t mins, maxs;
+
+ for (i=0 ; i<3 ; i++)
+ {
+ mins[i] = org[i] - 8;
+ maxs[i] = org[i] + 8;
+ }
+
+ count = CM_BoxLeafnums (mins, maxs, leafs, 64, NULL);
+ if (count < 1)
+ Com_Error (ERR_FATAL, "SV_FatPVS: count < 1");
+ longs = (CM_NumClusters()+31)>>5;
+
+ // convert leafs to clusters
+ for (i=0 ; i<count ; i++)
+ leafs[i] = CM_LeafCluster(leafs[i]);
+
+ memcpy (fatpvs, CM_ClusterPVS(leafs[0]), longs<<2);
+ // or in all the other leaf bits
+ for (i=1 ; i<count ; i++)
+ {
+ for (j=0 ; j<i ; j++)
+ if (leafs[i] == leafs[j])
+ break;
+ if (j != i)
+ continue; // already have the cluster we want
+ src = CM_ClusterPVS(leafs[i]);
+ for (j=0 ; j<longs ; j++)
+ ((long *)fatpvs)[j] |= ((long *)src)[j];
+ }
+}
+
+
+/*
+=============
+SV_BuildClientFrame
+
+Decides which entities are going to be visible to the client, and
+copies off the playerstat and areabits.
+=============
+*/
+void SV_BuildClientFrame (client_t *client)
+{
+ int e, i;
+ vec3_t org;
+ edict_t *ent;
+ edict_t *clent;
+ client_frame_t *frame;
+ entity_state_t *state;
+ int l;
+ int clientarea, clientcluster;
+ int leafnum;
+ int c_fullsend;
+ byte *clientphs;
+ byte *bitvector;
+
+ clent = client->edict;
+ if (!clent->client)
+ return; // not in game yet
+
+ //numprojs = 0; // no projectiles yet
+
+ // this is the frame we are creating
+ frame = &client->frames[sv.framenum & UPDATE_MASK];
+
+ frame->senttime = svs.realtime; // save it for ping calc later
+
+ // find the client's PVS
+ for (i=0 ; i<3 ; i++)
+ org[i] = clent->client->ps.pmove.origin[i]*0.125 + clent->client->ps.viewoffset[i];
+
+ leafnum = CM_PointLeafnum (org);
+ clientarea = CM_LeafArea (leafnum);
+ clientcluster = CM_LeafCluster (leafnum);
+
+ // calculate the visible areas
+ frame->areabytes = CM_WriteAreaBits (frame->areabits, clientarea);
+
+ // grab the current player_state_t
+ frame->ps = clent->client->ps;
+
+
+ SV_FatPVS (org);
+ clientphs = CM_ClusterPHS (clientcluster);
+
+ // build up the list of visible entities
+ frame->num_entities = 0;
+ frame->first_entity = svs.next_client_entities;
+
+ c_fullsend = 0;
+
+ for (e=1 ; e<ge->num_edicts ; e++)
+ {
+ ent = EDICT_NUM(e);
+
+ // ignore ents without visible models
+ if (ent->svflags & SVF_NOCLIENT)
+ continue;
+
+ // ignore ents without visible models unless they have an effect
+ if (!ent->s.modelindex && !ent->s.effects && !ent->s.sound
+ && !ent->s.event)
+ continue;
+
+ // ignore if not touching a PV leaf
+ if (ent != clent)
+ {
+ // check area
+ if (!CM_AreasConnected (clientarea, ent->areanum))
+ { // doors can legally straddle two areas, so
+ // we may need to check another one
+ if (!ent->areanum2
+ || !CM_AreasConnected (clientarea, ent->areanum2))
+ continue; // blocked by a door
+ }
+
+ // beams just check one point for PHS
+ if (ent->s.renderfx & RF_BEAM)
+ {
+ l = ent->clusternums[0];
+ if ( !(clientphs[l >> 3] & (1 << (l&7) )) )
+ continue;
+ }
+ else
+ {
+ // FIXME: if an ent has a model and a sound, but isn't
+ // in the PVS, only the PHS, clear the model
+ if (ent->s.sound)
+ {
+ bitvector = fatpvs; //clientphs;
+ }
+ else
+ bitvector = fatpvs;
+
+ if (ent->num_clusters == -1)
+ { // too many leafs for individual check, go by headnode
+ if (!CM_HeadnodeVisible (ent->headnode, bitvector))
+ continue;
+ c_fullsend++;
+ }
+ else
+ { // check individual leafs
+ for (i=0 ; i < ent->num_clusters ; i++)
+ {
+ l = ent->clusternums[i];
+ if (bitvector[l >> 3] & (1 << (l&7) ))
+ break;
+ }
+ if (i == ent->num_clusters)
+ continue; // not visible
+ }
+
+ if (!ent->s.modelindex)
+ { // don't send sounds if they will be attenuated away
+ vec3_t delta;
+ float len;
+
+ VectorSubtract (org, ent->s.origin, delta);
+ len = VectorLength (delta);
+ if (len > 400)
+ continue;
+ }
+ }
+ }
+
+/*
+ if (SV_AddProjectileUpdate(ent))
+ continue; // added as a special projectile
+*/
+
+ // add it to the circular client_entities array
+ state = &svs.client_entities[svs.next_client_entities%svs.num_client_entities];
+ if (ent->s.number != e)
+ {
+ Com_DPrintf ("FIXING ENT->S.NUMBER!!!\n");
+ ent->s.number = e;
+ }
+ *state = ent->s;
+
+ // don't mark players missiles as solid
+ if (ent->owner == client->edict)
+ state->solid = 0;
+
+ svs.next_client_entities++;
+ frame->num_entities++;
+ }
+}
+
+
+/*
+==================
+SV_RecordDemoMessage
+
+Save everything in the world out without deltas.
+Used for recording footage for merged or assembled demos
+==================
+*/
+void SV_RecordDemoMessage (void)
+{
+ int e;
+ edict_t *ent;
+ entity_state_t nostate;
+ sizebuf_t buf;
+ byte buf_data[32768];
+ int len;
+
+ if (!svs.demofile)
+ return;
+
+ memset (&nostate, 0, sizeof(nostate));
+ SZ_Init (&buf, buf_data, sizeof(buf_data));
+
+ // write a frame message that doesn't contain a player_state_t
+ MSG_WriteByte (&buf, svc_frame);
+ MSG_WriteLong (&buf, sv.framenum);
+
+ MSG_WriteByte (&buf, svc_packetentities);
+
+ e = 1;
+ ent = EDICT_NUM(e);
+ while (e < ge->num_edicts)
+ {
+ // ignore ents without visible models unless they have an effect
+ if (ent->inuse &&
+ ent->s.number &&
+ (ent->s.modelindex || ent->s.effects || ent->s.sound || ent->s.event) &&
+ !(ent->svflags & SVF_NOCLIENT))
+ MSG_WriteDeltaEntity (&nostate, &ent->s, &buf, false, true);
+
+ e++;
+ ent = EDICT_NUM(e);
+ }
+
+ MSG_WriteShort (&buf, 0); // end of packetentities
+
+ // now add the accumulated multicast information
+ SZ_Write (&buf, svs.demo_multicast.data, svs.demo_multicast.cursize);
+ SZ_Clear (&svs.demo_multicast);
+
+ // now write the entire message to the file, prefixed by the length
+ len = LittleLong (buf.cursize);
+ fwrite (&len, 4, 1, svs.demofile);
+ fwrite (buf.data, buf.cursize, 1, svs.demofile);
+}
+
--- /dev/null
+++ b/sv_game.c
@@ -1,0 +1,380 @@
+// sv_game.c -- interface to the game dll
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+game_export_t *ge;
+
+
+/*
+===============
+PF_Unicast
+
+Sends the contents of the mutlicast buffer to a single client
+===============
+*/
+void PF_Unicast (edict_t *ent, qboolean reliable)
+{
+ int p;
+ client_t *client;
+
+ if (!ent)
+ return;
+
+ p = NUM_FOR_EDICT(ent);
+ if (p < 1 || p > maxclients->value)
+ return;
+
+ client = svs.clients + (p-1);
+
+ if (reliable)
+ SZ_Write (&client->netchan.message, sv.multicast.data, sv.multicast.cursize);
+ else
+ SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize);
+
+ SZ_Clear (&sv.multicast);
+}
+
+
+/*
+===============
+PF_dprintf
+
+Debug print to server console
+===============
+*/
+void PF_dprintf (char *fmt, ...)
+{
+ char msg[1024];
+ va_list argptr;
+
+ va_start (argptr,fmt);
+ vsprintf (msg, fmt, argptr);
+ va_end (argptr);
+
+ Com_Printf ("%s", msg);
+}
+
+
+/*
+===============
+PF_cprintf
+
+Print to a single client
+===============
+*/
+void PF_cprintf (edict_t *ent, int level, char *fmt, ...)
+{
+ char msg[1024];
+ va_list argptr;
+ int n = 0;
+
+ if (ent)
+ {
+ n = NUM_FOR_EDICT(ent);
+ if (n < 1 || n > maxclients->value)
+ Com_Error (ERR_DROP, "cprintf to a non-client");
+ }
+
+ va_start (argptr,fmt);
+ vsprintf (msg, fmt, argptr);
+ va_end (argptr);
+
+ if (ent)
+ SV_ClientPrintf (svs.clients+(n-1), level, "%s", msg);
+ else
+ Com_Printf ("%s", msg);
+}
+
+
+/*
+===============
+PF_centerprintf
+
+centerprint to a single client
+===============
+*/
+void PF_centerprintf (edict_t *ent, char *fmt, ...)
+{
+ char msg[1024];
+ va_list argptr;
+ int n;
+
+ n = NUM_FOR_EDICT(ent);
+ if (n < 1 || n > maxclients->value)
+ return; // Com_Error (ERR_DROP, "centerprintf to a non-client");
+
+ va_start (argptr,fmt);
+ vsprintf (msg, fmt, argptr);
+ va_end (argptr);
+
+ MSG_WriteByte (&sv.multicast,svc_centerprint);
+ MSG_WriteString (&sv.multicast,msg);
+ PF_Unicast (ent, true);
+}
+
+
+/*
+===============
+PF_error
+
+Abort the server with a game error
+===============
+*/
+void PF_error (char *fmt, ...)
+{
+ char msg[1024];
+ va_list argptr;
+
+ va_start (argptr,fmt);
+ vsprintf (msg, fmt, argptr);
+ va_end (argptr);
+
+ Com_Error (ERR_DROP, "Game Error: %s", msg);
+}
+
+
+/*
+=================
+PF_setmodel
+
+Also sets mins and maxs for inline bmodels
+=================
+*/
+void PF_setmodel (edict_t *ent, char *name)
+{
+ int i;
+ cmodel_t *mod;
+
+ if (!name)
+ Com_Error (ERR_DROP, "PF_setmodel: NULL");
+
+ i = SV_ModelIndex (name);
+
+// ent->model = name;
+ ent->s.modelindex = i;
+
+// if it is an inline model, get the size information for it
+ if (name[0] == '*')
+ {
+ mod = CM_InlineModel (name);
+ VectorCopy (mod->mins, ent->mins);
+ VectorCopy (mod->maxs, ent->maxs);
+ SV_LinkEdict (ent);
+ }
+
+}
+
+/*
+===============
+PF_Configstring
+
+===============
+*/
+void PF_Configstring (int index, char *val)
+{
+ if (index < 0 || index >= MAX_CONFIGSTRINGS)
+ Com_Error (ERR_DROP, "configstring: bad index %i\n", index);
+
+ if (!val)
+ val = "";
+
+ // change the string in sv
+ strcpy (sv.configstrings[index], val);
+
+ if (sv.state != ss_loading)
+ { // send the update to everyone
+ SZ_Clear (&sv.multicast);
+ MSG_WriteChar (&sv.multicast, svc_configstring);
+ MSG_WriteShort (&sv.multicast, index);
+ MSG_WriteString (&sv.multicast, val);
+
+ SV_Multicast (vec3_origin, MULTICAST_ALL_R);
+ }
+}
+
+
+
+void PF_WriteChar (int c) {MSG_WriteChar (&sv.multicast, c);}
+void PF_WriteByte (int c) {MSG_WriteByte (&sv.multicast, c);}
+void PF_WriteShort (int c) {MSG_WriteShort (&sv.multicast, c);}
+void PF_WriteLong (int c) {MSG_WriteLong (&sv.multicast, c);}
+void PF_WriteFloat (float f) {MSG_WriteFloat (&sv.multicast, f);}
+void PF_WriteString (char *s) {MSG_WriteString (&sv.multicast, s);}
+void PF_WritePos (vec3_t pos) {MSG_WritePos (&sv.multicast, pos);}
+void PF_WriteDir (vec3_t dir) {MSG_WriteDir (&sv.multicast, dir);}
+void PF_WriteAngle (float f) {MSG_WriteAngle (&sv.multicast, f);}
+
+
+/*
+=================
+PF_inPVS
+
+Also checks portalareas so that doors block sight
+=================
+*/
+qboolean PF_inPVS (vec3_t p1, vec3_t p2)
+{
+ int leafnum;
+ int cluster;
+ int area1, area2;
+ byte *mask;
+
+ leafnum = CM_PointLeafnum (p1);
+ cluster = CM_LeafCluster (leafnum);
+ area1 = CM_LeafArea (leafnum);
+ mask = CM_ClusterPVS (cluster);
+
+ leafnum = CM_PointLeafnum (p2);
+ cluster = CM_LeafCluster (leafnum);
+ area2 = CM_LeafArea (leafnum);
+ if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
+ return false;
+ if (!CM_AreasConnected (area1, area2))
+ return false; // a door blocks sight
+ return true;
+}
+
+
+/*
+=================
+PF_inPHS
+
+Also checks portalareas so that doors block sound
+=================
+*/
+qboolean PF_inPHS (vec3_t p1, vec3_t p2)
+{
+ int leafnum;
+ int cluster;
+ int area1, area2;
+ byte *mask;
+
+ leafnum = CM_PointLeafnum (p1);
+ cluster = CM_LeafCluster (leafnum);
+ area1 = CM_LeafArea (leafnum);
+ mask = CM_ClusterPHS (cluster);
+
+ leafnum = CM_PointLeafnum (p2);
+ cluster = CM_LeafCluster (leafnum);
+ area2 = CM_LeafArea (leafnum);
+ if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
+ return false; // more than one bounce away
+ if (!CM_AreasConnected (area1, area2))
+ return false; // a door blocks hearing
+
+ return true;
+}
+
+void PF_StartSound (edict_t *entity, int channel, int sound_num, float volume,
+ float attenuation, float timeofs)
+{
+ if (!entity)
+ return;
+ SV_StartSound (NULL, entity, channel, sound_num, volume, attenuation, timeofs);
+}
+
+//==============================================
+
+/*
+===============
+SV_ShutdownGameProgs
+
+Called when either the entire server is being killed, or
+it is changing to a different game directory.
+===============
+*/
+void SV_ShutdownGameProgs (void)
+{
+ if (!ge)
+ return;
+ ge->Shutdown ();
+ Sys_UnloadGame ();
+ ge = NULL;
+}
+
+/*
+===============
+SV_InitGameProgs
+
+Init the game subsystem for a new map
+===============
+*/
+void SCR_DebugGraph (float value, int color);
+
+void SV_InitGameProgs (void)
+{
+ game_import_t import;
+
+ // unload anything we have now
+ if (ge)
+ SV_ShutdownGameProgs ();
+
+
+ // load a new game dll
+ import.multicast = SV_Multicast;
+ import.unicast = PF_Unicast;
+ import.bprintf = SV_BroadcastPrintf;
+ import.dprintf = PF_dprintf;
+ import.cprintf = PF_cprintf;
+ import.centerprintf = PF_centerprintf;
+ import.error = PF_error;
+
+ import.linkentity = SV_LinkEdict;
+ import.unlinkentity = SV_UnlinkEdict;
+ import.BoxEdicts = SV_AreaEdicts;
+ import.trace = SV_Trace;
+ import.pointcontents = SV_PointContents;
+ import.setmodel = PF_setmodel;
+ import.inPVS = PF_inPVS;
+ import.inPHS = PF_inPHS;
+ import.Pmove = Pmove;
+
+ import.modelindex = SV_ModelIndex;
+ import.soundindex = SV_SoundIndex;
+ import.imageindex = SV_ImageIndex;
+
+ import.configstring = PF_Configstring;
+ import.sound = PF_StartSound;
+ import.positioned_sound = SV_StartSound;
+
+ import.WriteChar = PF_WriteChar;
+ import.WriteByte = PF_WriteByte;
+ import.WriteShort = PF_WriteShort;
+ import.WriteLong = PF_WriteLong;
+ import.WriteFloat = PF_WriteFloat;
+ import.WriteString = PF_WriteString;
+ import.WritePosition = PF_WritePos;
+ import.WriteDir = PF_WriteDir;
+ import.WriteAngle = PF_WriteAngle;
+
+ import.TagMalloc = Z_TagMalloc;
+ import.TagFree = Z_Free;
+ import.FreeTags = Z_FreeTags;
+
+ import.cvar = Cvar_Get;
+ import.cvar_set = Cvar_Set;
+ import.cvar_forceset = Cvar_ForceSet;
+
+ import.argc = Cmd_Argc;
+ import.argv = Cmd_Argv;
+ import.args = Cmd_Args;
+ import.AddCommandString = Cbuf_AddText;
+
+ import.DebugGraph = SCR_DebugGraph;
+ import.SetAreaPortalState = CM_SetAreaPortalState;
+ import.AreasConnected = CM_AreasConnected;
+
+ ge = GetGameAPI(&import);
+
+ if (!ge)
+ Com_Error (ERR_DROP, "failed to load game DLL");
+ if (ge->apiversion != GAME_API_VERSION)
+ Com_Error (ERR_DROP, "game is version %i, not %i", ge->apiversion,
+ GAME_API_VERSION);
+
+ ge->Init ();
+}
--- /dev/null
+++ b/sv_init.c
@@ -1,0 +1,449 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+server_static_t svs; // persistant server info
+server_t sv; // local server
+
+/*
+================
+SV_FindIndex
+
+================
+*/
+int SV_FindIndex (char *name, int start, int max, qboolean create)
+{
+ int i;
+
+ if (!name || !name[0])
+ return 0;
+
+ for (i=1 ; i<max && sv.configstrings[start+i][0] ; i++)
+ if (!strcmp(sv.configstrings[start+i], name))
+ return i;
+
+ if (!create)
+ return 0;
+
+ if (i == max)
+ Com_Error (ERR_DROP, "*Index: overflow");
+
+ strncpy (sv.configstrings[start+i], name, sizeof(sv.configstrings[i]));
+
+ if (sv.state != ss_loading)
+ { // send the update to everyone
+ SZ_Clear (&sv.multicast);
+ MSG_WriteChar (&sv.multicast, svc_configstring);
+ MSG_WriteShort (&sv.multicast, start+i);
+ MSG_WriteString (&sv.multicast, name);
+ SV_Multicast (vec3_origin, MULTICAST_ALL_R);
+ }
+
+ return i;
+}
+
+
+int SV_ModelIndex (char *name)
+{
+ return SV_FindIndex (name, CS_MODELS, MAX_MODELS, true);
+}
+
+int SV_SoundIndex (char *name)
+{
+ return SV_FindIndex (name, CS_SOUNDS, MAX_SOUNDS, true);
+}
+
+int SV_ImageIndex (char *name)
+{
+ return SV_FindIndex (name, CS_IMAGES, MAX_IMAGES, true);
+}
+
+
+/*
+================
+SV_CreateBaseline
+
+Entity baselines are used to compress the update messages
+to the clients -- only the fields that differ from the
+baseline will be transmitted
+================
+*/
+void SV_CreateBaseline (void)
+{
+ edict_t *svent;
+ int entnum;
+
+ for (entnum = 1; entnum < ge->num_edicts ; entnum++)
+ {
+ svent = EDICT_NUM(entnum);
+ if (!svent->inuse)
+ continue;
+ if (!svent->s.modelindex && !svent->s.sound && !svent->s.effects)
+ continue;
+ svent->s.number = entnum;
+
+ //
+ // take current state as baseline
+ //
+ VectorCopy (svent->s.origin, svent->s.old_origin);
+ sv.baselines[entnum] = svent->s;
+ }
+}
+
+
+/*
+=================
+SV_CheckForSavegame
+=================
+*/
+void SV_CheckForSavegame (void)
+{
+ char name[MAX_OSPATH];
+ FILE *f;
+ int i;
+
+ if (sv_noreload->value)
+ return;
+
+ if (Cvar_VariableValue ("deathmatch"))
+ return;
+
+ Com_sprintf (name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name);
+ f = fopen (name, "rb");
+ if (!f)
+ return; // no savegame
+
+ fclose (f);
+
+ SV_ClearWorld ();
+
+ // get configstrings and areaportals
+ SV_ReadLevelFile ();
+
+ if (!sv.loadgame)
+ { // coming back to a level after being in a different
+ // level, so run it for ten seconds
+
+ // rlava2 was sending too many lightstyles, and overflowing the
+ // reliable data. temporarily changing the server state to loading
+ // prevents these from being passed down.
+ server_state_t previousState; // PGM
+
+ previousState = sv.state; // PGM
+ sv.state = ss_loading; // PGM
+ for (i=0 ; i<100 ; i++)
+ ge->RunFrame ();
+
+ sv.state = previousState; // PGM
+ }
+}
+
+
+/*
+================
+SV_SpawnServer
+
+Change the server to a new map, taking all connected
+clients along with it.
+
+================
+*/
+void SV_SpawnServer (char *server, char *spawnpoint, server_state_t serverstate, qboolean attractloop, qboolean loadgame)
+{
+ int i;
+ unsigned checksum;
+
+ if (attractloop)
+ Cvar_Set ("paused", "0");
+
+ Com_Printf ("------- Server Initialization -------\n");
+
+ Com_DPrintf ("SpawnServer: %s\n",server);
+ if (sv.demofile)
+ fclose (sv.demofile);
+
+ svs.spawncount++; // any partially connected client will be
+ // restarted
+ sv.state = ss_dead;
+ Com_SetServerState (sv.state);
+
+ // wipe the entire per-level structure
+ memset (&sv, 0, sizeof(sv));
+ svs.realtime = 0;
+ sv.loadgame = loadgame;
+ sv.attractloop = attractloop;
+
+ // save name for levels that don't set message
+ strcpy (sv.configstrings[CS_NAME], server);
+ if (Cvar_VariableValue ("deathmatch"))
+ {
+ sprintf(sv.configstrings[CS_AIRACCEL], "%g", sv_airaccelerate->value);
+ pm_airaccelerate = sv_airaccelerate->value;
+ }
+ else
+ {
+ strcpy(sv.configstrings[CS_AIRACCEL], "0");
+ pm_airaccelerate = 0;
+ }
+
+ SZ_Init (&sv.multicast, sv.multicast_buf, sizeof(sv.multicast_buf));
+
+ strcpy (sv.name, server);
+
+ // leave slots at start for clients only
+ for (i=0 ; i<maxclients->value ; i++)
+ {
+ // needs to reconnect
+ if (svs.clients[i].state > cs_connected)
+ svs.clients[i].state = cs_connected;
+ svs.clients[i].lastframe = -1;
+ }
+
+ sv.time = 1000;
+
+ strcpy (sv.name, server);
+ strcpy (sv.configstrings[CS_NAME], server);
+
+ if (serverstate != ss_game)
+ {
+ sv.models[1] = CM_LoadMap ("", false, &checksum); // no real map
+ }
+ else
+ {
+ Com_sprintf (sv.configstrings[CS_MODELS+1],sizeof(sv.configstrings[CS_MODELS+1]),
+ "maps/%s.bsp", server);
+ sv.models[1] = CM_LoadMap (sv.configstrings[CS_MODELS+1], false, &checksum);
+ }
+ Com_sprintf (sv.configstrings[CS_MAPCHECKSUM],sizeof(sv.configstrings[CS_MAPCHECKSUM]),
+ "%i", checksum);
+
+ //
+ // clear physics interaction links
+ //
+ SV_ClearWorld ();
+
+ for (i=1 ; i< CM_NumInlineModels() ; i++)
+ {
+ Com_sprintf (sv.configstrings[CS_MODELS+1+i], sizeof(sv.configstrings[CS_MODELS+1+i]),
+ "*%i", i);
+ sv.models[i+1] = CM_InlineModel (sv.configstrings[CS_MODELS+1+i]);
+ }
+
+ //
+ // spawn the rest of the entities on the map
+ //
+
+ // precache and static commands can be issued during
+ // map initialization
+ sv.state = ss_loading;
+ Com_SetServerState (sv.state);
+
+ // load and spawn all other entities
+ ge->SpawnEntities ( sv.name, CM_EntityString(), spawnpoint );
+
+ // run two frames to allow everything to settle
+ ge->RunFrame ();
+ ge->RunFrame ();
+
+ // all precaches are complete
+ sv.state = serverstate;
+ Com_SetServerState (sv.state);
+
+ // create a baseline for more efficient communications
+ SV_CreateBaseline ();
+
+ // check for a savegame
+ SV_CheckForSavegame ();
+
+ // set serverinfo variable
+ Cvar_FullSet ("mapname", sv.name, CVAR_SERVERINFO | CVAR_NOSET);
+
+ Com_Printf ("-------------------------------------\n");
+}
+
+/*
+==============
+SV_InitGame
+
+A brand new game has been started
+==============
+*/
+void SV_InitGame (void)
+{
+ int i;
+ edict_t *ent;
+ char idmaster[32];
+
+ if (svs.initialized)
+ {
+ // cause any connected clients to reconnect
+ SV_Shutdown ("Server restarted\n", true);
+ }
+ else
+ {
+ // make sure the client is down
+ CL_Drop ();
+ SCR_BeginLoadingPlaque ();
+ }
+
+ // get any latched variable changes (maxclients, etc)
+ Cvar_GetLatchedVars ();
+
+ svs.initialized = true;
+
+ if (Cvar_VariableValue ("coop") && Cvar_VariableValue ("deathmatch"))
+ {
+ Com_Printf("Deathmatch and Coop both set, disabling Coop\n");
+ Cvar_FullSet ("coop", "0", CVAR_SERVERINFO | CVAR_LATCH);
+ }
+
+ // dedicated servers are can't be single player and are usually DM
+ // so unless they explicity set coop, force it to deathmatch
+ if (dedicated->value)
+ {
+ if (!Cvar_VariableValue ("coop"))
+ Cvar_FullSet ("deathmatch", "1", CVAR_SERVERINFO | CVAR_LATCH);
+ }
+
+ // init clients
+ if (Cvar_VariableValue ("deathmatch"))
+ {
+ if (maxclients->value <= 1)
+ Cvar_FullSet ("maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH);
+ else if (maxclients->value > MAX_CLIENTS)
+ Cvar_FullSet ("maxclients", va("%i", MAX_CLIENTS), CVAR_SERVERINFO | CVAR_LATCH);
+ }
+ else if (Cvar_VariableValue ("coop"))
+ {
+ if (maxclients->value <= 1 || maxclients->value > 4)
+ Cvar_FullSet ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
+#ifdef COPYPROTECT
+ if (!sv.attractloop && !dedicated->value)
+ Sys_CopyProtect ();
+#endif
+ }
+ else // non-deathmatch, non-coop is one player
+ {
+ Cvar_FullSet ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);
+#ifdef COPYPROTECT
+ if (!sv.attractloop)
+ Sys_CopyProtect ();
+#endif
+ }
+
+ svs.spawncount = rand();
+ svs.clients = Z_Malloc (sizeof(client_t)*maxclients->value);
+ svs.num_client_entities = maxclients->value*UPDATE_BACKUP*64;
+ svs.client_entities = Z_Malloc (sizeof(entity_state_t)*svs.num_client_entities);
+
+ // init network stuff
+ NET_Config ( (maxclients->value > 1) );
+
+ // heartbeats will always be sent to the id master
+ svs.last_heartbeat = -99999; // send immediately
+ Com_sprintf(idmaster, sizeof(idmaster), "192.246.40.37:%i", PORT_MASTER);
+ NET_StringToAdr (idmaster, &master_adr[0]);
+
+ // init game
+ SV_InitGameProgs ();
+ for (i=0 ; i<maxclients->value ; i++)
+ {
+ ent = EDICT_NUM(i+1);
+ ent->s.number = i+1;
+ svs.clients[i].edict = ent;
+ memset (&svs.clients[i].lastcmd, 0, sizeof(svs.clients[i].lastcmd));
+ }
+}
+
+
+/*
+======================
+SV_Map
+
+ the full syntax is:
+
+ map [*]<map>$<startspot>+<nextserver>
+
+command from the console or progs.
+Map can also be a.cin, .pcx, or .dm2 file
+Nextserver is used to allow a cinematic to play, then proceed to
+another level:
+
+ map tram.cin+jail_e3
+======================
+*/
+void SV_Map (qboolean attractloop, char *levelstring, qboolean loadgame)
+{
+ char level[MAX_QPATH];
+ char *ch;
+ int l;
+ char spawnpoint[MAX_QPATH];
+
+ sv.loadgame = loadgame;
+ sv.attractloop = attractloop;
+
+ if (sv.state == ss_dead && !sv.loadgame)
+ SV_InitGame (); // the game is just starting
+
+ strcpy (level, levelstring);
+
+ // if there is a + in the map, set nextserver to the remainder
+ ch = strstr(level, "+");
+ if (ch)
+ {
+ *ch = 0;
+ Cvar_Set ("nextserver", va("gamemap \"%s\"", ch+1));
+ }
+ else
+ Cvar_Set ("nextserver", "");
+
+ //ZOID special hack for end game screen in coop mode
+ if (Cvar_VariableValue ("coop") && !cistrcmp(level, "victory.pcx"))
+ Cvar_Set ("nextserver", "gamemap \"*base1\"");
+
+ // if there is a $, use the remainder as a spawnpoint
+ ch = strstr(level, "$");
+ if (ch)
+ {
+ *ch = 0;
+ strcpy (spawnpoint, ch+1);
+ }
+ else
+ spawnpoint[0] = 0;
+
+ // skip the end-of-unit flag if necessary
+ if (level[0] == '*')
+ strcpy (level, level+1);
+
+ l = strlen(level);
+ if (l > 4 && !strcmp (level+l-4, ".cin") )
+ {
+ SCR_BeginLoadingPlaque (); // for local system
+ SV_BroadcastCommand ("changing\n");
+ SV_SpawnServer (level, spawnpoint, ss_cinematic, attractloop, loadgame);
+ }
+ else if (l > 4 && !strcmp (level+l-4, ".dm2") )
+ {
+ SCR_BeginLoadingPlaque (); // for local system
+ SV_BroadcastCommand ("changing\n");
+ SV_SpawnServer (level, spawnpoint, ss_demo, attractloop, loadgame);
+ }
+ else if (l > 4 && !strcmp (level+l-4, ".pcx") )
+ {
+ SCR_BeginLoadingPlaque (); // for local system
+ SV_BroadcastCommand ("changing\n");
+ SV_SpawnServer (level, spawnpoint, ss_pic, attractloop, loadgame);
+ }
+ else
+ {
+ SCR_BeginLoadingPlaque (); // for local system
+ SV_BroadcastCommand ("changing\n");
+ SV_SendClientMessages ();
+ SV_SpawnServer (level, spawnpoint, ss_game, attractloop, loadgame);
+ Cbuf_CopyToDefer ();
+ }
+
+ SV_BroadcastCommand ("reconnect\n");
+}
--- /dev/null
+++ b/sv_main.c
@@ -1,0 +1,1036 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+netadr_t master_adr[MAX_MASTERS]; // address of group servers
+
+client_t *sv_client; // current client
+
+cvar_t *sv_paused;
+cvar_t *sv_timedemo;
+
+cvar_t *sv_enforcetime;
+
+cvar_t *timeout; // seconds without any message
+cvar_t *zombietime; // seconds to sink messages after disconnect
+
+cvar_t *rcon_password; // password for remote server commands
+
+cvar_t *allow_download;
+cvar_t *allow_download_players;
+cvar_t *allow_download_models;
+cvar_t *allow_download_sounds;
+cvar_t *allow_download_maps;
+
+cvar_t *sv_airaccelerate;
+
+cvar_t *sv_noreload; // don't reload level state when reentering
+
+cvar_t *maxclients; // FIXME: rename sv_maxclients
+cvar_t *sv_showclamp;
+
+cvar_t *hostname;
+cvar_t *public_server; // should heartbeats be sent
+
+cvar_t *sv_reconnect_limit; // minimum seconds between connect messages
+
+void Master_Shutdown (void);
+
+
+//============================================================================
+
+
+/*
+=====================
+SV_DropClient
+
+Called when the player is totally leaving the server, either willingly
+or unwillingly. This is NOT called if the entire server is quiting
+or crashing.
+=====================
+*/
+void SV_DropClient (client_t *drop)
+{
+ // add the disconnect
+ MSG_WriteByte (&drop->netchan.message, svc_disconnect);
+
+ if (drop->state == cs_spawned)
+ {
+ // call the prog function for removing a client
+ // this will remove the body, among other things
+ ge->ClientDisconnect (drop->edict);
+ }
+
+ if (drop->download)
+ {
+ FS_FreeFile (drop->download);
+ drop->download = NULL;
+ }
+
+ drop->state = cs_zombie; // become free in a few seconds
+ drop->name[0] = 0;
+}
+
+
+
+/*
+==============================================================================
+
+CONNECTIONLESS COMMANDS
+
+==============================================================================
+*/
+
+/*
+===============
+SV_StatusString
+
+Builds the string that is sent as heartbeats and status replies
+===============
+*/
+char *SV_StatusString (void)
+{
+ char player[1024];
+ static char status[MAX_MSGLEN - 16];
+ int i;
+ client_t *cl;
+ int statusLength;
+ int playerLength;
+
+ strcpy (status, Cvar_Serverinfo());
+ strcat (status, "\n");
+ statusLength = strlen(status);
+
+ for (i=0 ; i<maxclients->value ; i++)
+ {
+ cl = &svs.clients[i];
+ if (cl->state == cs_connected || cl->state == cs_spawned )
+ {
+ Com_sprintf (player, sizeof(player), "%i %i \"%s\"\n",
+ cl->edict->client->ps.stats[STAT_FRAGS], cl->ping, cl->name);
+ playerLength = strlen(player);
+ if (statusLength + playerLength >= sizeof(status) )
+ break; // can't hold any more
+ strcpy (status + statusLength, player);
+ statusLength += playerLength;
+ }
+ }
+
+ return status;
+}
+
+/*
+================
+SVC_Status
+
+Responds with all the info that qplug or qspy can see
+================
+*/
+void SVC_Status (void)
+{
+ Netchan_OutOfBandPrint (NS_SERVER, net_from, "print\n%s", SV_StatusString());
+/*
+ Com_BeginRedirect (RD_PACKET, sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect);
+ Com_Printf (SV_StatusString());
+ Com_EndRedirect ();
+*/
+}
+
+/*
+================
+SVC_Ack
+
+================
+*/
+void SVC_Ack (void)
+{
+ Com_Printf ("Ping acknowledge from %s\n", NET_AdrToString(net_from));
+}
+
+/*
+================
+SVC_Info
+
+Responds with short info for broadcast scans
+The second parameter should be the current protocol version number.
+================
+*/
+void SVC_Info (void)
+{
+ char string[64];
+ int i, count;
+ int version;
+
+ if (maxclients->value == 1)
+ return; // ignore in single player
+
+ version = atoi (Cmd_Argv(1));
+
+ if (version != PROTOCOL_VERSION)
+ Com_sprintf (string, sizeof(string), "%s: wrong version\n", hostname->string, sizeof(string));
+ else
+ {
+ count = 0;
+ for (i=0 ; i<maxclients->value ; i++)
+ if (svs.clients[i].state >= cs_connected)
+ count++;
+
+ Com_sprintf (string, sizeof(string), "%16s %8s %2i/%2i\n", hostname->string, sv.name, count, (int)maxclients->value);
+ }
+
+ Netchan_OutOfBandPrint (NS_SERVER, net_from, "info\n%s", string);
+}
+
+/*
+================
+SVC_Ping
+
+Just responds with an acknowledgement
+================
+*/
+void SVC_Ping (void)
+{
+ Netchan_OutOfBandPrint (NS_SERVER, net_from, "ack");
+}
+
+
+/*
+=================
+SVC_GetChallenge
+
+Returns a challenge number that can be used
+in a subsequent client_connect command.
+We do this to prevent denial of service attacks that
+flood the server with invalid connection IPs. With a
+challenge, they must give a valid IP address.
+=================
+*/
+void SVC_GetChallenge (void)
+{
+ int i;
+ int oldest;
+ int oldestTime;
+
+ oldest = 0;
+ oldestTime = 0x7fffffff;
+
+ // see if we already have a challenge for this ip
+ for (i = 0 ; i < MAX_CHALLENGES ; i++)
+ {
+ if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
+ break;
+ if (svs.challenges[i].time < oldestTime)
+ {
+ oldestTime = svs.challenges[i].time;
+ oldest = i;
+ }
+ }
+
+ if (i == MAX_CHALLENGES)
+ {
+ // overwrite the oldest
+ svs.challenges[oldest].challenge = rand() & 0x7fff;
+ svs.challenges[oldest].adr = net_from;
+ svs.challenges[oldest].time = curtime;
+ i = oldest;
+ }
+
+ // send it back
+ Netchan_OutOfBandPrint (NS_SERVER, net_from, "challenge %i", svs.challenges[i].challenge);
+}
+
+/*
+==================
+SVC_DirectConnect
+
+A connection request that did not come from the master
+==================
+*/
+void SVC_DirectConnect (void)
+{
+ char userinfo[MAX_INFO_STRING];
+ netadr_t adr;
+ int i;
+ client_t *cl, *newcl;
+ client_t temp;
+ edict_t *ent;
+ int edictnum;
+ int version;
+ int qport;
+ int challenge;
+
+ adr = net_from;
+
+ Com_DPrintf ("SVC_DirectConnect ()\n");
+
+ version = atoi(Cmd_Argv(1));
+ if (version != PROTOCOL_VERSION)
+ {
+ Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nServer is version %4.2f.\n", VERSION);
+ Com_DPrintf (" rejected connect from version %i\n", version);
+ return;
+ }
+
+ qport = atoi(Cmd_Argv(2));
+
+ challenge = atoi(Cmd_Argv(3));
+
+ strncpy (userinfo, Cmd_Argv(4), sizeof(userinfo)-1);
+ userinfo[sizeof(userinfo) - 1] = 0;
+
+ // force the IP key/value pair so the game can filter based on ip
+ Info_SetValueForKey (userinfo, "ip", NET_AdrToString(net_from));
+
+ // attractloop servers are ONLY for local clients
+ if (sv.attractloop)
+ {
+ if (!NET_IsLocalAddress (adr))
+ {
+ Com_Printf ("Remote connect in attract loop. Ignored.\n");
+ Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nConnection refused.\n");
+ return;
+ }
+ }
+
+ // see if the challenge is valid
+ if (!NET_IsLocalAddress (adr))
+ {
+ for (i=0 ; i<MAX_CHALLENGES ; i++)
+ {
+ if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
+ {
+ if (challenge == svs.challenges[i].challenge)
+ break; // good
+ Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nBad challenge.\n");
+ return;
+ }
+ }
+ if (i == MAX_CHALLENGES)
+ {
+ Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nNo challenge for address.\n");
+ return;
+ }
+ }
+
+ newcl = &temp;
+ memset (newcl, 0, sizeof(client_t));
+
+ // if there is already a slot for this ip, reuse it
+ for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
+ {
+ if (cl->state == cs_free)
+ continue;
+ if (NET_CompareBaseAdr (adr, cl->netchan.remote_address)
+ && ( cl->netchan.qport == qport
+ || adr.port == cl->netchan.remote_address.port ) )
+ {
+ if (!NET_IsLocalAddress (adr) && (svs.realtime - cl->lastconnect) < ((int)sv_reconnect_limit->value * 1000))
+ {
+ Com_DPrintf ("%s:reconnect rejected : too soon\n", NET_AdrToString (adr));
+ return;
+ }
+ Com_Printf ("%s:reconnect\n", NET_AdrToString (adr));
+ newcl = cl;
+ goto gotnewcl;
+ }
+ }
+
+ // find a client slot
+ newcl = NULL;
+ for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
+ {
+ if (cl->state == cs_free)
+ {
+ newcl = cl;
+ break;
+ }
+ }
+ if (!newcl)
+ {
+ Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nServer is full.\n");
+ Com_DPrintf ("Rejected a connection.\n");
+ return;
+ }
+
+gotnewcl:
+ // build a new connection
+ // accept the new client
+ // this is the only place a client_t is ever initialized
+ *newcl = temp;
+ sv_client = newcl;
+ edictnum = (newcl-svs.clients)+1;
+ ent = EDICT_NUM(edictnum);
+ newcl->edict = ent;
+ newcl->challenge = challenge; // save challenge for checksumming
+
+ // get the game a chance to reject this connection or modify the userinfo
+ if (!(ge->ClientConnect (ent, userinfo)))
+ {
+ if (*Info_ValueForKey (userinfo, "rejmsg"))
+ Netchan_OutOfBandPrint (NS_SERVER, adr, "print\n%s\nConnection refused.\n",
+ Info_ValueForKey (userinfo, "rejmsg"));
+ else
+ Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nConnection refused.\n" );
+ Com_DPrintf ("Game rejected a connection.\n");
+ return;
+ }
+
+ // parse some info from the info strings
+ strncpy (newcl->userinfo, userinfo, sizeof(newcl->userinfo)-1);
+ SV_UserinfoChanged (newcl);
+
+ // send the connect packet to the client
+ Netchan_OutOfBandPrint (NS_SERVER, adr, "client_connect");
+
+ Netchan_Setup (NS_SERVER, &newcl->netchan , adr, qport);
+
+ newcl->state = cs_connected;
+
+ SZ_Init (&newcl->datagram, newcl->datagram_buf, sizeof(newcl->datagram_buf) );
+ newcl->datagram.allowoverflow = true;
+ newcl->lastmessage = svs.realtime; // don't timeout
+ newcl->lastconnect = svs.realtime;
+}
+
+int Rcon_Validate (void)
+{
+ if (!strlen (rcon_password->string))
+ return 0;
+
+ if (strcmp (Cmd_Argv(1), rcon_password->string) )
+ return 0;
+
+ return 1;
+}
+
+/*
+===============
+SVC_RemoteCommand
+
+A client issued an rcon command.
+Shift down the remaining args
+Redirect all printfs
+===============
+*/
+void SVC_RemoteCommand (void)
+{
+ int i;
+ char remaining[1024];
+
+ i = Rcon_Validate ();
+
+ if (i == 0)
+ Com_Printf ("Bad rcon from %s:\n%s\n", NET_AdrToString (net_from), net_message.data+4);
+ else
+ Com_Printf ("Rcon from %s:\n%s\n", NET_AdrToString (net_from), net_message.data+4);
+
+ Com_BeginRedirect (RD_PACKET, sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect);
+
+ if (!Rcon_Validate ())
+ {
+ Com_Printf ("Bad rcon_password.\n");
+ }
+ else
+ {
+ remaining[0] = 0;
+
+ for (i=2 ; i<Cmd_Argc() ; i++)
+ {
+ strcat (remaining, Cmd_Argv(i) );
+ strcat (remaining, " ");
+ }
+
+ Cmd_ExecuteString (remaining);
+ }
+
+ Com_EndRedirect ();
+}
+
+/*
+=================
+SV_ConnectionlessPacket
+
+A connectionless packet has four leading 0xff
+characters to distinguish it from a game channel.
+Clients that are in the game can still send
+connectionless packets.
+=================
+*/
+void SV_ConnectionlessPacket (void)
+{
+ char *s;
+ char *c;
+
+ MSG_BeginReading (&net_message);
+ MSG_ReadLong (&net_message); // skip the -1 marker
+
+ s = MSG_ReadStringLine (&net_message);
+
+ Cmd_TokenizeString (s, false);
+
+ c = Cmd_Argv(0);
+ Com_DPrintf ("Packet %s : %s\n", NET_AdrToString(net_from), c);
+
+ if (!strcmp(c, "ping"))
+ SVC_Ping ();
+ else if (!strcmp(c, "ack"))
+ SVC_Ack ();
+ else if (!strcmp(c,"status"))
+ SVC_Status ();
+ else if (!strcmp(c,"info"))
+ SVC_Info ();
+ else if (!strcmp(c,"getchallenge"))
+ SVC_GetChallenge ();
+ else if (!strcmp(c,"connect"))
+ SVC_DirectConnect ();
+ else if (!strcmp(c, "rcon"))
+ SVC_RemoteCommand ();
+ else
+ Com_Printf ("bad connectionless packet from %s:\n%s\n"
+ , NET_AdrToString (net_from), s);
+}
+
+
+//============================================================================
+
+/*
+===================
+SV_CalcPings
+
+Updates the cl->ping variables
+===================
+*/
+void SV_CalcPings (void)
+{
+ int i, j;
+ client_t *cl;
+ int total, count;
+
+ for (i=0 ; i<maxclients->value ; i++)
+ {
+ cl = &svs.clients[i];
+ if (cl->state != cs_spawned )
+ continue;
+
+/*
+ if (cl->lastframe > 0)
+ cl->frame_latency[sv.framenum&(LATENCY_COUNTS-1)] = sv.framenum - cl->lastframe + 1;
+ else
+ cl->frame_latency[sv.framenum&(LATENCY_COUNTS-1)] = 0;
+*/
+
+ total = 0;
+ count = 0;
+ for (j=0 ; j<LATENCY_COUNTS ; j++)
+ {
+ if (cl->frame_latency[j] > 0)
+ {
+ count++;
+ total += cl->frame_latency[j];
+ }
+ }
+ if (!count)
+ cl->ping = 0;
+ else
+ //cl->ping = total*100/count - 100;
+ cl->ping = total / count;
+
+ // let the game dll know about the ping
+ cl->edict->client->ping = cl->ping;
+ }
+}
+
+
+/*
+===================
+SV_GiveMsec
+
+Every few frames, gives all clients an allotment of milliseconds
+for their command moves. If they exceed it, assume cheating.
+===================
+*/
+void SV_GiveMsec (void)
+{
+ int i;
+ client_t *cl;
+
+ if (sv.framenum & 15)
+ return;
+
+ for (i=0 ; i<maxclients->value ; i++)
+ {
+ cl = &svs.clients[i];
+ if (cl->state == cs_free )
+ continue;
+
+ cl->commandMsec = 1800; // 1600 + some slop
+ }
+}
+
+
+/*
+=================
+SV_ReadPackets
+=================
+*/
+void SV_ReadPackets (void)
+{
+ int i;
+ client_t *cl;
+ int qport;
+
+ while (NET_GetPacket (NS_SERVER, &net_from, &net_message))
+ {
+ // check for connectionless packet (0xffffffff) first
+ if (*(int *)net_message.data == -1)
+ {
+ SV_ConnectionlessPacket ();
+ continue;
+ }
+
+ // read the qport out of the message so we can fix up
+ // stupid address translating routers
+ MSG_BeginReading (&net_message);
+ MSG_ReadLong (&net_message); // sequence number
+ MSG_ReadLong (&net_message); // sequence number
+ qport = MSG_ReadShort (&net_message) & 0xffff;
+
+ // check for packets from connected clients
+ for (i=0, cl=svs.clients ; i<maxclients->value ; i++,cl++)
+ {
+ if (cl->state == cs_free)
+ continue;
+ if (!NET_CompareBaseAdr (net_from, cl->netchan.remote_address))
+ continue;
+ if (cl->netchan.qport != qport)
+ continue;
+ if (cl->netchan.remote_address.port != net_from.port)
+ {
+ Com_Printf ("SV_ReadPackets: fixing up a translated port\n");
+ cl->netchan.remote_address.port = net_from.port;
+ }
+
+ if (Netchan_Process(&cl->netchan, &net_message))
+ { // this is a valid, sequenced packet, so process it
+ if (cl->state != cs_zombie)
+ {
+ cl->lastmessage = svs.realtime; // don't timeout
+ SV_ExecuteClientMessage (cl);
+ }
+ }
+ break;
+ }
+
+ if (i != maxclients->value)
+ continue;
+ }
+}
+
+/*
+==================
+SV_CheckTimeouts
+
+If a packet has not been received from a client for timeout->value
+seconds, drop the conneciton. Server frames are used instead of
+realtime to avoid dropping the local client while debugging.
+
+When a client is normally dropped, the client_t goes into a zombie state
+for a few seconds to make sure any final reliable message gets resent
+if necessary
+==================
+*/
+void SV_CheckTimeouts (void)
+{
+ int i;
+ client_t *cl;
+ int droppoint;
+ int zombiepoint;
+
+ droppoint = svs.realtime - 1000*timeout->value;
+ zombiepoint = svs.realtime - 1000*zombietime->value;
+
+ for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
+ {
+ // message times may be wrong across a changelevel
+ if (cl->lastmessage > svs.realtime)
+ cl->lastmessage = svs.realtime;
+
+ if (cl->state == cs_zombie
+ && cl->lastmessage < zombiepoint)
+ {
+ cl->state = cs_free; // can now be reused
+ continue;
+ }
+ if ( (cl->state == cs_connected || cl->state == cs_spawned)
+ && cl->lastmessage < droppoint)
+ {
+ SV_BroadcastPrintf (PRINT_HIGH, "%s timed out\n", cl->name);
+ SV_DropClient (cl);
+ cl->state = cs_free; // don't bother with zombie state
+ }
+ }
+}
+
+/*
+================
+SV_PrepWorldFrame
+
+This has to be done before the world logic, because
+player processing happens outside RunWorldFrame
+================
+*/
+void SV_PrepWorldFrame (void)
+{
+ edict_t *ent;
+ int i;
+
+ for (i=0 ; i<ge->num_edicts ; i++)
+ {
+ ent = EDICT_NUM(i);
+ // events only last for a single message
+ ent->s.event = 0;
+ }
+
+}
+
+
+/*
+=================
+SV_RunGameFrame
+=================
+*/
+void SV_RunGameFrame (void)
+{
+ if (host_speeds->value)
+ time_before_game = Sys_Milliseconds ();
+
+ // we always need to bump framenum, even if we
+ // don't run the world, otherwise the delta
+ // compression can get confused when a client
+ // has the "current" frame
+ sv.framenum++;
+ sv.time = sv.framenum*100;
+
+ // don't run if paused
+ if (!sv_paused->value || maxclients->value > 1)
+ {
+ ge->RunFrame ();
+
+ // never get more than one tic behind
+ if (sv.time < svs.realtime)
+ {
+ if (sv_showclamp->value)
+ Com_Printf ("sv highclamp\n");
+ svs.realtime = sv.time;
+ }
+ }
+
+ if (host_speeds->value)
+ time_after_game = Sys_Milliseconds ();
+
+}
+
+/*
+==================
+SV_Frame
+
+==================
+*/
+void SV_Frame (int msec)
+{
+ time_before_game = time_after_game = 0;
+
+ // if server is not active, do nothing
+ if (!svs.initialized)
+ return;
+
+ svs.realtime += msec;
+
+ // keep the random time dependent
+ rand ();
+
+ // check timeouts
+ SV_CheckTimeouts ();
+
+ // get packets from clients
+ SV_ReadPackets ();
+
+ // move autonomous things around if enough time has passed
+ if (!sv_timedemo->value && svs.realtime < sv.time)
+ {
+ // never let the time get too far off
+ if (sv.time - svs.realtime > 100)
+ {
+ if (sv_showclamp->value)
+ Com_Printf ("sv lowclamp\n");
+ svs.realtime = sv.time - 100;
+ }
+ NET_Sleep(sv.time - svs.realtime);
+ return;
+ }
+
+ // update ping based on the last known frame from all clients
+ SV_CalcPings ();
+
+ // give the clients some timeslices
+ SV_GiveMsec ();
+
+ // let everything in the world think and move
+ SV_RunGameFrame ();
+
+ // send messages back to the clients that had packets read this frame
+ SV_SendClientMessages ();
+
+ // save the entire world state if recording a serverdemo
+ SV_RecordDemoMessage ();
+
+ // send a heartbeat to the master if needed
+ Master_Heartbeat ();
+
+ // clear teleport flags, etc for next frame
+ SV_PrepWorldFrame ();
+
+}
+
+//============================================================================
+
+/*
+================
+Master_Heartbeat
+
+Send a message to the master every few minutes to
+let it know we are alive, and log information
+================
+*/
+#define HEARTBEAT_SECONDS 300
+void Master_Heartbeat (void)
+{
+ char *string;
+ int i;
+
+
+ if (!dedicated->value)
+ return; // only dedicated servers send heartbeats
+
+ if (!public_server->value)
+ return; // a private dedicated game
+
+ // check for time wraparound
+ if (svs.last_heartbeat > svs.realtime)
+ svs.last_heartbeat = svs.realtime;
+
+ if (svs.realtime - svs.last_heartbeat < HEARTBEAT_SECONDS*1000)
+ return; // not time to send yet
+
+ svs.last_heartbeat = svs.realtime;
+
+ // send the same string that we would give for a status OOB command
+ string = SV_StatusString();
+
+ // send to group master
+ for (i=0 ; i<MAX_MASTERS ; i++)
+ if (master_adr[i].port)
+ {
+ Com_Printf ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i]));
+ Netchan_OutOfBandPrint (NS_SERVER, master_adr[i], "heartbeat\n%s", string);
+ }
+}
+
+/*
+=================
+Master_Shutdown
+
+Informs all masters that this server is going down
+=================
+*/
+void Master_Shutdown (void)
+{
+ int i;
+
+ if (!dedicated->value)
+ return; // only dedicated servers send heartbeats
+
+ if (!public_server->value)
+ return; // a private dedicated game
+
+ // send to group master
+ for (i=0 ; i<MAX_MASTERS ; i++)
+ if (master_adr[i].port)
+ {
+ if (i > 0)
+ Com_Printf ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i]));
+ Netchan_OutOfBandPrint (NS_SERVER, master_adr[i], "shutdown");
+ }
+}
+
+//============================================================================
+
+
+/*
+=================
+SV_UserinfoChanged
+
+Pull specific info from a newly changed userinfo string
+into a more C freindly form.
+=================
+*/
+void SV_UserinfoChanged (client_t *cl)
+{
+ char *val;
+ int i;
+
+ // call prog code to allow overrides
+ ge->ClientUserinfoChanged (cl->edict, cl->userinfo);
+
+ // name for C code
+ strncpy (cl->name, Info_ValueForKey (cl->userinfo, "name"), sizeof(cl->name)-1);
+ // mask off high bit
+ for (i=0 ; i<sizeof(cl->name) ; i++)
+ cl->name[i] &= 127;
+
+ // rate command
+ val = Info_ValueForKey (cl->userinfo, "rate");
+ if (strlen(val))
+ {
+ i = atoi(val);
+ cl->rate = i;
+ if (cl->rate < 100)
+ cl->rate = 100;
+ if (cl->rate > 15000)
+ cl->rate = 15000;
+ }
+ else
+ cl->rate = 5000;
+
+ // msg command
+ val = Info_ValueForKey (cl->userinfo, "msg");
+ if (strlen(val))
+ {
+ cl->messagelevel = atoi(val);
+ }
+
+}
+
+
+//============================================================================
+
+/*
+===============
+SV_Init
+
+Only called at quake2.exe startup, not for each game
+===============
+*/
+void SV_Init (void)
+{
+ SV_InitOperatorCommands ();
+
+ rcon_password = Cvar_Get ("rcon_password", "", 0);
+ Cvar_Get ("skill", "1", 0);
+ Cvar_Get ("deathmatch", "0", CVAR_LATCH);
+ Cvar_Get ("coop", "0", CVAR_LATCH);
+ Cvar_Get ("dmflags", va("%i", DF_INSTANT_ITEMS), CVAR_SERVERINFO);
+ Cvar_Get ("fraglimit", "0", CVAR_SERVERINFO);
+ Cvar_Get ("timelimit", "0", CVAR_SERVERINFO);
+ Cvar_Get ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH);
+ Cvar_Get ("protocol", va("%i", PROTOCOL_VERSION), CVAR_SERVERINFO|CVAR_NOSET);;
+ maxclients = Cvar_Get ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);
+ hostname = Cvar_Get ("hostname", "noname", CVAR_SERVERINFO | CVAR_ARCHIVE);
+ timeout = Cvar_Get ("timeout", "125", 0);
+ zombietime = Cvar_Get ("zombietime", "2", 0);
+ sv_showclamp = Cvar_Get ("showclamp", "0", 0);
+ sv_paused = Cvar_Get ("paused", "0", 0);
+ sv_timedemo = Cvar_Get ("timedemo", "0", 0);
+ sv_enforcetime = Cvar_Get ("sv_enforcetime", "0", 0);
+ allow_download = Cvar_Get ("allow_download", "0", CVAR_ARCHIVE);
+ allow_download_players = Cvar_Get ("allow_download_players", "0", CVAR_ARCHIVE);
+ allow_download_models = Cvar_Get ("allow_download_models", "1", CVAR_ARCHIVE);
+ allow_download_sounds = Cvar_Get ("allow_download_sounds", "1", CVAR_ARCHIVE);
+ allow_download_maps = Cvar_Get ("allow_download_maps", "1", CVAR_ARCHIVE);
+
+ sv_noreload = Cvar_Get ("sv_noreload", "0", 0);
+
+ sv_airaccelerate = Cvar_Get("sv_airaccelerate", "0", CVAR_LATCH);
+
+ public_server = Cvar_Get ("public", "0", 0);
+
+ sv_reconnect_limit = Cvar_Get ("sv_reconnect_limit", "3", CVAR_ARCHIVE);
+
+ SZ_Init (&net_message, net_message_buffer, sizeof(net_message_buffer));
+}
+
+/*
+==================
+SV_FinalMessage
+
+Used by SV_Shutdown to send a final message to all
+connected clients before the server goes down. The messages are sent immediately,
+not just stuck on the outgoing message list, because the server is going
+to totally exit after returning from this function.
+==================
+*/
+void SV_FinalMessage (char *message, qboolean reconnect)
+{
+ int i;
+ client_t *cl;
+
+ SZ_Clear (&net_message);
+ MSG_WriteByte (&net_message, svc_print);
+ MSG_WriteByte (&net_message, PRINT_HIGH);
+ MSG_WriteString (&net_message, message);
+
+ if (reconnect)
+ MSG_WriteByte (&net_message, svc_reconnect);
+ else
+ MSG_WriteByte (&net_message, svc_disconnect);
+
+ // send it twice
+ // stagger the packets to crutch operating system limited buffers
+
+ for (i=0, cl = svs.clients ; i<maxclients->value ; i++, cl++)
+ if (cl->state >= cs_connected)
+ Netchan_Transmit (&cl->netchan, net_message.cursize
+ , net_message.data);
+
+ for (i=0, cl = svs.clients ; i<maxclients->value ; i++, cl++)
+ if (cl->state >= cs_connected)
+ Netchan_Transmit (&cl->netchan, net_message.cursize
+ , net_message.data);
+}
+
+
+
+/*
+================
+SV_Shutdown
+
+Called when each game quits,
+before Sys_Quit or Sys_Error
+================
+*/
+void SV_Shutdown (char *finalmsg, qboolean reconnect)
+{
+ if (svs.clients)
+ SV_FinalMessage (finalmsg, reconnect);
+
+ Master_Shutdown ();
+ SV_ShutdownGameProgs ();
+
+ // free current level
+ if (sv.demofile)
+ fclose (sv.demofile);
+ memset (&sv, 0, sizeof(sv));
+ Com_SetServerState (sv.state);
+
+ // free server static data
+ if (svs.clients)
+ Z_Free (svs.clients);
+ if (svs.client_entities)
+ Z_Free (svs.client_entities);
+ if (svs.demofile)
+ fclose (svs.demofile);
+ memset (&svs, 0, sizeof(svs));
+}
+
--- /dev/null
+++ b/sv_send.c
@@ -1,0 +1,548 @@
+// sv_main.c -- server main program
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+/*
+=============================================================================
+
+Com_Printf redirection
+
+=============================================================================
+*/
+
+char sv_outputbuf[SV_OUTPUTBUF_LENGTH];
+
+void SV_FlushRedirect (int sv_redirected, char *outputbuf)
+{
+ if (sv_redirected == RD_PACKET)
+ {
+ Netchan_OutOfBandPrint (NS_SERVER, net_from, "print\n%s", outputbuf);
+ }
+ else if (sv_redirected == RD_CLIENT)
+ {
+ MSG_WriteByte (&sv_client->netchan.message, svc_print);
+ MSG_WriteByte (&sv_client->netchan.message, PRINT_HIGH);
+ MSG_WriteString (&sv_client->netchan.message, outputbuf);
+ }
+}
+
+
+/*
+=============================================================================
+
+EVENT MESSAGES
+
+=============================================================================
+*/
+
+
+/*
+=================
+SV_ClientPrintf
+
+Sends text across to be displayed if the level passes
+=================
+*/
+void SV_ClientPrintf (client_t *cl, int level, char *fmt, ...)
+{
+ va_list argptr;
+ char string[1024];
+
+ if (level < cl->messagelevel)
+ return;
+
+ va_start (argptr,fmt);
+ vsprintf (string, fmt,argptr);
+ va_end (argptr);
+
+ MSG_WriteByte (&cl->netchan.message, svc_print);
+ MSG_WriteByte (&cl->netchan.message, level);
+ MSG_WriteString (&cl->netchan.message, string);
+}
+
+/*
+=================
+SV_BroadcastPrintf
+
+Sends text to all active clients
+=================
+*/
+void SV_BroadcastPrintf (int level, char *fmt, ...)
+{
+ va_list argptr;
+ char string[2048];
+ client_t *cl;
+ int i;
+
+ va_start (argptr,fmt);
+ vsprintf (string, fmt,argptr);
+ va_end (argptr);
+
+ // echo to console
+ if (dedicated->value)
+ {
+ char copy[1024];
+ int i;
+
+ // mask off high bits
+ for (i=0 ; i<1023 && string[i] ; i++)
+ copy[i] = string[i]&127;
+ copy[i] = 0;
+ Com_Printf ("%s", copy);
+ }
+
+ for (i=0, cl = svs.clients ; i<maxclients->value; i++, cl++)
+ {
+ if (level < cl->messagelevel)
+ continue;
+ if (cl->state != cs_spawned)
+ continue;
+ MSG_WriteByte (&cl->netchan.message, svc_print);
+ MSG_WriteByte (&cl->netchan.message, level);
+ MSG_WriteString (&cl->netchan.message, string);
+ }
+}
+
+/*
+=================
+SV_BroadcastCommand
+
+Sends text to all active clients
+=================
+*/
+void SV_BroadcastCommand (char *fmt, ...)
+{
+ va_list argptr;
+ char string[1024];
+
+ if (!sv.state)
+ return;
+ va_start (argptr,fmt);
+ vsprintf (string, fmt,argptr);
+ va_end (argptr);
+
+ MSG_WriteByte (&sv.multicast, svc_stufftext);
+ MSG_WriteString (&sv.multicast, string);
+ SV_Multicast (NULL, MULTICAST_ALL_R);
+}
+
+
+/*
+=================
+SV_Multicast
+
+Sends the contents of sv.multicast to a subset of the clients,
+then clears sv.multicast.
+
+MULTICAST_ALL same as broadcast (origin can be NULL)
+MULTICAST_PVS send to clients potentially visible from org
+MULTICAST_PHS send to clients potentially hearable from org
+=================
+*/
+void SV_Multicast (vec3_t origin, multicast_t to)
+{
+ client_t *client;
+ byte *mask;
+ int leafnum, cluster;
+ int j;
+ qboolean reliable;
+ int area1, area2;
+
+ reliable = false;
+
+ if (to != MULTICAST_ALL_R && to != MULTICAST_ALL)
+ {
+ leafnum = CM_PointLeafnum (origin);
+ area1 = CM_LeafArea (leafnum);
+ }
+ else
+ area1 = 0; // just to avoid compiler warnings
+
+ // if doing a serverrecord, store everything
+ if (svs.demofile)
+ SZ_Write (&svs.demo_multicast, sv.multicast.data, sv.multicast.cursize);
+
+ switch (to)
+ {
+ case MULTICAST_ALL_R:
+ reliable = true; // intentional fallthrough
+ case MULTICAST_ALL:
+ mask = NULL;
+ break;
+
+ case MULTICAST_PHS_R:
+ reliable = true; // intentional fallthrough
+ case MULTICAST_PHS:
+ leafnum = CM_PointLeafnum (origin);
+ cluster = CM_LeafCluster (leafnum);
+ mask = CM_ClusterPHS (cluster);
+ break;
+
+ case MULTICAST_PVS_R:
+ reliable = true; // intentional fallthrough
+ case MULTICAST_PVS:
+ leafnum = CM_PointLeafnum (origin);
+ cluster = CM_LeafCluster (leafnum);
+ mask = CM_ClusterPVS (cluster);
+ break;
+
+ default:
+ mask = NULL;
+ Com_Error (ERR_FATAL, "SV_Multicast: bad to:%i", to);
+ }
+
+ // send the data to all relevent clients
+ for (j = 0, client = svs.clients; j < maxclients->value; j++, client++)
+ {
+ if (client->state == cs_free || client->state == cs_zombie)
+ continue;
+ if (client->state != cs_spawned && !reliable)
+ continue;
+
+ if (mask)
+ {
+ leafnum = CM_PointLeafnum (client->edict->s.origin);
+ cluster = CM_LeafCluster (leafnum);
+ area2 = CM_LeafArea (leafnum);
+ if (!CM_AreasConnected (area1, area2))
+ continue;
+ if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
+ continue;
+ }
+
+ if (reliable)
+ SZ_Write (&client->netchan.message, sv.multicast.data, sv.multicast.cursize);
+ else
+ SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize);
+ }
+
+ SZ_Clear (&sv.multicast);
+}
+
+
+/*
+==================
+SV_StartSound
+
+Each entity can have eight independant sound sources, like voice,
+weapon, feet, etc.
+
+If cahnnel & 8, the sound will be sent to everyone, not just
+things in the PHS.
+
+FIXME: if entity isn't in PHS, they must be forced to be sent or
+have the origin explicitly sent.
+
+Channel 0 is an auto-allocate channel, the others override anything
+already running on that entity/channel pair.
+
+An attenuation of 0 will play full volume everywhere in the level.
+Larger attenuations will drop off. (max 4 attenuation)
+
+Timeofs can range from 0.0 to 0.1 to cause sounds to be started
+later in the frame than they normally would.
+
+If origin is NULL, the origin is determined from the entity origin
+or the midpoint of the entity box for bmodels.
+==================
+*/
+void SV_StartSound (vec3_t origin, edict_t *entity, int channel,
+ int soundindex, float volume,
+ float attenuation, float timeofs)
+{
+ int sendchan;
+ int flags;
+ int i;
+ int ent;
+ vec3_t origin_v;
+ qboolean use_phs;
+
+ if (volume < 0 || volume > 1.0)
+ Com_Error (ERR_FATAL, "SV_StartSound: volume = %f", volume);
+
+ if (attenuation < 0 || attenuation > 4)
+ Com_Error (ERR_FATAL, "SV_StartSound: attenuation = %f", attenuation);
+
+// if (channel < 0 || channel > 15)
+// Com_Error (ERR_FATAL, "SV_StartSound: channel = %i", channel);
+
+ if (timeofs < 0 || timeofs > 0.255)
+ Com_Error (ERR_FATAL, "SV_StartSound: timeofs = %f", timeofs);
+
+ ent = NUM_FOR_EDICT(entity);
+
+ if (channel & 8) // no PHS flag
+ {
+ use_phs = false;
+ channel &= 7;
+ }
+ else
+ use_phs = true;
+
+ sendchan = (ent<<3) | (channel&7);
+
+ flags = 0;
+ if (volume != DEFAULT_SOUND_PACKET_VOLUME)
+ flags |= SND_VOLUME;
+ if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
+ flags |= SND_ATTENUATION;
+
+ // the client doesn't know that bmodels have weird origins
+ // the origin can also be explicitly set
+ if ( (entity->svflags & SVF_NOCLIENT)
+ || (entity->solid == SOLID_BSP)
+ || origin )
+ flags |= SND_POS;
+
+ // always send the entity number for channel overrides
+ flags |= SND_ENT;
+
+ if (timeofs)
+ flags |= SND_OFFSET;
+
+ // use the entity origin unless it is a bmodel or explicitly specified
+ if (!origin)
+ {
+ origin = origin_v;
+ if (entity->solid == SOLID_BSP)
+ {
+ for (i=0 ; i<3 ; i++)
+ origin_v[i] = entity->s.origin[i]+0.5*(entity->mins[i]+entity->maxs[i]);
+ }
+ else
+ {
+ VectorCopy (entity->s.origin, origin_v);
+ }
+ }
+
+ MSG_WriteByte (&sv.multicast, svc_sound);
+ MSG_WriteByte (&sv.multicast, flags);
+ MSG_WriteByte (&sv.multicast, soundindex);
+
+ if (flags & SND_VOLUME)
+ MSG_WriteByte (&sv.multicast, volume*255);
+ if (flags & SND_ATTENUATION)
+ MSG_WriteByte (&sv.multicast, attenuation*64);
+ if (flags & SND_OFFSET)
+ MSG_WriteByte (&sv.multicast, timeofs*1000);
+
+ if (flags & SND_ENT)
+ MSG_WriteShort (&sv.multicast, sendchan);
+
+ if (flags & SND_POS)
+ MSG_WritePos (&sv.multicast, origin);
+
+ // if the sound doesn't attenuate,send it to everyone
+ // (global radio chatter, voiceovers, etc)
+ if (attenuation == ATTN_NONE)
+ use_phs = false;
+
+ if (channel & CHAN_RELIABLE)
+ {
+ if (use_phs)
+ SV_Multicast (origin, MULTICAST_PHS_R);
+ else
+ SV_Multicast (origin, MULTICAST_ALL_R);
+ }
+ else
+ {
+ if (use_phs)
+ SV_Multicast (origin, MULTICAST_PHS);
+ else
+ SV_Multicast (origin, MULTICAST_ALL);
+ }
+}
+
+
+/*
+===============================================================================
+
+FRAME UPDATES
+
+===============================================================================
+*/
+
+
+
+/*
+=======================
+SV_SendClientDatagram
+=======================
+*/
+qboolean SV_SendClientDatagram (client_t *client)
+{
+ byte msg_buf[MAX_MSGLEN];
+ sizebuf_t msg;
+
+ SV_BuildClientFrame (client);
+
+ SZ_Init (&msg, msg_buf, sizeof(msg_buf));
+ msg.allowoverflow = true;
+
+ // send over all the relevant entity_state_t
+ // and the player_state_t
+ SV_WriteFrameToClient (client, &msg);
+
+ // copy the accumulated multicast datagram
+ // for this client out to the message
+ // it is necessary for this to be after the WriteEntities
+ // so that entity references will be current
+ if (client->datagram.overflowed)
+ Com_Printf ("WARNING: datagram overflowed for %s\n", client->name);
+ else
+ SZ_Write (&msg, client->datagram.data, client->datagram.cursize);
+ SZ_Clear (&client->datagram);
+
+ if (msg.overflowed)
+ { // must have room left for the packet header
+ Com_Printf ("WARNING: msg overflowed for %s\n", client->name);
+ SZ_Clear (&msg);
+ }
+
+ // send the datagram
+ Netchan_Transmit (&client->netchan, msg.cursize, msg.data);
+
+ // record the size for rate estimation
+ client->message_size[sv.framenum % RATE_MESSAGES] = msg.cursize;
+
+ return true;
+}
+
+
+/*
+==================
+SV_DemoCompleted
+==================
+*/
+void SV_DemoCompleted (void)
+{
+ if (sv.demofile)
+ {
+ fclose (sv.demofile);
+ sv.demofile = NULL;
+ }
+ SV_Nextserver ();
+}
+
+
+/*
+=======================
+SV_RateDrop
+
+Returns true if the client is over its current
+bandwidth estimation and should not be sent another packet
+=======================
+*/
+qboolean SV_RateDrop (client_t *c)
+{
+ int total;
+ int i;
+
+ // never drop over the loopback
+ if (c->netchan.remote_address.type == NA_LOOPBACK)
+ return false;
+
+ total = 0;
+
+ for (i = 0 ; i < RATE_MESSAGES ; i++)
+ {
+ total += c->message_size[i];
+ }
+
+ if (total > c->rate)
+ {
+ c->surpressCount++;
+ c->message_size[sv.framenum % RATE_MESSAGES] = 0;
+ return true;
+ }
+
+ return false;
+}
+
+/*
+=======================
+SV_SendClientMessages
+=======================
+*/
+void SV_SendClientMessages (void)
+{
+ int i;
+ client_t *c;
+ int msglen;
+ byte msgbuf[MAX_MSGLEN];
+ int r;
+
+ msglen = 0;
+
+ // read the next demo message if needed
+ if (sv.state == ss_demo && sv.demofile)
+ {
+ if (sv_paused->value)
+ msglen = 0;
+ else
+ {
+ // get the next message
+ r = fread (&msglen, 4, 1, sv.demofile);
+ if (r != 1)
+ {
+ SV_DemoCompleted ();
+ return;
+ }
+ msglen = LittleLong (msglen);
+ if (msglen == -1)
+ {
+ SV_DemoCompleted ();
+ return;
+ }
+ if (msglen > MAX_MSGLEN)
+ Com_Error (ERR_DROP, "SV_SendClientMessages: msglen > MAX_MSGLEN");
+ r = fread (msgbuf, msglen, 1, sv.demofile);
+ if (r != 1)
+ {
+ SV_DemoCompleted ();
+ return;
+ }
+ }
+ }
+
+ // send a message to each connected client
+ for (i=0, c = svs.clients ; i<maxclients->value; i++, c++)
+ {
+ if (!c->state)
+ continue;
+ // if the reliable message overflowed,
+ // drop the client
+ if (c->netchan.message.overflowed)
+ {
+ SZ_Clear (&c->netchan.message);
+ SZ_Clear (&c->datagram);
+ SV_BroadcastPrintf (PRINT_HIGH, "%s overflowed\n", c->name);
+ SV_DropClient (c);
+ }
+
+ if (sv.state == ss_cinematic
+ || sv.state == ss_demo
+ || sv.state == ss_pic
+ )
+ Netchan_Transmit (&c->netchan, msglen, msgbuf);
+ else if (c->state == cs_spawned)
+ {
+ // don't overrun bandwidth
+ if (SV_RateDrop (c))
+ continue;
+
+ SV_SendClientDatagram (c);
+ }
+ else
+ {
+ // just update reliable if needed
+ if (c->netchan.message.cursize || curtime - c->netchan.last_sent > 1000 )
+ Netchan_Transmit (&c->netchan, 0, NULL);
+ }
+ }
+}
+
--- /dev/null
+++ b/sv_user.c
@@ -1,0 +1,649 @@
+// sv_user.c -- server code for moving users
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+edict_t *sv_player;
+
+/*
+============================================================
+
+USER STRINGCMD EXECUTION
+
+sv_client and sv_player will be valid.
+============================================================
+*/
+
+/*
+==================
+SV_BeginDemoServer
+==================
+*/
+void SV_BeginDemoserver (void)
+{
+ char name[MAX_OSPATH];
+
+ Com_sprintf (name, sizeof(name), "demos/%s", sv.name);
+ FS_FOpenFile (name, &sv.demofile);
+ if (!sv.demofile)
+ Com_Error (ERR_DROP, "Couldn't open %s\n", name);
+}
+
+/*
+================
+SV_New_f
+
+Sends the first message from the server to a connected client.
+This will be sent on the initial connection and upon each server load.
+================
+*/
+void SV_New_f (void)
+{
+ char *gamedir;
+ int playernum;
+ edict_t *ent;
+
+ Com_DPrintf ("New() from %s\n", sv_client->name);
+
+ if (sv_client->state != cs_connected)
+ {
+ Com_Printf ("New not valid -- already spawned\n");
+ return;
+ }
+
+ // demo servers just dump the file message
+ if (sv.state == ss_demo)
+ {
+ SV_BeginDemoserver ();
+ return;
+ }
+
+ //
+ // serverdata needs to go over for all types of servers
+ // to make sure the protocol is right, and to set the gamedir
+ //
+ gamedir = Cvar_VariableString ("gamedir");
+
+ // send the serverdata
+ MSG_WriteByte (&sv_client->netchan.message, svc_serverdata);
+ MSG_WriteLong (&sv_client->netchan.message, PROTOCOL_VERSION);
+ MSG_WriteLong (&sv_client->netchan.message, svs.spawncount);
+ MSG_WriteByte (&sv_client->netchan.message, sv.attractloop);
+ MSG_WriteString (&sv_client->netchan.message, gamedir);
+
+ if (sv.state == ss_cinematic || sv.state == ss_pic)
+ playernum = -1;
+ else
+ playernum = sv_client - svs.clients;
+ MSG_WriteShort (&sv_client->netchan.message, playernum);
+
+ // send full levelname
+ MSG_WriteString (&sv_client->netchan.message, sv.configstrings[CS_NAME]);
+
+ //
+ // game server
+ //
+ if (sv.state == ss_game)
+ {
+ // set up the entity for the client
+ ent = EDICT_NUM(playernum+1);
+ ent->s.number = playernum+1;
+ sv_client->edict = ent;
+ memset (&sv_client->lastcmd, 0, sizeof(sv_client->lastcmd));
+
+ // begin fetching configstrings
+ MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
+ MSG_WriteString (&sv_client->netchan.message, va("cmd configstrings %i 0\n",svs.spawncount) );
+ }
+
+}
+
+/*
+==================
+SV_Configstrings_f
+==================
+*/
+void SV_Configstrings_f (void)
+{
+ int start;
+
+ Com_DPrintf ("Configstrings() from %s\n", sv_client->name);
+
+ if (sv_client->state != cs_connected)
+ {
+ Com_Printf ("configstrings not valid -- already spawned\n");
+ return;
+ }
+
+ // handle the case of a level changing while a client was connecting
+ if ( atoi(Cmd_Argv(1)) != svs.spawncount )
+ {
+ Com_Printf ("SV_Configstrings_f from different level\n");
+ SV_New_f ();
+ return;
+ }
+
+ start = atoi(Cmd_Argv(2));
+
+ // write a packet full of data
+
+ while ( sv_client->netchan.message.cursize < MAX_MSGLEN/2
+ && start < MAX_CONFIGSTRINGS)
+ {
+ if (sv.configstrings[start][0])
+ {
+ MSG_WriteByte (&sv_client->netchan.message, svc_configstring);
+ MSG_WriteShort (&sv_client->netchan.message, start);
+ MSG_WriteString (&sv_client->netchan.message, sv.configstrings[start]);
+ }
+ start++;
+ }
+
+ // send next command
+
+ if (start == MAX_CONFIGSTRINGS)
+ {
+ MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
+ MSG_WriteString (&sv_client->netchan.message, va("cmd baselines %i 0\n",svs.spawncount) );
+ }
+ else
+ {
+ MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
+ MSG_WriteString (&sv_client->netchan.message, va("cmd configstrings %i %i\n",svs.spawncount, start) );
+ }
+}
+
+/*
+==================
+SV_Baselines_f
+==================
+*/
+void SV_Baselines_f (void)
+{
+ int start;
+ entity_state_t nullstate;
+ entity_state_t *base;
+
+ Com_DPrintf ("Baselines() from %s\n", sv_client->name);
+
+ if (sv_client->state != cs_connected)
+ {
+ Com_Printf ("baselines not valid -- already spawned\n");
+ return;
+ }
+
+ // handle the case of a level changing while a client was connecting
+ if ( atoi(Cmd_Argv(1)) != svs.spawncount )
+ {
+ Com_Printf ("SV_Baselines_f from different level\n");
+ SV_New_f ();
+ return;
+ }
+
+ start = atoi(Cmd_Argv(2));
+
+ memset (&nullstate, 0, sizeof(nullstate));
+
+ // write a packet full of data
+
+ while ( sv_client->netchan.message.cursize < MAX_MSGLEN/2
+ && start < MAX_EDICTS)
+ {
+ base = &sv.baselines[start];
+ if (base->modelindex || base->sound || base->effects)
+ {
+ MSG_WriteByte (&sv_client->netchan.message, svc_spawnbaseline);
+ MSG_WriteDeltaEntity (&nullstate, base, &sv_client->netchan.message, true, true);
+ }
+ start++;
+ }
+
+ // send next command
+
+ if (start == MAX_EDICTS)
+ {
+ MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
+ MSG_WriteString (&sv_client->netchan.message, va("precache %i\n", svs.spawncount) );
+ }
+ else
+ {
+ MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
+ MSG_WriteString (&sv_client->netchan.message, va("cmd baselines %i %i\n",svs.spawncount, start) );
+ }
+}
+
+/*
+==================
+SV_Begin_f
+==================
+*/
+void SV_Begin_f (void)
+{
+ Com_DPrintf ("Begin() from %s\n", sv_client->name);
+
+ // handle the case of a level changing while a client was connecting
+ if ( atoi(Cmd_Argv(1)) != svs.spawncount )
+ {
+ Com_Printf ("SV_Begin_f from different level\n");
+ SV_New_f ();
+ return;
+ }
+
+ sv_client->state = cs_spawned;
+
+ // call the game begin function
+ ge->ClientBegin (sv_player);
+
+ Cbuf_InsertFromDefer ();
+}
+
+//=============================================================================
+
+/*
+==================
+SV_NextDownload_f
+==================
+*/
+void SV_NextDownload_f (void)
+{
+ int r;
+ int percent;
+ int size;
+
+ if (!sv_client->download)
+ return;
+
+ r = sv_client->downloadsize - sv_client->downloadcount;
+ if (r > 1024)
+ r = 1024;
+
+ MSG_WriteByte (&sv_client->netchan.message, svc_download);
+ MSG_WriteShort (&sv_client->netchan.message, r);
+
+ sv_client->downloadcount += r;
+ size = sv_client->downloadsize;
+ if (!size)
+ size = 1;
+ percent = sv_client->downloadcount*100/size;
+ MSG_WriteByte (&sv_client->netchan.message, percent);
+ SZ_Write (&sv_client->netchan.message,
+ sv_client->download + sv_client->downloadcount - r, r);
+
+ if (sv_client->downloadcount != sv_client->downloadsize)
+ return;
+
+ FS_FreeFile (sv_client->download);
+ sv_client->download = NULL;
+}
+
+/*
+==================
+SV_BeginDownload_f
+==================
+*/
+void SV_BeginDownload_f(void)
+{
+ char *name;
+ extern cvar_t *allow_download;
+ extern cvar_t *allow_download_players;
+ extern cvar_t *allow_download_models;
+ extern cvar_t *allow_download_sounds;
+ extern cvar_t *allow_download_maps;
+ extern int file_from_pak; // ZOID did file come from pak?
+ int offset = 0;
+
+ name = Cmd_Argv(1);
+
+ if (Cmd_Argc() > 2)
+ offset = atoi(Cmd_Argv(2)); // downloaded offset
+
+ // hacked by zoid to allow more conrol over download
+ // first off, no .. or global allow check
+ if (strstr (name, "..") || !allow_download->value
+ // leading dot is no good
+ || *name == '.'
+ // leading slash bad as well, must be in subdir
+ || *name == '/'
+ // next up, skin check
+ || (strncmp(name, "players/", 6) == 0 && !allow_download_players->value)
+ // now models
+ || (strncmp(name, "models/", 6) == 0 && !allow_download_models->value)
+ // now sounds
+ || (strncmp(name, "sound/", 6) == 0 && !allow_download_sounds->value)
+ // now maps (note special case for maps, must not be in pak)
+ || (strncmp(name, "maps/", 6) == 0 && !allow_download_maps->value)
+ // MUST be in a subdirectory
+ || !strstr (name, "/") )
+ { // don't allow anything with .. path
+ MSG_WriteByte (&sv_client->netchan.message, svc_download);
+ MSG_WriteShort (&sv_client->netchan.message, -1);
+ MSG_WriteByte (&sv_client->netchan.message, 0);
+ return;
+ }
+
+
+ if (sv_client->download)
+ FS_FreeFile (sv_client->download);
+
+ sv_client->downloadsize = FS_LoadFile (name, (void **)&sv_client->download);
+ sv_client->downloadcount = offset;
+
+ if (offset > sv_client->downloadsize)
+ sv_client->downloadcount = sv_client->downloadsize;
+
+ if (!sv_client->download
+ // special check for maps, if it came from a pak file, don't allow
+ // download ZOID
+ || (strncmp(name, "maps/", 5) == 0 && file_from_pak))
+ {
+ Com_DPrintf ("Couldn't download %s to %s\n", name, sv_client->name);
+ if (sv_client->download) {
+ FS_FreeFile (sv_client->download);
+ sv_client->download = NULL;
+ }
+
+ MSG_WriteByte (&sv_client->netchan.message, svc_download);
+ MSG_WriteShort (&sv_client->netchan.message, -1);
+ MSG_WriteByte (&sv_client->netchan.message, 0);
+ return;
+ }
+
+ SV_NextDownload_f ();
+ Com_DPrintf ("Downloading %s to %s\n", name, sv_client->name);
+}
+
+
+
+//============================================================================
+
+
+/*
+=================
+SV_Disconnect_f
+
+The client is going to disconnect, so remove the connection immediately
+=================
+*/
+void SV_Disconnect_f (void)
+{
+// SV_EndRedirect ();
+ SV_DropClient (sv_client);
+}
+
+
+/*
+==================
+SV_ShowServerinfo_f
+
+Dumps the serverinfo info string
+==================
+*/
+void SV_ShowServerinfo_f (void)
+{
+ Info_Print (Cvar_Serverinfo());
+}
+
+
+void SV_Nextserver (void)
+{
+ char *v;
+
+ //ZOID, ss_pic can be nextserver'd in coop mode
+ if (sv.state == ss_game || (sv.state == ss_pic && !Cvar_VariableValue("coop")))
+ return; // can't nextserver while playing a normal game
+
+ svs.spawncount++; // make sure another doesn't sneak in
+ v = Cvar_VariableString ("nextserver");
+ if (!v[0])
+ Cbuf_AddText ("killserver\n");
+ else
+ {
+ Cbuf_AddText (v);
+ Cbuf_AddText ("\n");
+ }
+ Cvar_Set ("nextserver","");
+}
+
+/*
+==================
+SV_Nextserver_f
+
+A cinematic has completed or been aborted by a client, so move
+to the next server,
+==================
+*/
+void SV_Nextserver_f (void)
+{
+ if ( atoi(Cmd_Argv(1)) != svs.spawncount ) {
+ Com_DPrintf ("Nextserver() from wrong level, from %s\n", sv_client->name);
+ return; // leftover from last server
+ }
+
+ Com_DPrintf ("Nextserver() from %s\n", sv_client->name);
+
+ SV_Nextserver ();
+}
+
+typedef struct
+{
+ char *name;
+ void (*func) (void);
+} ucmd_t;
+
+ucmd_t ucmds[] =
+{
+ // auto issued
+ {"new", SV_New_f},
+ {"configstrings", SV_Configstrings_f},
+ {"baselines", SV_Baselines_f},
+ {"begin", SV_Begin_f},
+
+ {"nextserver", SV_Nextserver_f},
+
+ {"disconnect", SV_Disconnect_f},
+
+ // issued by hand at client consoles
+ {"info", SV_ShowServerinfo_f},
+
+ {"download", SV_BeginDownload_f},
+ {"nextdl", SV_NextDownload_f},
+
+ {NULL, NULL}
+};
+
+/*
+==================
+SV_ExecuteUserCommand
+==================
+*/
+void SV_ExecuteUserCommand (char *s)
+{
+ ucmd_t *u;
+
+ Cmd_TokenizeString (s, true);
+ sv_player = sv_client->edict;
+
+// SV_BeginRedirect (RD_CLIENT);
+
+ for (u=ucmds ; u->name ; u++)
+ if (!strcmp (Cmd_Argv(0), u->name) )
+ {
+ u->func ();
+ break;
+ }
+
+ if (!u->name && sv.state == ss_game)
+ ge->ClientCommand (sv_player);
+
+// SV_EndRedirect ();
+}
+
+/*
+===========================================================================
+
+USER CMD EXECUTION
+
+===========================================================================
+*/
+
+
+
+void SV_ClientThink (client_t *cl, usercmd_t *cmd)
+
+{
+ cl->commandMsec -= cmd->msec;
+
+ if (cl->commandMsec < 0 && sv_enforcetime->value )
+ {
+ Com_DPrintf ("commandMsec underflow from %s\n", cl->name);
+ return;
+ }
+
+ ge->ClientThink (cl->edict, cmd);
+}
+
+
+
+#define MAX_STRINGCMDS 8
+/*
+===================
+SV_ExecuteClientMessage
+
+The current net_message is parsed for the given client
+===================
+*/
+void SV_ExecuteClientMessage (client_t *cl)
+{
+ int c;
+ char *s;
+
+ usercmd_t nullcmd;
+ usercmd_t oldest, oldcmd, newcmd;
+ int net_drop;
+ int stringCmdCount;
+ int checksum, calculatedChecksum;
+ int checksumIndex;
+ qboolean move_issued;
+ int lastframe;
+
+ sv_client = cl;
+ sv_player = sv_client->edict;
+
+ // only allow one move command
+ move_issued = false;
+ stringCmdCount = 0;
+
+ while (1)
+ {
+ if (net_message.readcount > net_message.cursize)
+ {
+ Com_Printf ("SV_ReadClientMessage: badread\n");
+ SV_DropClient (cl);
+ return;
+ }
+
+ c = MSG_ReadByte (&net_message);
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ default:
+ Com_Printf ("SV_ReadClientMessage: unknown command char\n");
+ SV_DropClient (cl);
+ return;
+
+ case clc_nop:
+ break;
+
+ case clc_userinfo:
+ strncpy (cl->userinfo, MSG_ReadString (&net_message), sizeof(cl->userinfo)-1);
+ SV_UserinfoChanged (cl);
+ break;
+
+ case clc_move:
+ if (move_issued)
+ return; // someone is trying to cheat...
+
+ move_issued = true;
+ checksumIndex = net_message.readcount;
+ checksum = MSG_ReadByte (&net_message);
+ lastframe = MSG_ReadLong (&net_message);
+ if (lastframe != cl->lastframe) {
+ cl->lastframe = lastframe;
+ if (cl->lastframe > 0) {
+ cl->frame_latency[cl->lastframe&(LATENCY_COUNTS-1)] =
+ svs.realtime - cl->frames[cl->lastframe & UPDATE_MASK].senttime;
+ }
+ }
+
+ memset (&nullcmd, 0, sizeof(nullcmd));
+ MSG_ReadDeltaUsercmd (&net_message, &nullcmd, &oldest);
+ MSG_ReadDeltaUsercmd (&net_message, &oldest, &oldcmd);
+ MSG_ReadDeltaUsercmd (&net_message, &oldcmd, &newcmd);
+
+ if ( cl->state != cs_spawned )
+ {
+ cl->lastframe = -1;
+ break;
+ }
+
+ // if the checksum fails, ignore the rest of the packet
+ calculatedChecksum = COM_BlockSequenceCRCByte (
+ net_message.data + checksumIndex + 1,
+ net_message.readcount - checksumIndex - 1,
+ cl->netchan.incoming_sequence);
+
+ if (calculatedChecksum != checksum)
+ {
+ Com_DPrintf ("Failed command checksum for %s (%d != %d)/%d\n",
+ cl->name, calculatedChecksum, checksum,
+ cl->netchan.incoming_sequence);
+ return;
+ }
+
+ if (!sv_paused->value)
+ {
+ net_drop = cl->netchan.dropped;
+ if (net_drop < 20)
+ {
+
+//if (net_drop > 2)
+
+// Com_Printf ("drop %i\n", net_drop);
+ while (net_drop > 2)
+ {
+ SV_ClientThink (cl, &cl->lastcmd);
+
+ net_drop--;
+ }
+ if (net_drop > 1)
+ SV_ClientThink (cl, &oldest);
+
+ if (net_drop > 0)
+ SV_ClientThink (cl, &oldcmd);
+
+ }
+ SV_ClientThink (cl, &newcmd);
+ }
+
+ cl->lastcmd = newcmd;
+ break;
+
+ case clc_stringcmd:
+ s = MSG_ReadString (&net_message);
+
+ // malicious users may try using too many string commands
+ if (++stringCmdCount < MAX_STRINGCMDS)
+ SV_ExecuteUserCommand (s);
+
+ if (cl->state == cs_zombie)
+ return; // disconnect command
+ break;
+ }
+ }
+}
+
--- /dev/null
+++ b/sv_world.c
@@ -1,0 +1,591 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+typedef struct moveclip_t moveclip_t;
+typedef struct areanode_t areanode_t;
+
+/* ENTITY AREA CHECKING: high level object sorting to reduce interaction tests
+ * FIXME: this use of "area" is different from the bsp file use */
+
+// (type *)STRUCT_FROM_LINK(link_t *link, type, member)
+// ent = STRUCT_FROM_LINK(link,entity_t,order)
+// FIXME: remove this mess!
+#define STRUCT_FROM_LINK(l,t,m) ((t *)((byte *)l - (uintptr)&(((t *)0)->m)))
+#define EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area)
+
+enum{
+ AREA_DEPTH = 4,
+ AREA_NODES = 32,
+ MAX_TOTAL_ENT_LEAFS = 128
+};
+struct areanode_t{
+ int axis; // -1 = leaf node
+ float dist;
+ areanode_t *children[2];
+ link_t trigger_edicts;
+ link_t solid_edicts;
+};
+areanode_t sv_areanodes[AREA_NODES];
+int sv_numareanodes;
+
+float *area_mins;
+float *area_maxs;
+edict_t **area_list;
+int area_count;
+int area_maxcount;
+int area_type;
+
+struct moveclip_t{
+ vec3_t boxmins; // enclose the test object along entire move
+ vec3_t boxmaxs;
+ float *mins; // size of the moving object
+ float *maxs;
+ vec3_t mins2; // size when clipping against monsters
+ vec3_t maxs2;
+ float *start;
+ float *end;
+ trace_t trace;
+ edict_t *passedict;
+ int contentmask;
+};
+
+int SV_HullForEntity(edict_t *);
+
+
+/* used for new headnodes */
+void
+ClearLink(link_t *l)
+{
+ l->prev = l->next = l;
+}
+
+void
+RemoveLink(link_t *l)
+{
+ l->next->prev = l->prev;
+ l->prev->next = l->next;
+}
+
+void
+InsertLinkBefore(link_t *l, link_t *before)
+{
+ l->next = before;
+ l->prev = before->prev;
+ l->prev->next = l;
+ l->next->prev = l;
+}
+
+/* builds a uniformly subdivided tree for the given world size */
+areanode_t *
+SV_CreateAreaNode(int depth, vec3_t mins, vec3_t maxs)
+{
+ areanode_t *anode;
+ vec3_t size;
+ vec3_t mins1, maxs1, mins2, maxs2;
+
+ anode = &sv_areanodes[sv_numareanodes];
+ sv_numareanodes++;
+
+ ClearLink (&anode->trigger_edicts);
+ ClearLink (&anode->solid_edicts);
+
+ if (depth == AREA_DEPTH)
+ {
+ anode->axis = -1;
+ anode->children[0] = anode->children[1] = NULL;
+ return anode;
+ }
+
+ VectorSubtract (maxs, mins, size);
+ if (size[0] > size[1])
+ anode->axis = 0;
+ else
+ anode->axis = 1;
+
+ anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);
+ VectorCopy (mins, mins1);
+ VectorCopy (mins, mins2);
+ VectorCopy (maxs, maxs1);
+ VectorCopy (maxs, maxs2);
+
+ maxs1[anode->axis] = mins2[anode->axis] = anode->dist;
+
+ anode->children[0] = SV_CreateAreaNode (depth+1, mins2, maxs2);
+ anode->children[1] = SV_CreateAreaNode (depth+1, mins1, maxs1);
+
+ return anode;
+}
+
+/* called after the world model has been loaded, before linking any entities */
+void
+SV_ClearWorld(void)
+{
+ memset(sv_areanodes, 0, sizeof sv_areanodes);
+ sv_numareanodes = 0;
+ SV_CreateAreaNode(0, sv.models[1]->mins, sv.models[1]->maxs);
+}
+
+/* call before removing an entity, and before trying to move one, so it doesn't
+ * clip against itself */
+void
+SV_UnlinkEdict(edict_t *p)
+{
+ if(!p->area.prev)
+ return; // not linked in anywhere
+ RemoveLink(&p->area);
+ p->area.prev = p->area.next = nil;
+}
+
+/* needs to be called any time an entity changes origin, mins, maxs, or solid.
+ * automatically unlinks if needed. sets ent->v.absmin and ent->v.absmax. sets
+ * ent->leafnums[] for pvs determination even if the entity is not solid */
+void
+SV_LinkEdict(edict_t *ent)
+{
+ areanode_t *node;
+ int leafs[MAX_TOTAL_ENT_LEAFS];
+ int clusters[MAX_TOTAL_ENT_LEAFS];
+ int num_leafs;
+ int i, j, k;
+ int area;
+ int topnode;
+
+ if (ent->area.prev)
+ SV_UnlinkEdict (ent); // unlink from old position
+
+ if (ent == ge->edicts)
+ return; // don't add the world
+
+ if (!ent->inuse)
+ return;
+
+ // set the size
+ VectorSubtract (ent->maxs, ent->mins, ent->size);
+
+ // encode the size into the entity_state for client prediction
+ if (ent->solid == SOLID_BBOX && !(ent->svflags & SVF_DEADMONSTER))
+ { // assume that x/y are equal and symetric
+ i = ent->maxs[0]/8;
+ if (i<1)
+ i = 1;
+ if (i>31)
+ i = 31;
+
+ // z is not symetric
+ j = (-ent->mins[2])/8;
+ if (j<1)
+ j = 1;
+ if (j>31)
+ j = 31;
+
+ // and z maxs can be negative...
+ k = (ent->maxs[2]+32)/8;
+ if (k<1)
+ k = 1;
+ if (k>63)
+ k = 63;
+
+ ent->s.solid = (k<<10) | (j<<5) | i;
+ }
+ else if (ent->solid == SOLID_BSP)
+ {
+ ent->s.solid = 31; // a solid_bbox will never create this value
+ }
+ else
+ ent->s.solid = 0;
+
+ // set the abs box
+ if (ent->solid == SOLID_BSP &&
+ (ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2]) )
+ { // expand for rotation
+ float max, v;
+ int i;
+
+ max = 0;
+ for (i=0 ; i<3 ; i++)
+ {
+ v =fabs( ent->mins[i]);
+ if (v > max)
+ max = v;
+ v =fabs( ent->maxs[i]);
+ if (v > max)
+ max = v;
+ }
+ for (i=0 ; i<3 ; i++)
+ {
+ ent->absmin[i] = ent->s.origin[i] - max;
+ ent->absmax[i] = ent->s.origin[i] + max;
+ }
+ }
+ else
+ { // normal
+ VectorAdd (ent->s.origin, ent->mins, ent->absmin);
+ VectorAdd (ent->s.origin, ent->maxs, ent->absmax);
+ }
+
+ // because movement is clipped an epsilon away from an actual edge,
+ // we must fully check even when bounding boxes don't quite touch
+ ent->absmin[0] -= 1;
+ ent->absmin[1] -= 1;
+ ent->absmin[2] -= 1;
+ ent->absmax[0] += 1;
+ ent->absmax[1] += 1;
+ ent->absmax[2] += 1;
+
+// link to PVS leafs
+ ent->num_clusters = 0;
+ ent->areanum = 0;
+ ent->areanum2 = 0;
+
+ //get all leafs, including solids
+ num_leafs = CM_BoxLeafnums (ent->absmin, ent->absmax,
+ leafs, MAX_TOTAL_ENT_LEAFS, &topnode);
+
+ // set areas
+ for (i=0 ; i<num_leafs ; i++)
+ {
+ clusters[i] = CM_LeafCluster (leafs[i]);
+ area = CM_LeafArea (leafs[i]);
+ if (area)
+ { // doors may legally straggle two areas,
+ // but nothing should evern need more than that
+ if (ent->areanum && ent->areanum != area)
+ {
+ if (ent->areanum2 && ent->areanum2 != area && sv.state == ss_loading)
+ Com_DPrintf ("Object touching 3 areas at %f %f %f\n",
+ ent->absmin[0], ent->absmin[1], ent->absmin[2]);
+ ent->areanum2 = area;
+ }
+ else
+ ent->areanum = area;
+ }
+ }
+
+ if (num_leafs >= MAX_TOTAL_ENT_LEAFS)
+ { // assume we missed some leafs, and mark by headnode
+ ent->num_clusters = -1;
+ ent->headnode = topnode;
+ }
+ else
+ {
+ ent->num_clusters = 0;
+ for (i=0 ; i<num_leafs ; i++)
+ {
+ if (clusters[i] == -1)
+ continue; // not a visible leaf
+ for (j=0 ; j<i ; j++)
+ if (clusters[j] == clusters[i])
+ break;
+ if (j == i)
+ {
+ if (ent->num_clusters == MAX_ENT_CLUSTERS)
+ { // assume we missed some leafs, and mark by headnode
+ ent->num_clusters = -1;
+ ent->headnode = topnode;
+ break;
+ }
+
+ ent->clusternums[ent->num_clusters++] = clusters[i];
+ }
+ }
+ }
+
+ // if first time, make sure old_origin is valid
+ if (!ent->linkcount)
+ {
+ VectorCopy (ent->s.origin, ent->s.old_origin);
+ }
+ ent->linkcount++;
+
+ if (ent->solid == SOLID_NOT)
+ return;
+
+// find the first node that the ent's box crosses
+ node = sv_areanodes;
+ while (1)
+ {
+ if (node->axis == -1)
+ break;
+ if (ent->absmin[node->axis] > node->dist)
+ node = node->children[0];
+ else if (ent->absmax[node->axis] < node->dist)
+ node = node->children[1];
+ else
+ break; // crosses the node
+ }
+
+ // link it in
+ if (ent->solid == SOLID_TRIGGER)
+ InsertLinkBefore (&ent->area, &node->trigger_edicts);
+ else
+ InsertLinkBefore (&ent->area, &node->solid_edicts);
+
+}
+
+void
+SV_AreaEdicts_r(areanode_t *node)
+{
+ link_t *l, *next, *start;
+ edict_t *check;
+
+ // touch linked edicts
+ if (area_type == AREA_SOLID)
+ start = &node->solid_edicts;
+ else
+ start = &node->trigger_edicts;
+
+ for (l=start->next ; l != start ; l = next)
+ {
+ next = l->next;
+ check = EDICT_FROM_AREA(l);
+
+ if (check->solid == SOLID_NOT)
+ continue; // deactivated
+ if (check->absmin[0] > area_maxs[0]
+ || check->absmin[1] > area_maxs[1]
+ || check->absmin[2] > area_maxs[2]
+ || check->absmax[0] < area_mins[0]
+ || check->absmax[1] < area_mins[1]
+ || check->absmax[2] < area_mins[2])
+ continue; // not touching
+
+ if (area_count == area_maxcount)
+ {
+ Com_Printf ("SV_AreaEdicts: MAXCOUNT\n");
+ return;
+ }
+
+ area_list[area_count] = check;
+ area_count++;
+ }
+
+ if (node->axis == -1)
+ return; // terminal node
+
+ // recurse down both sides
+ if ( area_maxs[node->axis] > node->dist )
+ SV_AreaEdicts_r ( node->children[0] );
+ if ( area_mins[node->axis] < node->dist )
+ SV_AreaEdicts_r ( node->children[1] );
+}
+
+/* fills in a table of edict pointers with edicts that have bounding boxes that
+ * intersect the given area. it is possible for a non-axial bmodel to be
+ * returned that doesn't actually intersect the area on an exact test. returns
+ * the number of pointers filled in.
+ * ??? does this always return the world? */
+int
+SV_AreaEdicts(vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int areatype)
+{
+ area_mins = mins;
+ area_maxs = maxs;
+ area_list = list;
+ area_count = 0;
+ area_maxcount = maxcount;
+ area_type = areatype;
+
+ SV_AreaEdicts_r (sv_areanodes);
+
+ return area_count;
+}
+
+/* returns the CONTENTS_* value from the world at the given point. Quake 2
+ * extends this to also check entities, to allow moving liquids */
+int
+SV_PointContents(vec3_t p)
+{
+ edict_t *touch[MAX_EDICTS], *hit;
+ int i, num;
+ int contents, c2;
+ int headnode;
+
+ // get base contents from world
+ contents = CM_PointContents (p, sv.models[1]->headnode);
+
+ // or in contents from all the other entities
+ num = SV_AreaEdicts (p, p, touch, MAX_EDICTS, AREA_SOLID);
+
+ for (i=0 ; i<num ; i++)
+ {
+ hit = touch[i];
+
+ // might intersect, so do an exact clip
+ headnode = SV_HullForEntity (hit);
+
+ /* unused
+ float *angles;
+ angles = hit->s.angles;
+ if (hit->solid != SOLID_BSP)
+ angles = vec3_origin; // boxes don't rotate
+ */
+
+ c2 = CM_TransformedPointContents (p, headnode, hit->s.origin, hit->s.angles);
+
+ contents |= c2;
+ }
+
+ return contents;
+}
+
+/* returns a headnode that can be used for testing or clipping an object of
+ * mins/maxs size. offset is filled in to contain the adjustment that must be
+ * added to the testing object's origin to get a point to use with the returned
+ * hull. */
+int
+SV_HullForEntity(edict_t *ent)
+{
+ cmodel_t *model;
+
+// decide which clipping hull to use, based on the size
+ if (ent->solid == SOLID_BSP)
+ { // explicit hulls in the BSP model
+ model = sv.models[ ent->s.modelindex ];
+
+ if (!model)
+ Com_Error (ERR_FATAL, "MOVETYPE_PUSH with a non bsp model");
+
+ return model->headnode;
+ }
+
+ // create a temp hull from bounding box sizes
+
+ return CM_HeadnodeForBox (ent->mins, ent->maxs);
+}
+
+void
+SV_ClipMoveToEntities(moveclip_t *clip)
+{
+ int i, num;
+ edict_t *touchlist[MAX_EDICTS], *touch;
+ trace_t trace;
+ int headnode;
+ float *angles;
+
+ num = SV_AreaEdicts (clip->boxmins, clip->boxmaxs, touchlist
+ , MAX_EDICTS, AREA_SOLID);
+
+ // be careful, it is possible to have an entity in this
+ // list removed before we get to it (killtriggered)
+ for (i=0 ; i<num ; i++)
+ {
+ touch = touchlist[i];
+ if (touch->solid == SOLID_NOT)
+ continue;
+ if (touch == clip->passedict)
+ continue;
+ if (clip->trace.allsolid)
+ return;
+ if (clip->passedict)
+ {
+ if (touch->owner == clip->passedict)
+ continue; // don't clip against own missiles
+ if (clip->passedict->owner == touch)
+ continue; // don't clip against owner
+ }
+
+ if ( !(clip->contentmask & CONTENTS_DEADMONSTER)
+ && (touch->svflags & SVF_DEADMONSTER) )
+ continue;
+
+ // might intersect, so do an exact clip
+ headnode = SV_HullForEntity (touch);
+ angles = touch->s.angles;
+ if (touch->solid != SOLID_BSP)
+ angles = vec3_origin; // boxes don't rotate
+
+ if (touch->svflags & SVF_MONSTER)
+ trace = CM_TransformedBoxTrace (clip->start, clip->end,
+ clip->mins2, clip->maxs2, headnode, clip->contentmask,
+ touch->s.origin, angles);
+ else
+ trace = CM_TransformedBoxTrace (clip->start, clip->end,
+ clip->mins, clip->maxs, headnode, clip->contentmask,
+ touch->s.origin, angles);
+
+ if (trace.allsolid || trace.startsolid ||
+ trace.fraction < clip->trace.fraction)
+ {
+ trace.ent = touch;
+ if (clip->trace.startsolid)
+ {
+ clip->trace = trace;
+ clip->trace.startsolid = true;
+ }
+ else
+ clip->trace = trace;
+ }
+ else if (trace.startsolid)
+ clip->trace.startsolid = true;
+ }
+}
+
+void
+SV_TraceBounds(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t boxmins, vec3_t boxmaxs)
+{
+/*
+ // debug to test against everything
+ boxmins[0] = boxmins[1] = boxmins[2] = -9999;
+ boxmaxs[0] = boxmaxs[1] = boxmaxs[2] = 9999;
+*/
+ int i;
+
+ for (i=0 ; i<3 ; i++)
+ {
+ if (end[i] > start[i])
+ {
+ boxmins[i] = start[i] + mins[i] - 1;
+ boxmaxs[i] = end[i] + maxs[i] + 1;
+ }
+ else
+ {
+ boxmins[i] = end[i] + mins[i] - 1;
+ boxmaxs[i] = start[i] + maxs[i] + 1;
+ }
+ }
+}
+
+/* moves the given mins/maxs volume through the world from start to end.
+ * passedict and edicts owned by passedict are explicitly not checked. mins and
+ * maxs are relative.
+ * if the entire move stays in a solid volume, trace.allsolid will be set,
+ * trace.startsolid will be set, and trace.fraction will be 0. if the starting
+ * point is in a solid, it will be allowed to move out to an open area */
+trace_t
+SV_Trace(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask)
+{
+ moveclip_t clip;
+
+ if (!mins)
+ mins = vec3_origin;
+ if (!maxs)
+ maxs = vec3_origin;
+
+ memset ( &clip, 0, sizeof ( moveclip_t ) );
+
+ // clip to world
+ clip.trace = CM_BoxTrace (start, end, mins, maxs, 0, contentmask);
+ clip.trace.ent = ge->edicts;
+ if (clip.trace.fraction == 0)
+ return clip.trace; // blocked by the world
+
+ clip.contentmask = contentmask;
+ clip.start = start;
+ clip.end = end;
+ clip.mins = mins;
+ clip.maxs = maxs;
+ clip.passedict = passedict;
+
+ VectorCopy (mins, clip.mins2);
+ VectorCopy (maxs, clip.maxs2);
+
+ // create the bounding box of the entire move
+ SV_TraceBounds ( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs );
+
+ // clip to other solid entities
+ SV_ClipMoveToEntities ( &clip );
+
+ return clip.trace;
+}
--- /dev/null
+++ b/sys.c
@@ -1,0 +1,453 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <thread.h>
+#include "dat.h"
+#include "fns.h"
+
+void KBD_Update(void);
+
+mainstacksize = 512*1024;
+int curtime;
+uint sys_frame_time;
+Channel *fuckchan, *tchan;
+
+static uchar *membase;
+static int maxhunksize, curhunksize;
+static char findbase[MAX_OSPATH], findpath[MAX_OSPATH], findpattern[MAX_OSPATH];
+static Dir *dirs;
+static long dirn, di;
+
+static int glob_match(char *, char *);
+
+
+/* Like glob_match, but match PATTERN against any final segment of TEXT. */
+static int
+glob_match_after_star(char *pattern, char *text)
+{
+ char *p = pattern, *t = text;
+ char c, c1;
+
+ while ((c = *p++) == '?' || c == '*')
+ if (c == '?' && *t++ == '\0')
+ return 0;
+
+ if (c == '\0')
+ return 1;
+
+ if (c == '\\')
+ c1 = *p;
+ else
+ c1 = c;
+
+ while (1) {
+ if ((c == '[' || *t == c1) && glob_match(p - 1, t))
+ return 1;
+ if (*t++ == '\0')
+ return 0;
+ }
+}
+
+/* Return nonzero if PATTERN has any special globbing chars in it. */
+static int
+glob_pattern_p(char *pattern)
+{
+ char *p = pattern;
+ char c;
+ int open = 0;
+
+ while ((c = *p++) != '\0')
+ switch (c) {
+ case '?':
+ case '*':
+ return 1;
+
+ case '[': /* Only accept an open brace if there is a close */
+ open++; /* brace to match it. Bracket expressions must be */
+ continue; /* complete, according to Posix.2 */
+ case ']':
+ if (open)
+ return 1;
+ continue;
+
+ case '\\':
+ if (*p++ == '\0')
+ return 0;
+ }
+
+ return 0;
+}
+
+/* Match the pattern PATTERN against the string TEXT;
+ return 1 if it matches, 0 otherwise.
+
+ A match means the entire string TEXT is used up in matching.
+
+ In the pattern string, `*' matches any sequence of characters,
+ `?' matches any character, [SET] matches any character in the specified set,
+ [!SET] matches any character not in the specified set.
+
+ A set is composed of characters or ranges; a range looks like
+ character hyphen character (as in 0-9 or A-Z).
+ [0-9a-zA-Z_] is the set of characters allowed in C identifiers.
+ Any other character in the pattern must be matched exactly.
+
+ To suppress the special syntactic significance of any of `[]*?!-\',
+ and match the character exactly, precede it with a `\'.
+*/
+
+static int
+glob_match(char *pattern, char *text)
+{
+ char *p = pattern, *t = text;
+ char c, c1, cstart, cend;
+ int invert;
+
+ while ((c = *p++) != '\0')
+ switch (c) {
+ case '?':
+ if (*t == '\0')
+ return 0;
+ else
+ ++t;
+ break;
+
+ case '\\':
+ if (*p++ != *t++)
+ return 0;
+ break;
+
+ case '*':
+ return glob_match_after_star(p, t);
+
+ case '[':
+ {
+ c1 = *t++;
+
+ if (!c1)
+ return (0);
+
+ invert = ((*p == '!') || (*p == '^'));
+ if (invert)
+ p++;
+
+ c = *p++;
+ while (1) {
+ cstart = c;
+ cend = c;
+
+ if (c == '\\') {
+ cstart = *p++;
+ cend = cstart;
+ }
+ if (c == '\0')
+ return 0;
+
+ c = *p++;
+ if (c == '-' && *p != ']') {
+ cend = *p++;
+ if (cend == '\\')
+ cend = *p++;
+ if (cend == '\0')
+ return 0;
+ c = *p++;
+ }
+ if (c1 >= cstart && c1 <= cend)
+ goto match;
+ if (c == ']')
+ break;
+ }
+ if (!invert)
+ return 0;
+ break;
+
+ match:
+ /* Skip the rest of the [...] construct that already matched. */
+ while (c != ']') {
+ if (c == '\0')
+ return 0;
+ c = *p++;
+ if (c == '\0')
+ return 0;
+ else if (c == '\\')
+ ++p;
+ }
+ if (invert)
+ return 0;
+ break;
+ }
+
+ default:
+ if (c != *t++)
+ return 0;
+ }
+
+ /* if the pattern is empty, Sys_FindNext looks at the current file anyway */
+ return *t == '\0';
+}
+
+void *
+Hunk_Begin(int maxsize)
+{
+ // reserve a huge chunk of memory, but don't commit any yet
+ maxhunksize = maxsize;
+ curhunksize = 0;
+ if((membase = mallocz(maxhunksize, 1)) == nil)
+ sysfatal("Hunk_Begin:malloc %d: %r", maxhunksize);
+ return membase;
+}
+
+void *
+Hunk_Alloc(int size)
+{
+ byte *buf;
+
+ // round to cacheline
+ size = (size+31)&~31;
+ if(curhunksize + size > maxhunksize)
+ Sys_Error("Hunk_Alloc overflow");
+ buf = membase + curhunksize;
+ curhunksize += size;
+ return buf;
+}
+
+int
+Hunk_End(void)
+{
+ if(realloc(membase, curhunksize) != membase)
+ sysfatal("Hunk_End:realloc: %r");
+ return curhunksize;
+}
+
+void
+Hunk_Free(void *base)
+{
+ if(base != nil)
+ free(base);
+}
+
+static qboolean
+CompareAttributes(ulong m, uint musthave, uint canthave)
+{
+ if(m & DMDIR && canthave & SFF_SUBDIR)
+ return false;
+ if(musthave & SFF_SUBDIR && ~m & DMDIR)
+ return false;
+ return true;
+}
+
+char *
+Sys_FindFirst(char *path, uint musthave, uint canhave)
+{
+ char *p;
+ int fd;
+
+ if(dirs != nil)
+ Sys_Error("Sys_BeginFind without close");
+
+ strncpy(findbase, path, sizeof findbase-1);
+ if((p = strrchr(findbase, '/')) != nil){
+ *p = 0;
+ strncpy(findpattern, p+1, sizeof findpattern-1);
+ }else
+ strcpy(findpattern, "*");
+ if(strcmp(findpattern, "*.*") == 0)
+ strcpy(findpattern, "*");
+ if(*findpattern == '\0'){
+ Com_Printf("Sys_BeginFind: empty pattern\n");
+ return nil;
+ }
+
+ if((fd = open(findbase, OREAD)) < 0){
+ fprint(2, "Sys_BeginFind:open: %r\n");
+ return nil;
+ }
+ dirn = dirreadall(fd, &dirs);
+ close(fd);
+ if(dirn == 0)
+ return nil;
+ if(dirn < 0){
+ fprint(2, "Sys_BeginFind:dirread: %r\n");
+ return nil;
+ }
+
+ di = 0;
+ return Sys_FindNext(musthave, canhave);
+}
+
+char *
+Sys_FindNext(uint musthave, uint canhave)
+{
+ int i;
+
+ if(dirs == nil)
+ Sys_Error("Sys_FindNext without open\n");
+
+ while(di < dirn){
+ i = di++;
+ if(glob_match(findpattern, dirs[i].name)){
+ if(CompareAttributes(dirs[i].mode, musthave, canhave)){
+ snprintf(findpath, sizeof findpath, "%s/%s", findbase, dirs[i].name);
+ return findpath;
+ }
+ }
+ }
+ return nil;
+}
+
+void
+Sys_FindClose(void)
+{
+ if(dirs != nil){
+ free(dirs);
+ dirs = nil;
+ }
+}
+
+/* prints to "debugging console" */
+void
+Sys_ConsoleOutput(char *s)
+{
+ write(1, s, strlen(s));
+}
+
+void
+Sys_Error(char *error, ...)
+{
+ char buf[1024], *out;
+ va_list arg;
+
+ CL_Shutdown();
+
+ va_start(arg, error);
+ out = vseprint(buf, buf+sizeof(buf), error, arg);
+ va_end(arg);
+ write(2, buf, out-buf);
+ print("\n");
+ sysfatal("ending.");
+}
+
+int
+Sys_Milliseconds(void)
+{
+ static long msbase;
+
+ if(msbase == 0)
+ msbase = time(nil)*1000;
+ curtime = nsec()/1000000 - msbase;
+ return curtime;
+}
+
+void
+Sys_Mkdir(char *path)
+{
+ int d;
+
+ if((d = create(path, OREAD, DMDIR|0777)) < 0)
+ fprint(2, "Sys_Mkdir:create: %r\n");
+ else
+ close(d);
+}
+
+vlong
+flen(int fd)
+{
+ uchar bs[1024];
+
+ if(fstat(fd, bs, sizeof bs) < 0){
+ fprint(2, "flen:fstat: %r\n");
+ return -1;
+ }
+ return *((vlong *)(bs+2+2+4+1+4+8+4+4+4)); /* length[8] */
+}
+
+int
+Sys_FileTime(char *path)
+{
+ uchar sb[1024];
+
+ if(stat(path, sb, sizeof sb) < 0){
+ fprint(2, "Sys_FileTime:stat: %r\n");
+ return -1;
+ }
+ return *((int *)(sb+25));
+}
+
+void
+Sys_UnloadGame(void)
+{
+}
+
+void
+Sys_AppActivate(void)
+{
+}
+
+void
+Sys_SendKeyEvents(void)
+{
+ KBD_Update();
+ sys_frame_time = Sys_Milliseconds(); // grab frame time
+}
+
+char *
+Sys_GetClipboardData(void)
+{
+ return nil;
+}
+
+void
+Sys_CopyProtect(void)
+{
+}
+
+void
+Sys_Quit(void)
+{
+ chanfree(fuckchan);
+ chanfree(tchan);
+ threadexitsall(nil);
+}
+
+void
+Sys_Init(void)
+{
+ //Sys_SetFPCW();
+ if((fuckchan = chancreate(sizeof(int), 1)) == nil)
+ sysfatal("chancreate fuckchan: %r");
+ if((tchan = chancreate(sizeof(int), 16)) == nil)
+ sysfatal("chancreate tchan: %r");
+}
+
+void
+croak(void *, char *note)
+{
+ if(!strncmp(note, "sys:", 4)){
+ IN_Shutdown();
+ SNDDMA_Shutdown();
+ NET_Shutdown();
+ }
+ noted(NDFLT);
+}
+
+void
+threadmain(int argc, char *argv[])
+{
+ int time, oldtime, newtime;
+
+ setfcr(getfcr() & ~(FPOVFL|FPUNFL|FPINVAL|FPZDIV)); /* assumed ignored in code */
+ notify(croak);
+
+ Qcommon_Init(argc, argv);
+
+ oldtime = Sys_Milliseconds();
+ for(;;){
+ do{
+ newtime = Sys_Milliseconds();
+ time = newtime - oldtime;
+ }while(time < 1); // find time spent rendering last frame
+ Qcommon_Frame(time);
+ oldtime = newtime;
+ }
+}
--- /dev/null
+++ b/udp.c
@@ -1,0 +1,553 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include <thread.h>
+#include <bio.h>
+#include <ndb.h>
+#include <ip.h>
+#include "dat.h"
+#include "fns.h"
+
+/* FIXME: this shit SUCKS, and ipv4 only because of other code */
+
+extern Channel *fuckchan, *tchan;
+
+static cvar_t *svport; /* server port and copy of string value */
+static char srv[6];
+static cvar_t *clport; /* "client" port and copy */
+static char clsrv[6];
+
+typedef struct Loopmsg Loopmsg;
+typedef struct Loopback Loopback;
+typedef struct Conmsg Conmsg;
+typedef struct Conlist Conlist;
+
+enum{
+ Hdrsz = 16+16+16+2+2, /* sizeof Udphdr w/o padding */
+ Bufsz = MAX_MSGLEN,
+ Nbuf = 64,
+ MAX_LOOPBACK = 4,
+ CLPORT = 27909
+};
+struct Loopmsg{
+ byte data[MAX_MSGLEN];
+ int datalen;
+};
+struct Loopback{
+ Loopmsg msgs[MAX_LOOPBACK];
+ int get;
+ int send;
+};
+static Loopback loopbacks[2];
+
+struct Conlist{
+ Conlist *p;
+ uchar u[IPaddrlen+2];
+ char addr[IPaddrlen*2+8+6]; /* ipv6 + separators + port in decimal */
+ int dfd;
+ Udphdr h;
+ int src; /* q2 assumes broadcast replies are received on NS_CLIENT */
+};
+static Conlist *cnroot;
+
+struct Conmsg{
+ Conlist *p;
+ int n;
+ uchar buf[Bufsz];
+};
+static Channel *udpchan, *clchan;
+
+static netadr_t laddr; /* 0.0.0.0:0 */
+static int cfd = -1, ufd = -1, clfd = -1, cldfd = -1;
+static QLock cnlock;
+
+
+qboolean
+NET_CompareAdr(netadr_t a, netadr_t b)
+{
+ return(a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port);
+}
+
+/* compares without the port */
+qboolean
+NET_CompareBaseAdr(netadr_t a, netadr_t b)
+{
+ if(a.type != b.type)
+ return false;
+ switch(a.type){
+ case NA_LOOPBACK:
+ return true;
+ case NA_IP:
+ return (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3]);
+ case NA_IPX:
+ return !memcmp(a.ipx, b.ipx, 10);
+ default:
+ return false;
+ }
+}
+
+char *
+NET_AdrToString(netadr_t a)
+{
+ static char s[256];
+
+ seprint(s, s+sizeof s, "%ud.%ud.%ud.%ud:%hud", a.ip[0], a.ip[1], a.ip[2], a.ip[3], BigShort(a.port));
+ return s;
+}
+
+char *
+NET_BaseAdrToString(netadr_t a)
+{
+ static char s[256];
+
+ seprint(s, s+sizeof s, "%ud.%ud.%ud.%ud", a.ip[0], a.ip[1], a.ip[2], a.ip[3]);
+ return s;
+}
+
+/*
+=============
+NET_StringToAdr
+
+localhost
+idnewt
+idnewt:28000
+192.246.40.70
+192.246.40.70:28000
+=============
+*/
+qboolean
+NET_StringToAdr(char *addr, netadr_t *a) /* assumes IPv4 */
+{
+ int i;
+ char s[256], *p, *pp;
+ Ndbtuple *t, *nt;
+
+ if(!strcmp(addr, "localhost")){
+ memset(a, 0, sizeof *a);
+ a->type = NA_LOOPBACK;
+ return true;
+ }
+
+ strncpy(s, addr, sizeof s);
+ s[sizeof(s)-1] = 0;
+
+ /* FIXME: arbitrary length strings */
+ if((p = strrchr(s, ':')) != nil){
+ *p++ = '\0';
+ a->port = BigShort(atoi(p));
+ }
+
+ if((t = dnsquery(nil, s, "ip")) == nil){
+ fprint(2, "NET_StringToAdr:dnsquery %s: %r\n", s);
+ return 0;
+ }
+
+ for(nt = t; nt != nil; nt = nt->entry)
+ if(!strcmp(nt->attr, "ip")){
+ strncpy(s, nt->val, sizeof(s)-1);
+ break;
+ }
+ ndbfree(t);
+
+ /* FIXMEGASHIT */
+ for(i = 0, pp = s; i < IPv4addrlen; i++){
+ if((p = strchr(pp, '.')) != nil)
+ *p++ = '\0';
+ a->ip[i] = atoi(pp);
+ pp = p;
+ }
+ a->type = NA_IP;
+ return true;
+}
+
+qboolean
+NET_IsLocalAddress(netadr_t adr)
+{
+ return NET_CompareAdr(adr, laddr);
+}
+
+static int
+looprecv(netsrc_t sock, netadr_t *net_from, sizebuf_t *d)
+{
+ int i;
+ Loopback *l;
+
+ l = &loopbacks[sock];
+ if(l->send - l->get > MAX_LOOPBACK)
+ l->get = l->send - MAX_LOOPBACK;
+ if(l->get >= l->send)
+ return 0;
+ i = l->get & (MAX_LOOPBACK-1);
+ l->get++;
+
+ memcpy(d->data, l->msgs[i].data, l->msgs[i].datalen);
+ d->cursize = l->msgs[i].datalen;
+ *net_from = laddr;
+ return 1;
+}
+
+static void
+loopsend(netsrc_t sock, int length, void *data, netadr_t /*to*/)
+{
+ Loopback *l;
+ int i;
+
+ l = &loopbacks[sock^1];
+ i = l->send & (MAX_LOOPBACK-1);
+ l->send++;
+ memcpy(l->msgs[i].data, data, length);
+ l->msgs[i].datalen = length;
+}
+
+static void
+cninit(void)
+{
+ if(cnroot != nil)
+ return;
+ if((cnroot = malloc(sizeof *cnroot)) == nil)
+ sysfatal("cninit:malloc: %r");
+ cnroot->p = cnroot;
+ memset(cnroot->u, 0, sizeof cnroot->u);
+ memset(cnroot->addr, 0, sizeof cnroot->addr);
+ cnroot->dfd = -1;
+}
+
+static Conlist *
+cnins(int fd, char *addr, uchar *u, Udphdr *h, int src)
+{
+ Conlist *p, *l;
+
+ l = cnroot;
+ if((p = malloc(sizeof *p)) == nil)
+ sysfatal("cnins:malloc: %r");
+
+ strncpy(p->addr, addr, sizeof p->addr);
+ memcpy(p->u, u, sizeof p->u);
+ p->dfd = fd;
+ if(h != nil)
+ memcpy(&p->h, h, sizeof p->h);
+ p->src = src;
+ p->p = l->p;
+ l->p = p;
+ return p;
+}
+
+static Conlist *
+cnfind(char *raddr)
+{
+ Conlist *p = cnroot->p;
+
+ while(p != cnroot){
+ if(!strncmp(p->addr, raddr, strlen(p->addr)))
+ return p;
+ p = p->p;
+ }
+ return nil;
+}
+
+static void
+cndel(Conlist *p)
+{
+ Conlist *l = cnroot;
+
+ while(l->p != p){
+ l = l->p;
+ if(l == cnroot)
+ sysfatal("cndel: bad unlink: cnroot 0x%p node 0x%p\n", cnroot, p);
+ }
+ l->p = p->p;
+ if(p->dfd != ufd && p->dfd != cldfd && p->dfd != -1)
+ close(p->dfd);
+ free(p);
+}
+
+static void
+cnnuke(void)
+{
+ Conlist *p, *l = cnroot;
+
+ if(cnroot == nil)
+ return;
+ do{
+ p = l;
+ l = l->p;
+ if(p->dfd != -1)
+ close(p->dfd);
+ free(p);
+ }while(l != cnroot);
+ cnroot = nil;
+}
+
+static void
+dproc(void *me)
+{
+ int n, fd;
+ Conmsg m;
+ Conlist *p;
+ Channel *c;
+
+ threadsetgrp(THnet);
+
+ m.p = p = me;
+ c = p->src == NS_CLIENT ? clchan : udpchan;
+ fd = p->dfd;
+
+ for(;;){
+ if((n = read(fd, m.buf, sizeof m.buf)) <= 0)
+ break;
+ m.n = n;
+ if(send(c, &m) < 0)
+ sysfatal("uproc:send: %r");
+ if(nbsend(fuckchan, nil) < 0)
+ sysfatal("uproc:nbsend; %r");
+ }
+ fprint(2, "dproc %d: %r\n", threadpid(threadid()));
+ cndel(me);
+}
+
+static void
+uproc(void *c)
+{
+ int n, fd;
+ uchar udpbuf[Bufsz+Hdrsz], u[IPaddrlen+2];
+ char a[IPaddrlen*2+8+6];
+ Udphdr h;
+ Conmsg m;
+ Conlist *p;
+
+ threadsetgrp(THnet);
+
+ fd = ufd;
+ if(c == clchan)
+ fd = cldfd;
+ for(;;){
+ if((n = read(fd, udpbuf, sizeof udpbuf)) <= 0)
+ sysfatal("uproc:read: %r");
+ memcpy(&h, udpbuf, Hdrsz);
+
+ memcpy(u, h.raddr, IPaddrlen);
+ memcpy(u+IPaddrlen, h.rport, 2);
+ snprint(a, sizeof a, "%ud.%ud.%ud.%ud:%hud", u[12], u[13], u[14], u[15], u[16]<<8 | u[17]);
+ qlock(&cnlock);
+ if((p = cnfind(a)) == nil)
+ p = cnins(fd, a, u, &h, 0);
+ qunlock(&cnlock);
+ m.p = p;
+
+ if(n - Hdrsz < 0){ /* FIXME */
+ m.n = n;
+ memcpy(m.buf, udpbuf, m.n);
+ }else{
+ m.n = n - Hdrsz;
+ memcpy(m.buf, udpbuf+Hdrsz, m.n);
+ }
+ if(send(c, &m) < 0)
+ sysfatal("uproc:send: %r");
+ if(nbsend(fuckchan, nil) < 0)
+ sysfatal("uproc:nbsend: %r");
+ }
+}
+
+qboolean
+NET_GetPacket(netsrc_t src, netadr_t *from, sizebuf_t *d)
+{
+ int n;
+ Conmsg m;
+
+ if(looprecv(src, from, d))
+ return true;
+ if(cfd == -1)
+ return false;
+
+ if((n = nbrecv(src == NS_SERVER ? udpchan : clchan, &m)) < 0)
+ sysfatal("NET_GetPacket:nbrecv: %r");
+ if(n == 0)
+ return false;
+
+ memcpy(from->ip, m.p->u+12, 4);
+ from->port = m.p->u[17] << 8 | m.p->u[16];
+ if(m.n == d->maxsize){
+ Com_Printf("Oversize packet from %s\n", NET_AdrToString(*from));
+ return false;
+ }
+ from->type = NA_IP;
+ d->cursize = m.n;
+ memcpy(d->data, m.buf, m.n);
+ return true;
+}
+
+void
+NET_SendPacket(netsrc_t src, int length, void *data, netadr_t to)
+{
+ int fd;
+ char *addr, *s, *lport;
+ uchar b[Bufsz+Hdrsz], u[IPaddrlen+2];
+ Conlist *p;
+
+ switch(to.type){
+ case NA_LOOPBACK:
+ loopsend(src, length, data, to);
+ break;
+ case NA_BROADCAST_IPX:
+ case NA_IPX:
+ break;
+ case NA_BROADCAST:
+ memset(to.ip, 0xff, 4);
+ addr = NET_AdrToString(to); /* port is PORT_SERVER */
+ s = strrchr(addr, ':');
+ *s++ = '\0';
+ if((fd = dial(netmkaddr(addr, "udp", s), clsrv, nil, nil)) < 0)
+ sysfatal("NET_SendPacket:dial bcast: %r");
+ if(write(fd, data, length) != length)
+ sysfatal("NET_SendPacket:write bcast: %r");
+ close(fd);
+ break;
+ case NA_IP:
+ if(cfd == -1)
+ break;
+
+ addr = NET_AdrToString(to);
+ qlock(&cnlock);
+ p = cnfind(addr);
+ qunlock(&cnlock);
+ if(p != nil){
+ fd = p->dfd;
+ if(fd == ufd || fd == cldfd){
+ memcpy(b, &p->h, Hdrsz);
+ memcpy(b+Hdrsz, data, length);
+ write(fd, b, length+Hdrsz);
+ break;
+ }
+ }else{
+ lport = strrchr(addr, ':');
+ *lport++ = '\0';
+ s = netmkaddr(addr, "udp", lport);
+ if((fd = dial(s, srv, nil, nil)) < 0)
+ sysfatal("NET_SendPacket:dial: %r");
+
+ memcpy(u, v4prefix, sizeof v4prefix);
+ memcpy(u+IPv4off, to.ip, IPv4addrlen);
+ u[16] = to.port;
+ u[17] = to.port >> 8;
+ *(lport-1) = ':';
+ qlock(&cnlock);
+ p = cnins(fd, addr, u, nil, src);
+ qunlock(&cnlock);
+
+ if(proccreate(dproc, p, 8196) < 0)
+ sysfatal("NET_SendPacket:proccreate: %r");
+ }
+ if(write(fd, data, length) != length)
+ sysfatal("NET_SendPacket:write: %r");
+ break;
+ default:
+ Com_Error(ERR_FATAL, "NET_SendPacket: bad address type");
+ }
+}
+
+void
+NET_Sleep(int ms) /* sleep for ms, or wakeup for stdio or incoming packets */
+{
+ if(cfd == -1 || dedicated != nil && !dedicated->value)
+ return; // we're not a server, just run full speed
+
+ if(send(tchan, &ms) < 0)
+ sysfatal("NET_Sleep:send: %r");
+ if(recv(fuckchan, nil) < 0)
+ sysfatal("NET_Sleep:recv: %r");
+ ms = -1;
+ if(nbsend(tchan, &ms) < 0) /* stop timer */
+ sysfatal("NET_Sleep:nbsend: %r");
+}
+
+static int
+openname(char *port, int *dfd, Channel **c)
+{
+ int fd;
+ char data[64], adir[40];
+
+ if((fd = announce(netmkaddr("*", "udp", port), adir)) < 0)
+ sysfatal("openname:announce udp!*!%s: %r", port);
+ if(fprint(fd, "headers") < 0)
+ sysfatal("openname: failed to set header mode: %r");
+ snprint(data, sizeof data, "%s/data", adir);
+ if((*dfd = open(data, ORDWR)) < 0)
+ sysfatal("openname:open %r");
+ if((*c = chancreate(sizeof(Conmsg), Nbuf)) == nil)
+ sysfatal("openname:chancreate: %r");
+ if(proccreate(uproc, *c, 8192) < 0)
+ sysfatal("openname:proccreate: %r");
+ return fd;
+}
+
+static void
+openudp(void)
+{
+ if(cfd != -1)
+ return;
+
+ /* svport value can be changed at any time */
+ if(svport->value == PORT_ANY || svport->value > 32767)
+ /* FIXME */
+ strncpy(srv, "*", sizeof(srv)-1);
+ else
+ strncpy(srv, svport->string, sizeof(srv)-1);
+ cfd = openname(srv, &ufd, &udpchan);
+
+ /* broadcast kluge */
+ if(clport->value == PORT_ANY || clport->value > 32767)
+ strncpy(clsrv, "*", sizeof(clsrv)-1);
+ else
+ strncpy(clsrv, clport->string, sizeof(clsrv)-1);
+ clfd = openname(clsrv, &cldfd, &clchan);
+}
+
+/* a single player game will only use the loopback code */
+void
+NET_Config(qboolean multiplayer)
+{
+ if(!multiplayer){ /* shut down existing udp connections */
+ threadkillgrp(THnet);
+ cnnuke();
+ if(udpchan != nil){
+ chanfree(udpchan);
+ udpchan = nil;
+ }
+ if(clchan != nil){
+ chanfree(clchan);
+ clchan = nil;
+ }
+ if(cfd != -1){
+ close(cfd);
+ cfd = -1;
+ }
+ if(clfd != -1){
+ close(clfd);
+ clfd = -1;
+ }
+ if(ufd != -1){
+ close(ufd);
+ ufd = -1;
+ }
+ if(cldfd != -1){
+ close(cldfd);
+ cldfd = -1;
+ }
+ }else{ /* announce open line and get cfd for it */
+ cninit();
+ openudp();
+ }
+}
+
+void
+NET_Shutdown(void)
+{
+ NET_Config(false);
+}
+
+void
+NET_Init(void)
+{
+ svport = Cvar_Get("port", va("%hu", PORT_SERVER), CVAR_NOSET);
+ clport = Cvar_Get("clport", va("%hu", CLPORT), CVAR_NOSET);
+}
--- /dev/null
+++ b/vid.c
@@ -1,0 +1,251 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "dat.h"
+#include "fns.h"
+
+refexport_t re; /* exported functions from refresh DLL */
+int resized;
+Point center;
+
+typedef ulong PIXEL;
+
+static int rwon;
+static uchar *framebuf;
+static Image *fbim;
+static PIXEL st2d_8to24table[256];
+static int shiftmask_fl;
+static int r_shift, g_shift, b_shift;
+static uint r_mask, g_mask, b_mask;
+
+refexport_t GetRefAPI(refimport_t);
+
+
+static void
+shiftmask_init(void)
+{
+ uint x;
+
+ r_mask = 0xff0000;
+ g_mask = 0xff00;
+ b_mask = 0xff;
+ for(r_shift = -8, x = 1; x < r_mask; x <<= 1)
+ r_shift++;
+ for(g_shift = -8, x = 1; x < g_mask; x <<= 1)
+ g_shift++;
+ for(b_shift = -8, x = 1; x < b_mask; x <<= 1)
+ b_shift++;
+ shiftmask_fl = 1;
+}
+
+static PIXEL
+rgb24(int r, int g, int b)
+{
+ PIXEL p = 0;
+
+ if(shiftmask_fl == 0)
+ shiftmask_init();
+
+ if(r_shift > 0)
+ p = r<<r_shift & r_mask;
+ else if(r_shift < 0)
+ p = r>>-r_shift & r_mask;
+ else
+ p |= r & r_mask;
+ if(g_shift > 0)
+ p |= g<<g_shift & g_mask;
+ else if(g_shift < 0)
+ p |= g>>-g_shift & g_mask;
+ else
+ p |= g & g_mask;
+ if(b_shift > 0)
+ p |= b<<b_shift & b_mask;
+ else if(b_shift < 0)
+ p |= b>>-b_shift & b_mask;
+ else
+ p |= b & b_mask;
+ return p;
+}
+
+static void
+st3_fixup(void)
+{
+ int x, y;
+ uchar *src;
+ PIXEL *dest;
+
+ for(y = 0; y < vid.height; y++){
+ src = &framebuf[y*vid.rowbytes];
+ dest = (PIXEL*)src;
+
+ /* vid.width % 8 not always 0
+ for(x = vid.width-1; x >= 0; x -= 8) {
+ dest[x ] = st2d_8to24table[src[x ]];
+ dest[x-1] = st2d_8to24table[src[x-1]];
+ dest[x-2] = st2d_8to24table[src[x-2]];
+ dest[x-3] = st2d_8to24table[src[x-3]];
+ dest[x-4] = st2d_8to24table[src[x-4]];
+ dest[x-5] = st2d_8to24table[src[x-5]];
+ dest[x-6] = st2d_8to24table[src[x-6]];
+ dest[x-7] = st2d_8to24table[src[x-7]];
+ }
+ */
+
+ for(x = vid.width-1; x >= 0; x--)
+ dest[x] = st2d_8to24table[src[x]];
+ }
+}
+
+static void
+resetfb(void)
+{
+ vid.width = Dx(screen->r);
+ vid.height = Dy(screen->r);
+ if(framebuf != nil){
+ free(framebuf);
+ framebuf = nil;
+ }
+ if(fbim != nil){
+ freeimage(fbim);
+ fbim = nil;
+ }
+ if((framebuf = malloc(sizeof *framebuf * vid.width * vid.height * screen->depth/8)) == nil)
+ sysfatal("resetfb:malloc: %r");
+ if((fbim = allocimage(display, Rect(0, 0, vid.width, vid.height), screen->chan, 1, DNofill)) == nil)
+ sysfatal("resetfb: %r");
+ vid.buffer = framebuf;
+ vid.rowbytes = vid.width * screen->depth/8;
+ center = addpt(screen->r.min, Pt(vid.width/2, vid.height/2));
+ sw_mode->modified = true; /* make ref_soft refresh its shit */
+}
+
+int
+SWimp_Init(void *, void *)
+{
+ srand(getpid());
+
+ if(initdraw(nil, nil, "quake2") < 0)
+ sysfatal("VID_Init:initdraw: %r\n");
+ resetfb();
+ rwon = 1;
+ vidref_val = VIDREF_SOFT;
+ return 1;
+}
+
+/* copy backbuffer to front buffer */
+void
+SWimp_EndFrame(void)
+{
+ if(resized){ /* skip frame if window resizes */
+ resized = 0;
+ if(getwindow(display, Refnone) < 0)
+ sysfatal("SWimp_EndFrame:getwindow: %r\n");
+ resetfb();
+ return;
+ }
+ st3_fixup();
+ loadimage(fbim, fbim->r, framebuf, vid.height * vid.rowbytes);
+ draw(screen, screen->r, fbim, nil, ZP);
+ flushimage(display, 1);
+}
+
+rserr_t
+SWimp_SetMode(int */*pwidth*/, int */*pheight*/, int /*mode*/, qboolean /*fullscreen*/)
+{
+ return rserr_ok;
+}
+
+/* nil palette == use existing; palette is expected to be in padded 4-byte xRGB format */
+void
+SWimp_SetPalette(uchar *palette)
+{
+ int i;
+
+ if(!rwon)
+ return;
+ if(!palette)
+ palette = (uchar *)sw_state.currentpalette;
+ for(i = 0; i < 256; i++)
+ st2d_8to24table[i] = rgb24(palette[i*4], palette[i*4+1], palette[i*4+2]);
+}
+
+void
+SWimp_Shutdown(void)
+{
+ if(!rwon)
+ return;
+ if(framebuf != nil)
+ free(framebuf);
+ if(fbim != nil)
+ freeimage(fbim);
+ rwon = 0;
+}
+
+void
+SWimp_AppActivate(qboolean /*active*/)
+{
+}
+
+void
+VID_Printf(int print_level, char *fmt, ...)
+{
+ va_list argptr;
+ char msg[4096];
+
+ va_start(argptr, fmt);
+ vsprintf(msg, fmt, argptr);
+ va_end(argptr);
+ if(print_level == PRINT_ALL)
+ Com_Printf("%s", msg);
+ else
+ Com_DPrintf("%s", msg);
+}
+
+void
+VID_Error(int err_level, char *fmt, ...)
+{
+ va_list argptr;
+ char msg[4096];
+
+ va_start(argptr, fmt);
+ vsprintf(msg, fmt, argptr);
+ va_end(argptr);
+ Com_Error(err_level, "%s", msg);
+}
+
+void
+VID_CheckChanges(void)
+{
+}
+
+void
+VID_Shutdown(void)
+{
+ R_Shutdown();
+}
+
+void
+VID_Init(void)
+{
+ refimport_t ri;
+
+ ri.Cmd_AddCommand = Cmd_AddCommand;
+ ri.Cmd_RemoveCommand = Cmd_RemoveCommand;
+ ri.Cmd_Argc = Cmd_Argc;
+ ri.Cmd_Argv = Cmd_Argv;
+ ri.Cmd_ExecuteText = Cbuf_ExecuteText;
+ ri.Con_Printf = VID_Printf;
+ ri.Sys_Error = VID_Error;
+ ri.FS_LoadFile = FS_LoadFile;
+ ri.FS_FreeFile = FS_FreeFile;
+ ri.FS_Gamedir = FS_Gamedir;
+ ri.Cvar_Get = Cvar_Get;
+ ri.Cvar_Set = Cvar_Set;
+ ri.Cvar_SetValue = Cvar_SetValue;
+ ri.Vid_MenuInit = VID_MenuInit;
+
+ re = GetRefAPI(ri);
+ re.Init(nil, nil);
+}
--- /dev/null
+++ b/vmenu.c
@@ -1,0 +1,138 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "dat.h"
+#include "fns.h"
+
+extern void M_PopMenu(void);
+
+static menuframework_t vmenu;
+static menuslider_t ssizeslide, gammaslide;
+static menulist_t fullscrbox;
+static menuaction_t applyaction, defaultsaction;
+
+
+void
+vmssize(void *s)
+{
+ Cvar_SetValue("viewsize", ((menuslider_t *)s)->curvalue * 10);
+}
+
+void
+vmgamma(void *s)
+{
+ // invert sense so greater = brighter, and scale to a range of 0.5 to 1.3
+ Cvar_SetValue("vid_gamma", 0.8 - (((menuslider_t *)s)->curvalue/10.0 - 0.5) + 0.5);
+}
+
+void
+vmreset(void *)
+{
+ VID_MenuInit();
+}
+
+void
+vmapply(void *)
+{
+ Cvar_SetValue("vid_gamma", 0.8 - (gammaslide.curvalue/10.0 - 0.5) + 0.5);
+ Cvar_SetValue("vid_fullscreen", fullscrbox.curvalue);
+ M_ForceMenuOff();
+}
+
+void
+VID_MenuInit(void)
+{
+ static char *yesno[] = {"no", "yes", nil};
+
+ if(!scr_viewsize)
+ scr_viewsize = Cvar_Get("viewsize", "100", CVAR_ARCHIVE);
+ ssizeslide.curvalue = scr_viewsize->value/10;
+
+ vmenu.x = vid.width * 0.50;
+ vmenu.nitems = 0;
+
+ ssizeslide.generic.type = MTYPE_SLIDER;
+ ssizeslide.generic.x = 0;
+ ssizeslide.generic.y = 20;
+ ssizeslide.generic.name = "screen size";
+ ssizeslide.minvalue = 3;
+ ssizeslide.maxvalue = 12;
+ ssizeslide.generic.callback = vmssize;
+
+ gammaslide.generic.type = MTYPE_SLIDER;
+ gammaslide.generic.x = 0;
+ gammaslide.generic.y = 30;
+ gammaslide.generic.name = "gamma";
+ gammaslide.generic.callback = vmgamma;
+ gammaslide.minvalue = 5;
+ gammaslide.maxvalue = 13;
+ gammaslide.curvalue = (1.3 - vid_gamma->value + 0.5) * 10;
+
+ fullscrbox.generic.type = MTYPE_SPINCONTROL;
+ fullscrbox.generic.x = 0;
+ fullscrbox.generic.y = 40;
+ fullscrbox.generic.name = "fullscreen";
+ fullscrbox.itemnames = yesno;
+ fullscrbox.curvalue = vid_fullscreen->value;
+
+ defaultsaction.generic.type = MTYPE_ACTION;
+ defaultsaction.generic.name = "reset to default";
+ defaultsaction.generic.x = 0;
+ defaultsaction.generic.y = 90;
+ defaultsaction.generic.callback = vmreset;
+
+ applyaction.generic.type = MTYPE_ACTION;
+ applyaction.generic.name = "apply";
+ applyaction.generic.x = 0;
+ applyaction.generic.y = 100;
+ applyaction.generic.callback = vmapply;
+
+ Menu_AddItem(&vmenu, (void *)&ssizeslide);
+ Menu_AddItem(&vmenu, (void *)&gammaslide);
+ Menu_AddItem(&vmenu, (void *)&fullscrbox);
+ Menu_AddItem(&vmenu, (void *)&defaultsaction);
+ Menu_AddItem(&vmenu, (void *)&applyaction);
+
+ Menu_Center(&vmenu);
+ vmenu.x -= 8;
+}
+
+void
+VID_MenuDraw(void)
+{
+ int w, h;
+
+ Draw_GetPicSize(&w, &h, "m_banner_video");
+ Draw_Pic(vid.width/2 - w/2, vid.height/2 - 110, "m_banner_video");
+ Menu_AdjustCursor(&vmenu, 1); // starting position
+ Menu_Draw(&vmenu);
+}
+
+char *VID_MenuKey (int key)
+{
+ static char *sound = "misc/menu1.wav";
+
+ switch(key){
+ case K_ESCAPE:
+ M_PopMenu();
+ return NULL;
+ case K_UPARROW:
+ vmenu.cursor--;
+ Menu_AdjustCursor(&vmenu, -1);
+ break;
+ case K_DOWNARROW:
+ vmenu.cursor++;
+ Menu_AdjustCursor(&vmenu, 1);
+ break;
+ case K_LEFTARROW:
+ Menu_SlideItem(&vmenu, -1);
+ break;
+ case K_RIGHTARROW:
+ Menu_SlideItem(&vmenu, 1);
+ break;
+ case K_ENTER:
+ Menu_SelectItem(&vmenu);
+ break;
+ }
+ return sound;
+}