From 76a5aa612381ba1ba7567ca408197c235f5869e5 Mon Sep 17 00:00:00 2001 From: Tim Angus Date: Wed, 3 Jan 2001 21:54:12 +0000 Subject: im making a right mess of this --- src/game/bg_lib.c | 1337 ---------------------- src/game/bg_lib.h | 94 -- src/game/bg_local.h | 110 -- src/game/bg_misc.c | 1709 ---------------------------- src/game/bg_pmove.c | 2818 ----------------------------------------------- src/game/bg_public.h | 783 ------------- src/game/bg_slidemove.c | 327 ------ src/game/g_active.c | 1059 ------------------ src/game/g_buildable.c | 627 ----------- src/game/g_client.c | 1543 -------------------------- src/game/g_cmds.c | 2050 ---------------------------------- src/game/g_combat.c | 1193 -------------------- src/game/g_local.h | 977 ---------------- src/game/g_main.c | 1881 ------------------------------- src/game/g_mem.c | 64 -- src/game/g_misc.c | 384 ------- src/game/g_missile.c | 519 --------- src/game/g_mover.c | 1490 ------------------------- src/game/g_public.h | 413 ------- src/game/g_session.c | 188 ---- src/game/g_spawn.c | 635 ----------- src/game/g_svcmds.c | 488 -------- src/game/g_syscalls.asm | 217 ---- src/game/g_syscalls.c | 765 ------------- src/game/g_target.c | 472 -------- src/game/g_team.c | 1046 ------------------ src/game/g_trigger.c | 469 -------- src/game/g_utils.c | 718 ------------ src/game/g_weapon.c | 800 -------------- src/game/q_math.c | 1355 ----------------------- src/game/q_shared.c | 1229 --------------------- src/game/q_shared.h | 1206 -------------------- src/game/surfaceflags.h | 81 -- 33 files changed, 29047 deletions(-) delete mode 100644 src/game/bg_lib.c delete mode 100644 src/game/bg_lib.h delete mode 100644 src/game/bg_local.h delete mode 100644 src/game/bg_misc.c delete mode 100644 src/game/bg_pmove.c delete mode 100644 src/game/bg_public.h delete mode 100644 src/game/bg_slidemove.c delete mode 100644 src/game/g_active.c delete mode 100644 src/game/g_buildable.c delete mode 100644 src/game/g_client.c delete mode 100644 src/game/g_cmds.c delete mode 100644 src/game/g_combat.c delete mode 100644 src/game/g_local.h delete mode 100644 src/game/g_main.c delete mode 100644 src/game/g_mem.c delete mode 100644 src/game/g_misc.c delete mode 100644 src/game/g_missile.c delete mode 100644 src/game/g_mover.c delete mode 100644 src/game/g_public.h delete mode 100644 src/game/g_session.c delete mode 100644 src/game/g_spawn.c delete mode 100644 src/game/g_svcmds.c delete mode 100644 src/game/g_syscalls.asm delete mode 100644 src/game/g_syscalls.c delete mode 100644 src/game/g_target.c delete mode 100644 src/game/g_team.c delete mode 100644 src/game/g_trigger.c delete mode 100644 src/game/g_utils.c delete mode 100644 src/game/g_weapon.c delete mode 100644 src/game/q_math.c delete mode 100644 src/game/q_shared.c delete mode 100644 src/game/q_shared.h delete mode 100644 src/game/surfaceflags.h (limited to 'src/game') diff --git a/src/game/bg_lib.c b/src/game/bg_lib.c deleted file mode 100644 index e55b47bd..00000000 --- a/src/game/bg_lib.c +++ /dev/null @@ -1,1337 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// Copyright (C) 1999-2000 Id Software, Inc. -// -// bg_lib,c -- standard C library replacement routines used by code -// compiled for the virtual machine - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "q_shared.h" - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -#if 0 -static char sccsid[] = "@(#)qsort.c 8.1 (Berkeley) 6/4/93"; -#endif -static const char rcsid[] = - "$Id$"; -#endif /* LIBC_SCCS and not lint */ - -//typedef int cmp_t(const void *, const void *); -static char* med3(char *, char *, char *, cmp_t *); -static void swapfunc(char *, char *, int, int); - -#ifndef min -#define min(a, b) (a) < (b) ? a : b -#endif - -/* - * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". - */ -#define swapcode(TYPE, parmi, parmj, n) { \ - long i = (n) / sizeof (TYPE); \ - register TYPE *pi = (TYPE *) (parmi); \ - register TYPE *pj = (TYPE *) (parmj); \ - do { \ - register TYPE t = *pi; \ - *pi++ = *pj; \ - *pj++ = t; \ - } while (--i > 0); \ -} - -#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ - es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; - -static void -swapfunc(a, b, n, swaptype) - char *a, *b; - int n, swaptype; -{ - if(swaptype <= 1) - swapcode(long, a, b, n) - else - swapcode(char, a, b, n) -} - -#define swap(a, b) \ - if (swaptype == 0) { \ - long t = *(long *)(a); \ - *(long *)(a) = *(long *)(b); \ - *(long *)(b) = t; \ - } else \ - swapfunc(a, b, es, swaptype) - -#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) - -static char * -med3(a, b, c, cmp) - char *a, *b, *c; - cmp_t *cmp; -{ - return cmp(a, b) < 0 ? - (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a )) - :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); -} - -void -qsort(a, n, es, cmp) - void *a; - size_t n, es; - cmp_t *cmp; -{ - char *pa, *pb, *pc, *pd, *pl, *pm, *pn; - int d, r, swaptype, swap_cnt; - -loop: SWAPINIT(a, es); - swap_cnt = 0; - if (n < 7) { - for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) - for (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0; - pl -= es) - swap(pl, pl - es); - return; - } - pm = (char *)a + (n / 2) * es; - if (n > 7) { - pl = a; - pn = (char *)a + (n - 1) * es; - if (n > 40) { - d = (n / 8) * es; - pl = med3(pl, pl + d, pl + 2 * d, cmp); - pm = med3(pm - d, pm, pm + d, cmp); - pn = med3(pn - 2 * d, pn - d, pn, cmp); - } - pm = med3(pl, pm, pn, cmp); - } - swap(a, pm); - pa = pb = (char *)a + es; - - pc = pd = (char *)a + (n - 1) * es; - for (;;) { - while (pb <= pc && (r = cmp(pb, a)) <= 0) { - if (r == 0) { - swap_cnt = 1; - swap(pa, pb); - pa += es; - } - pb += es; - } - while (pb <= pc && (r = cmp(pc, a)) >= 0) { - if (r == 0) { - swap_cnt = 1; - swap(pc, pd); - pd -= es; - } - pc -= es; - } - if (pb > pc) - break; - swap(pb, pc); - swap_cnt = 1; - pb += es; - pc -= es; - } - if (swap_cnt == 0) { /* Switch to insertion sort */ - for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) - for (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0; - pl -= es) - swap(pl, pl - es); - return; - } - - pn = (char *)a + n * es; - r = min(pa - (char *)a, pb - pa); - vecswap(a, pb - r, r); - r = min(pd - pc, pn - pd - es); - vecswap(pb, pn - r, r); - if ((r = pb - pa) > es) - qsort(a, r / es, es, cmp); - if ((r = pd - pc) > es) { - /* Iterate rather than recurse to save stack space */ - a = pn - r; - n = r / es; - goto loop; - } -/* qsort(pn - r, r / es, es, cmp);*/ -} - -//================================================================================== - - -// this file is excluded from release builds because of intrinsics - -size_t strlen( const char *string ) { - const char *s; - - s = string; - while ( *s ) { - s++; - } - return s - string; -} - - -char *strcat( char *strDestination, const char *strSource ) { - char *s; - - s = strDestination; - while ( *s ) { - s++; - } - while ( *strSource ) { - *s++ = *strSource++; - } - *s = 0; - return strDestination; -} - -char *strcpy( char *strDestination, const char *strSource ) { - char *s; - - s = strDestination; - while ( *strSource ) { - *s++ = *strSource++; - } - *s = 0; - return strDestination; -} - - -int strcmp( const char *string1, const char *string2 ) { - while ( *string1 == *string2 && *string1 && *string2 ) { - string1++; - string2++; - } - return *string1 - *string2; -} - - -char *strchr( const char *string, int c ) { - while ( *string ) { - if ( *string == c ) { - return ( char * )string; - } - string++; - } - return (char *)0; -} - -char *strstr( const char *string, const char *strCharSet ) { - while ( *string ) { - int i; - - for ( i = 0 ; strCharSet[i] ; i++ ) { - if ( string[i] != strCharSet[i] ) { - break; - } - } - if ( !strCharSet[i] ) { - return (char *)string; - } - string++; - } - return (char *)0; -} - -#if !defined ( _MSC_VER ) && !defined ( __linux__ ) - -int tolower( int c ) { - if ( c >= 'A' && c <= 'Z' ) { - c += 'a' - 'A'; - } - return c; -} - - -int toupper( int c ) { - if ( c >= 'a' && c <= 'z' ) { - c += 'A' - 'a'; - } - return c; -} - -#endif -//#ifndef _MSC_VER - -void *memmove( void *dest, const void *src, size_t count ) { - int i; - - if ( dest > src ) { - for ( i = count-1 ; i >= 0 ; i-- ) { - ((char *)dest)[i] = ((char *)src)[i]; - } - } else { - for ( i = 0 ; i < count ; i++ ) { - ((char *)dest)[i] = ((char *)src)[i]; - } - } - return dest; -} - - -#if 0 - -double floor( double x ) { - return (int)(x + 0x40000000) - 0x40000000; -} - -void *memset( void *dest, int c, size_t count ) { - while ( count-- ) { - ((char *)dest)[count] = c; - } - return dest; -} - -void *memcpy( void *dest, const void *src, size_t count ) { - while ( count-- ) { - ((char *)dest)[count] = ((char *)src)[count]; - } - return dest; -} - -char *strncpy( char *strDest, const char *strSource, size_t count ) { - char *s; - - s = strDest; - while ( *strSource && count ) { - *s++ = *strSource++; - count--; - } - while ( count-- ) { - *s++ = 0; - } - return strDest; -} - -double sqrt( double x ) { - float y; - float delta; - float maxError; - - if ( x <= 0 ) { - return 0; - } - - // initial guess - y = x / 2; - - // refine - maxError = x * 0.001; - - do { - delta = ( y * y ) - x; - y -= delta / ( 2 * y ); - } while ( delta > maxError || delta < -maxError ); - - return y; -} - - -float sintable[1024] = { -0.000000,0.001534,0.003068,0.004602,0.006136,0.007670,0.009204,0.010738, -0.012272,0.013805,0.015339,0.016873,0.018407,0.019940,0.021474,0.023008, -0.024541,0.026075,0.027608,0.029142,0.030675,0.032208,0.033741,0.035274, -0.036807,0.038340,0.039873,0.041406,0.042938,0.044471,0.046003,0.047535, -0.049068,0.050600,0.052132,0.053664,0.055195,0.056727,0.058258,0.059790, -0.061321,0.062852,0.064383,0.065913,0.067444,0.068974,0.070505,0.072035, -0.073565,0.075094,0.076624,0.078153,0.079682,0.081211,0.082740,0.084269, -0.085797,0.087326,0.088854,0.090381,0.091909,0.093436,0.094963,0.096490, -0.098017,0.099544,0.101070,0.102596,0.104122,0.105647,0.107172,0.108697, -0.110222,0.111747,0.113271,0.114795,0.116319,0.117842,0.119365,0.120888, -0.122411,0.123933,0.125455,0.126977,0.128498,0.130019,0.131540,0.133061, -0.134581,0.136101,0.137620,0.139139,0.140658,0.142177,0.143695,0.145213, -0.146730,0.148248,0.149765,0.151281,0.152797,0.154313,0.155828,0.157343, -0.158858,0.160372,0.161886,0.163400,0.164913,0.166426,0.167938,0.169450, -0.170962,0.172473,0.173984,0.175494,0.177004,0.178514,0.180023,0.181532, -0.183040,0.184548,0.186055,0.187562,0.189069,0.190575,0.192080,0.193586, -0.195090,0.196595,0.198098,0.199602,0.201105,0.202607,0.204109,0.205610, -0.207111,0.208612,0.210112,0.211611,0.213110,0.214609,0.216107,0.217604, -0.219101,0.220598,0.222094,0.223589,0.225084,0.226578,0.228072,0.229565, -0.231058,0.232550,0.234042,0.235533,0.237024,0.238514,0.240003,0.241492, -0.242980,0.244468,0.245955,0.247442,0.248928,0.250413,0.251898,0.253382, -0.254866,0.256349,0.257831,0.259313,0.260794,0.262275,0.263755,0.265234, -0.266713,0.268191,0.269668,0.271145,0.272621,0.274097,0.275572,0.277046, -0.278520,0.279993,0.281465,0.282937,0.284408,0.285878,0.287347,0.288816, -0.290285,0.291752,0.293219,0.294685,0.296151,0.297616,0.299080,0.300543, -0.302006,0.303468,0.304929,0.306390,0.307850,0.309309,0.310767,0.312225, -0.313682,0.315138,0.316593,0.318048,0.319502,0.320955,0.322408,0.323859, -0.325310,0.326760,0.328210,0.329658,0.331106,0.332553,0.334000,0.335445, -0.336890,0.338334,0.339777,0.341219,0.342661,0.344101,0.345541,0.346980, -0.348419,0.349856,0.351293,0.352729,0.354164,0.355598,0.357031,0.358463, -0.359895,0.361326,0.362756,0.364185,0.365613,0.367040,0.368467,0.369892, -0.371317,0.372741,0.374164,0.375586,0.377007,0.378428,0.379847,0.381266, -0.382683,0.384100,0.385516,0.386931,0.388345,0.389758,0.391170,0.392582, -0.393992,0.395401,0.396810,0.398218,0.399624,0.401030,0.402435,0.403838, -0.405241,0.406643,0.408044,0.409444,0.410843,0.412241,0.413638,0.415034, -0.416430,0.417824,0.419217,0.420609,0.422000,0.423390,0.424780,0.426168, -0.427555,0.428941,0.430326,0.431711,0.433094,0.434476,0.435857,0.437237, -0.438616,0.439994,0.441371,0.442747,0.444122,0.445496,0.446869,0.448241, -0.449611,0.450981,0.452350,0.453717,0.455084,0.456449,0.457813,0.459177, -0.460539,0.461900,0.463260,0.464619,0.465976,0.467333,0.468689,0.470043, -0.471397,0.472749,0.474100,0.475450,0.476799,0.478147,0.479494,0.480839, -0.482184,0.483527,0.484869,0.486210,0.487550,0.488889,0.490226,0.491563, -0.492898,0.494232,0.495565,0.496897,0.498228,0.499557,0.500885,0.502212, -0.503538,0.504863,0.506187,0.507509,0.508830,0.510150,0.511469,0.512786, -0.514103,0.515418,0.516732,0.518045,0.519356,0.520666,0.521975,0.523283, -0.524590,0.525895,0.527199,0.528502,0.529804,0.531104,0.532403,0.533701, -0.534998,0.536293,0.537587,0.538880,0.540171,0.541462,0.542751,0.544039, -0.545325,0.546610,0.547894,0.549177,0.550458,0.551738,0.553017,0.554294, -0.555570,0.556845,0.558119,0.559391,0.560662,0.561931,0.563199,0.564466, -0.565732,0.566996,0.568259,0.569521,0.570781,0.572040,0.573297,0.574553, -0.575808,0.577062,0.578314,0.579565,0.580814,0.582062,0.583309,0.584554, -0.585798,0.587040,0.588282,0.589521,0.590760,0.591997,0.593232,0.594466, -0.595699,0.596931,0.598161,0.599389,0.600616,0.601842,0.603067,0.604290, -0.605511,0.606731,0.607950,0.609167,0.610383,0.611597,0.612810,0.614022, -0.615232,0.616440,0.617647,0.618853,0.620057,0.621260,0.622461,0.623661, -0.624859,0.626056,0.627252,0.628446,0.629638,0.630829,0.632019,0.633207, -0.634393,0.635578,0.636762,0.637944,0.639124,0.640303,0.641481,0.642657, -0.643832,0.645005,0.646176,0.647346,0.648514,0.649681,0.650847,0.652011, -0.653173,0.654334,0.655493,0.656651,0.657807,0.658961,0.660114,0.661266, -0.662416,0.663564,0.664711,0.665856,0.667000,0.668142,0.669283,0.670422, -0.671559,0.672695,0.673829,0.674962,0.676093,0.677222,0.678350,0.679476, -0.680601,0.681724,0.682846,0.683965,0.685084,0.686200,0.687315,0.688429, -0.689541,0.690651,0.691759,0.692866,0.693971,0.695075,0.696177,0.697278, -0.698376,0.699473,0.700569,0.701663,0.702755,0.703845,0.704934,0.706021, -0.707107,0.708191,0.709273,0.710353,0.711432,0.712509,0.713585,0.714659, -0.715731,0.716801,0.717870,0.718937,0.720003,0.721066,0.722128,0.723188, -0.724247,0.725304,0.726359,0.727413,0.728464,0.729514,0.730563,0.731609, -0.732654,0.733697,0.734739,0.735779,0.736817,0.737853,0.738887,0.739920, -0.740951,0.741980,0.743008,0.744034,0.745058,0.746080,0.747101,0.748119, -0.749136,0.750152,0.751165,0.752177,0.753187,0.754195,0.755201,0.756206, -0.757209,0.758210,0.759209,0.760207,0.761202,0.762196,0.763188,0.764179, -0.765167,0.766154,0.767139,0.768122,0.769103,0.770083,0.771061,0.772036, -0.773010,0.773983,0.774953,0.775922,0.776888,0.777853,0.778817,0.779778, -0.780737,0.781695,0.782651,0.783605,0.784557,0.785507,0.786455,0.787402, -0.788346,0.789289,0.790230,0.791169,0.792107,0.793042,0.793975,0.794907, -0.795837,0.796765,0.797691,0.798615,0.799537,0.800458,0.801376,0.802293, -0.803208,0.804120,0.805031,0.805940,0.806848,0.807753,0.808656,0.809558, -0.810457,0.811355,0.812251,0.813144,0.814036,0.814926,0.815814,0.816701, -0.817585,0.818467,0.819348,0.820226,0.821103,0.821977,0.822850,0.823721, -0.824589,0.825456,0.826321,0.827184,0.828045,0.828904,0.829761,0.830616, -0.831470,0.832321,0.833170,0.834018,0.834863,0.835706,0.836548,0.837387, -0.838225,0.839060,0.839894,0.840725,0.841555,0.842383,0.843208,0.844032, -0.844854,0.845673,0.846491,0.847307,0.848120,0.848932,0.849742,0.850549, -0.851355,0.852159,0.852961,0.853760,0.854558,0.855354,0.856147,0.856939, -0.857729,0.858516,0.859302,0.860085,0.860867,0.861646,0.862424,0.863199, -0.863973,0.864744,0.865514,0.866281,0.867046,0.867809,0.868571,0.869330, -0.870087,0.870842,0.871595,0.872346,0.873095,0.873842,0.874587,0.875329, -0.876070,0.876809,0.877545,0.878280,0.879012,0.879743,0.880471,0.881197, -0.881921,0.882643,0.883363,0.884081,0.884797,0.885511,0.886223,0.886932, -0.887640,0.888345,0.889048,0.889750,0.890449,0.891146,0.891841,0.892534, -0.893224,0.893913,0.894599,0.895284,0.895966,0.896646,0.897325,0.898001, -0.898674,0.899346,0.900016,0.900683,0.901349,0.902012,0.902673,0.903332, -0.903989,0.904644,0.905297,0.905947,0.906596,0.907242,0.907886,0.908528, -0.909168,0.909806,0.910441,0.911075,0.911706,0.912335,0.912962,0.913587, -0.914210,0.914830,0.915449,0.916065,0.916679,0.917291,0.917901,0.918508, -0.919114,0.919717,0.920318,0.920917,0.921514,0.922109,0.922701,0.923291, -0.923880,0.924465,0.925049,0.925631,0.926210,0.926787,0.927363,0.927935, -0.928506,0.929075,0.929641,0.930205,0.930767,0.931327,0.931884,0.932440, -0.932993,0.933544,0.934093,0.934639,0.935184,0.935726,0.936266,0.936803, -0.937339,0.937872,0.938404,0.938932,0.939459,0.939984,0.940506,0.941026, -0.941544,0.942060,0.942573,0.943084,0.943593,0.944100,0.944605,0.945107, -0.945607,0.946105,0.946601,0.947094,0.947586,0.948075,0.948561,0.949046, -0.949528,0.950008,0.950486,0.950962,0.951435,0.951906,0.952375,0.952842, -0.953306,0.953768,0.954228,0.954686,0.955141,0.955594,0.956045,0.956494, -0.956940,0.957385,0.957826,0.958266,0.958703,0.959139,0.959572,0.960002, -0.960431,0.960857,0.961280,0.961702,0.962121,0.962538,0.962953,0.963366, -0.963776,0.964184,0.964590,0.964993,0.965394,0.965793,0.966190,0.966584, -0.966976,0.967366,0.967754,0.968139,0.968522,0.968903,0.969281,0.969657, -0.970031,0.970403,0.970772,0.971139,0.971504,0.971866,0.972226,0.972584, -0.972940,0.973293,0.973644,0.973993,0.974339,0.974684,0.975025,0.975365, -0.975702,0.976037,0.976370,0.976700,0.977028,0.977354,0.977677,0.977999, -0.978317,0.978634,0.978948,0.979260,0.979570,0.979877,0.980182,0.980485, -0.980785,0.981083,0.981379,0.981673,0.981964,0.982253,0.982539,0.982824, -0.983105,0.983385,0.983662,0.983937,0.984210,0.984480,0.984749,0.985014, -0.985278,0.985539,0.985798,0.986054,0.986308,0.986560,0.986809,0.987057, -0.987301,0.987544,0.987784,0.988022,0.988258,0.988491,0.988722,0.988950, -0.989177,0.989400,0.989622,0.989841,0.990058,0.990273,0.990485,0.990695, -0.990903,0.991108,0.991311,0.991511,0.991710,0.991906,0.992099,0.992291, -0.992480,0.992666,0.992850,0.993032,0.993212,0.993389,0.993564,0.993737, -0.993907,0.994075,0.994240,0.994404,0.994565,0.994723,0.994879,0.995033, -0.995185,0.995334,0.995481,0.995625,0.995767,0.995907,0.996045,0.996180, -0.996313,0.996443,0.996571,0.996697,0.996820,0.996941,0.997060,0.997176, -0.997290,0.997402,0.997511,0.997618,0.997723,0.997825,0.997925,0.998023, -0.998118,0.998211,0.998302,0.998390,0.998476,0.998559,0.998640,0.998719, -0.998795,0.998870,0.998941,0.999011,0.999078,0.999142,0.999205,0.999265, -0.999322,0.999378,0.999431,0.999481,0.999529,0.999575,0.999619,0.999660, -0.999699,0.999735,0.999769,0.999801,0.999831,0.999858,0.999882,0.999905, -0.999925,0.999942,0.999958,0.999971,0.999981,0.999989,0.999995,0.999999 -}; - -double sin( double x ) { - int index; - int quad; - - index = 1024 * x / (M_PI * 0.5); - quad = ( index >> 10 ) & 3; - index &= 1023; - switch ( quad ) { - case 0: - return sintable[index]; - case 1: - return sintable[1023-index]; - case 2: - return -sintable[index]; - case 3: - return -sintable[1023-index]; - } - return 0; -} - - -double cos( double x ) { - int index; - int quad; - - index = 1024 * x / (M_PI * 0.5); - quad = ( index >> 10 ) & 3; - index &= 1023; - switch ( quad ) { - case 3: - return sintable[index]; - case 0: - return sintable[1023-index]; - case 1: - return -sintable[index]; - case 2: - return -sintable[1023-index]; - } - return 0; -} - - -/* -void create_acostable( void ) { - int i; - FILE *fp; - float a; - - fp = fopen("c:\\acostable.txt", "w"); - fprintf(fp, "float acostable[] = {"); - for (i = 0; i < 1024; i++) { - if (!(i & 7)) - fprintf(fp, "\n"); - a = acos( (float) -1 + i / 512 ); - fprintf(fp, "%1.8f,", a); - } - fprintf(fp, "\n}\n"); - fclose(fp); -} -*/ - - -float acostable[] = { -3.14159265,3.07908248,3.05317551,3.03328655,3.01651113,3.00172442,2.98834964,2.97604422, -2.96458497,2.95381690,2.94362719,2.93393068,2.92466119,2.91576615,2.90720289,2.89893629, -2.89093699,2.88318015,2.87564455,2.86831188,2.86116621,2.85419358,2.84738169,2.84071962, -2.83419760,2.82780691,2.82153967,2.81538876,2.80934770,2.80341062,2.79757211,2.79182724, -2.78617145,2.78060056,2.77511069,2.76969824,2.76435988,2.75909250,2.75389319,2.74875926, -2.74368816,2.73867752,2.73372510,2.72882880,2.72398665,2.71919677,2.71445741,2.70976688, -2.70512362,2.70052613,2.69597298,2.69146283,2.68699438,2.68256642,2.67817778,2.67382735, -2.66951407,2.66523692,2.66099493,2.65678719,2.65261279,2.64847088,2.64436066,2.64028133, -2.63623214,2.63221238,2.62822133,2.62425835,2.62032277,2.61641398,2.61253138,2.60867440, -2.60484248,2.60103507,2.59725167,2.59349176,2.58975488,2.58604053,2.58234828,2.57867769, -2.57502832,2.57139977,2.56779164,2.56420354,2.56063509,2.55708594,2.55355572,2.55004409, -2.54655073,2.54307530,2.53961750,2.53617701,2.53275354,2.52934680,2.52595650,2.52258238, -2.51922417,2.51588159,2.51255441,2.50924238,2.50594525,2.50266278,2.49939476,2.49614096, -2.49290115,2.48967513,2.48646269,2.48326362,2.48007773,2.47690482,2.47374472,2.47059722, -2.46746215,2.46433933,2.46122860,2.45812977,2.45504269,2.45196720,2.44890314,2.44585034, -2.44280867,2.43977797,2.43675809,2.43374890,2.43075025,2.42776201,2.42478404,2.42181622, -2.41885841,2.41591048,2.41297232,2.41004380,2.40712480,2.40421521,2.40131491,2.39842379, -2.39554173,2.39266863,2.38980439,2.38694889,2.38410204,2.38126374,2.37843388,2.37561237, -2.37279910,2.36999400,2.36719697,2.36440790,2.36162673,2.35885335,2.35608768,2.35332964, -2.35057914,2.34783610,2.34510044,2.34237208,2.33965094,2.33693695,2.33423003,2.33153010, -2.32883709,2.32615093,2.32347155,2.32079888,2.31813284,2.31547337,2.31282041,2.31017388, -2.30753373,2.30489988,2.30227228,2.29965086,2.29703556,2.29442632,2.29182309,2.28922580, -2.28663439,2.28404881,2.28146900,2.27889490,2.27632647,2.27376364,2.27120637,2.26865460, -2.26610827,2.26356735,2.26103177,2.25850149,2.25597646,2.25345663,2.25094195,2.24843238, -2.24592786,2.24342836,2.24093382,2.23844420,2.23595946,2.23347956,2.23100444,2.22853408, -2.22606842,2.22360742,2.22115104,2.21869925,2.21625199,2.21380924,2.21137096,2.20893709, -2.20650761,2.20408248,2.20166166,2.19924511,2.19683280,2.19442469,2.19202074,2.18962092, -2.18722520,2.18483354,2.18244590,2.18006225,2.17768257,2.17530680,2.17293493,2.17056692, -2.16820274,2.16584236,2.16348574,2.16113285,2.15878367,2.15643816,2.15409630,2.15175805, -2.14942338,2.14709226,2.14476468,2.14244059,2.14011997,2.13780279,2.13548903,2.13317865, -2.13087163,2.12856795,2.12626757,2.12397047,2.12167662,2.11938600,2.11709859,2.11481435, -2.11253326,2.11025530,2.10798044,2.10570867,2.10343994,2.10117424,2.09891156,2.09665185, -2.09439510,2.09214129,2.08989040,2.08764239,2.08539725,2.08315496,2.08091550,2.07867884, -2.07644495,2.07421383,2.07198545,2.06975978,2.06753681,2.06531651,2.06309887,2.06088387, -2.05867147,2.05646168,2.05425445,2.05204979,2.04984765,2.04764804,2.04545092,2.04325628, -2.04106409,2.03887435,2.03668703,2.03450211,2.03231957,2.03013941,2.02796159,2.02578610, -2.02361292,2.02144204,2.01927344,2.01710710,2.01494300,2.01278113,2.01062146,2.00846399, -2.00630870,2.00415556,2.00200457,1.99985570,1.99770895,1.99556429,1.99342171,1.99128119, -1.98914271,1.98700627,1.98487185,1.98273942,1.98060898,1.97848051,1.97635399,1.97422942, -1.97210676,1.96998602,1.96786718,1.96575021,1.96363511,1.96152187,1.95941046,1.95730088, -1.95519310,1.95308712,1.95098292,1.94888050,1.94677982,1.94468089,1.94258368,1.94048818, -1.93839439,1.93630228,1.93421185,1.93212308,1.93003595,1.92795046,1.92586659,1.92378433, -1.92170367,1.91962459,1.91754708,1.91547113,1.91339673,1.91132385,1.90925250,1.90718266, -1.90511432,1.90304746,1.90098208,1.89891815,1.89685568,1.89479464,1.89273503,1.89067683, -1.88862003,1.88656463,1.88451060,1.88245794,1.88040664,1.87835668,1.87630806,1.87426076, -1.87221477,1.87017008,1.86812668,1.86608457,1.86404371,1.86200412,1.85996577,1.85792866, -1.85589277,1.85385809,1.85182462,1.84979234,1.84776125,1.84573132,1.84370256,1.84167495, -1.83964848,1.83762314,1.83559892,1.83357582,1.83155381,1.82953289,1.82751305,1.82549429, -1.82347658,1.82145993,1.81944431,1.81742973,1.81541617,1.81340362,1.81139207,1.80938151, -1.80737194,1.80536334,1.80335570,1.80134902,1.79934328,1.79733848,1.79533460,1.79333164, -1.79132959,1.78932843,1.78732817,1.78532878,1.78333027,1.78133261,1.77933581,1.77733985, -1.77534473,1.77335043,1.77135695,1.76936428,1.76737240,1.76538132,1.76339101,1.76140148, -1.75941271,1.75742470,1.75543743,1.75345090,1.75146510,1.74948002,1.74749565,1.74551198, -1.74352900,1.74154672,1.73956511,1.73758417,1.73560389,1.73362426,1.73164527,1.72966692, -1.72768920,1.72571209,1.72373560,1.72175971,1.71978441,1.71780969,1.71583556,1.71386199, -1.71188899,1.70991653,1.70794462,1.70597325,1.70400241,1.70203209,1.70006228,1.69809297, -1.69612416,1.69415584,1.69218799,1.69022062,1.68825372,1.68628727,1.68432127,1.68235571, -1.68039058,1.67842588,1.67646160,1.67449772,1.67253424,1.67057116,1.66860847,1.66664615, -1.66468420,1.66272262,1.66076139,1.65880050,1.65683996,1.65487975,1.65291986,1.65096028, -1.64900102,1.64704205,1.64508338,1.64312500,1.64116689,1.63920905,1.63725148,1.63529416, -1.63333709,1.63138026,1.62942366,1.62746728,1.62551112,1.62355517,1.62159943,1.61964388, -1.61768851,1.61573332,1.61377831,1.61182346,1.60986877,1.60791422,1.60595982,1.60400556, -1.60205142,1.60009739,1.59814349,1.59618968,1.59423597,1.59228235,1.59032882,1.58837536, -1.58642196,1.58446863,1.58251535,1.58056211,1.57860891,1.57665574,1.57470259,1.57274945, -1.57079633,1.56884320,1.56689007,1.56493692,1.56298375,1.56103055,1.55907731,1.55712403, -1.55517069,1.55321730,1.55126383,1.54931030,1.54735668,1.54540297,1.54344917,1.54149526, -1.53954124,1.53758710,1.53563283,1.53367843,1.53172389,1.52976919,1.52781434,1.52585933, -1.52390414,1.52194878,1.51999323,1.51803748,1.51608153,1.51412537,1.51216900,1.51021240, -1.50825556,1.50629849,1.50434117,1.50238360,1.50042576,1.49846765,1.49650927,1.49455060, -1.49259163,1.49063237,1.48867280,1.48671291,1.48475270,1.48279215,1.48083127,1.47887004, -1.47690845,1.47494650,1.47298419,1.47102149,1.46905841,1.46709493,1.46513106,1.46316677, -1.46120207,1.45923694,1.45727138,1.45530538,1.45333893,1.45137203,1.44940466,1.44743682, -1.44546850,1.44349969,1.44153038,1.43956057,1.43759024,1.43561940,1.43364803,1.43167612, -1.42970367,1.42773066,1.42575709,1.42378296,1.42180825,1.41983295,1.41785705,1.41588056, -1.41390346,1.41192573,1.40994738,1.40796840,1.40598877,1.40400849,1.40202755,1.40004594, -1.39806365,1.39608068,1.39409701,1.39211264,1.39012756,1.38814175,1.38615522,1.38416795, -1.38217994,1.38019117,1.37820164,1.37621134,1.37422025,1.37222837,1.37023570,1.36824222, -1.36624792,1.36425280,1.36225684,1.36026004,1.35826239,1.35626387,1.35426449,1.35226422, -1.35026307,1.34826101,1.34625805,1.34425418,1.34224937,1.34024364,1.33823695,1.33622932, -1.33422072,1.33221114,1.33020059,1.32818904,1.32617649,1.32416292,1.32214834,1.32013273, -1.31811607,1.31609837,1.31407960,1.31205976,1.31003885,1.30801684,1.30599373,1.30396951, -1.30194417,1.29991770,1.29789009,1.29586133,1.29383141,1.29180031,1.28976803,1.28773456, -1.28569989,1.28366400,1.28162688,1.27958854,1.27754894,1.27550809,1.27346597,1.27142257, -1.26937788,1.26733189,1.26528459,1.26323597,1.26118602,1.25913471,1.25708205,1.25502803, -1.25297262,1.25091583,1.24885763,1.24679802,1.24473698,1.24267450,1.24061058,1.23854519, -1.23647833,1.23440999,1.23234015,1.23026880,1.22819593,1.22612152,1.22404557,1.22196806, -1.21988898,1.21780832,1.21572606,1.21364219,1.21155670,1.20946958,1.20738080,1.20529037, -1.20319826,1.20110447,1.19900898,1.19691177,1.19481283,1.19271216,1.19060973,1.18850553, -1.18639955,1.18429178,1.18218219,1.18007079,1.17795754,1.17584244,1.17372548,1.17160663, -1.16948589,1.16736324,1.16523866,1.16311215,1.16098368,1.15885323,1.15672081,1.15458638, -1.15244994,1.15031147,1.14817095,1.14602836,1.14388370,1.14173695,1.13958808,1.13743709, -1.13528396,1.13312866,1.13097119,1.12881153,1.12664966,1.12448556,1.12231921,1.12015061, -1.11797973,1.11580656,1.11363107,1.11145325,1.10927308,1.10709055,1.10490563,1.10271831, -1.10052856,1.09833638,1.09614174,1.09394462,1.09174500,1.08954287,1.08733820,1.08513098, -1.08292118,1.08070879,1.07849378,1.07627614,1.07405585,1.07183287,1.06960721,1.06737882, -1.06514770,1.06291382,1.06067715,1.05843769,1.05619540,1.05395026,1.05170226,1.04945136, -1.04719755,1.04494080,1.04268110,1.04041841,1.03815271,1.03588399,1.03361221,1.03133735, -1.02905939,1.02677830,1.02449407,1.02220665,1.01991603,1.01762219,1.01532509,1.01302471, -1.01072102,1.00841400,1.00610363,1.00378986,1.00147268,0.99915206,0.99682798,0.99450039, -0.99216928,0.98983461,0.98749636,0.98515449,0.98280898,0.98045980,0.97810691,0.97575030, -0.97338991,0.97102573,0.96865772,0.96628585,0.96391009,0.96153040,0.95914675,0.95675912, -0.95436745,0.95197173,0.94957191,0.94716796,0.94475985,0.94234754,0.93993099,0.93751017, -0.93508504,0.93265556,0.93022170,0.92778341,0.92534066,0.92289341,0.92044161,0.91798524, -0.91552424,0.91305858,0.91058821,0.90811309,0.90563319,0.90314845,0.90065884,0.89816430, -0.89566479,0.89316028,0.89065070,0.88813602,0.88561619,0.88309116,0.88056088,0.87802531, -0.87548438,0.87293806,0.87038629,0.86782901,0.86526619,0.86269775,0.86012366,0.85754385, -0.85495827,0.85236686,0.84976956,0.84716633,0.84455709,0.84194179,0.83932037,0.83669277, -0.83405893,0.83141877,0.82877225,0.82611928,0.82345981,0.82079378,0.81812110,0.81544172, -0.81275556,0.81006255,0.80736262,0.80465570,0.80194171,0.79922057,0.79649221,0.79375655, -0.79101352,0.78826302,0.78550497,0.78273931,0.77996593,0.77718475,0.77439569,0.77159865, -0.76879355,0.76598029,0.76315878,0.76032891,0.75749061,0.75464376,0.75178826,0.74892402, -0.74605092,0.74316887,0.74027775,0.73737744,0.73446785,0.73154885,0.72862033,0.72568217, -0.72273425,0.71977644,0.71680861,0.71383064,0.71084240,0.70784376,0.70483456,0.70181469, -0.69878398,0.69574231,0.69268952,0.68962545,0.68654996,0.68346288,0.68036406,0.67725332, -0.67413051,0.67099544,0.66784794,0.66468783,0.66151492,0.65832903,0.65512997,0.65191753, -0.64869151,0.64545170,0.64219789,0.63892987,0.63564741,0.63235028,0.62903824,0.62571106, -0.62236849,0.61901027,0.61563615,0.61224585,0.60883911,0.60541564,0.60197515,0.59851735, -0.59504192,0.59154856,0.58803694,0.58450672,0.58095756,0.57738911,0.57380101,0.57019288, -0.56656433,0.56291496,0.55924437,0.55555212,0.55183778,0.54810089,0.54434099,0.54055758, -0.53675018,0.53291825,0.52906127,0.52517867,0.52126988,0.51733431,0.51337132,0.50938028, -0.50536051,0.50131132,0.49723200,0.49312177,0.48897987,0.48480547,0.48059772,0.47635573, -0.47207859,0.46776530,0.46341487,0.45902623,0.45459827,0.45012983,0.44561967,0.44106652, -0.43646903,0.43182577,0.42713525,0.42239588,0.41760600,0.41276385,0.40786755,0.40291513, -0.39790449,0.39283339,0.38769946,0.38250016,0.37723277,0.37189441,0.36648196,0.36099209, -0.35542120,0.34976542,0.34402054,0.33818204,0.33224495,0.32620390,0.32005298,0.31378574, -0.30739505,0.30087304,0.29421096,0.28739907,0.28042645,0.27328078,0.26594810,0.25841250, -0.25065566,0.24265636,0.23438976,0.22582651,0.21693146,0.20766198,0.19796546,0.18777575, -0.17700769,0.16554844,0.15324301,0.13986823,0.12508152,0.10830610,0.08841715,0.06251018, -}; - -double acos( double x ) { - int index; - - if (x < -1) - x = -1; - if (x > 1) - x = 1; - index = (float) (1.0 + x) * 511.9; - return acostable[index]; -} - - -double atan2( double y, double x ) { - float base; - float temp; - float dir; - float test; - int i; - - if ( x < 0 ) { - if ( y >= 0 ) { - // quad 1 - base = M_PI / 2; - temp = x; - x = y; - y = -temp; - } else { - // quad 2 - base = M_PI; - x = -x; - y = -y; - } - } else { - if ( y < 0 ) { - // quad 3 - base = 3 * M_PI / 2; - temp = x; - x = -y; - y = temp; - } - } - - if ( y > x ) { - base += M_PI/2; - temp = x; - x = y; - y = temp; - dir = -1; - } else { - dir = 1; - } - - // calcualte angle in octant 0 - if ( x == 0 ) { - return base; - } - y /= x; - - for ( i = 0 ; i < 512 ; i++ ) { - test = sintable[i] / sintable[1023-i]; - if ( test > y ) { - break; - } - } - - return base + dir * i * ( M_PI/2048); -} - - -#endif - -double tan( double x ) { - return sin(x) / cos(x); -} - - -static int randSeed = 0; - -void srand( unsigned seed ) { - randSeed = seed; -} - -int rand( void ) { - randSeed = (69069 * randSeed + 1); - return randSeed & 0x7fff; -} - -double atof( const char *string ) { - float sign; - float value; - int c; - - - // skip whitespace - while ( *string <= ' ' ) { - if ( !*string ) { - return 0; - } - string++; - } - - // check sign - switch ( *string ) { - case '+': - string++; - sign = 1; - break; - case '-': - string++; - sign = -1; - break; - default: - sign = 1; - break; - } - - // read digits - value = 0; - c = string[0]; - if ( c != '.' ) { - do { - c = *string++; - if ( c < '0' || c > '9' ) { - break; - } - c -= '0'; - value = value * 10 + c; - } while ( 1 ); - } else { - string++; - } - - // check for decimal point - if ( c == '.' ) { - double fraction; - - fraction = 0.1; - do { - c = *string++; - if ( c < '0' || c > '9' ) { - break; - } - c -= '0'; - value += c * fraction; - fraction *= 0.1; - } while ( 1 ); - - } - - // not handling 10e10 notation... - - return value * sign; -} - -double _atof( const char **stringPtr ) { - const char *string; - float sign; - float value; - int c; - - string = *stringPtr; - - // skip whitespace - while ( *string <= ' ' ) { - if ( !*string ) { - *stringPtr = string; - return 0; - } - string++; - } - - // check sign - switch ( *string ) { - case '+': - string++; - sign = 1; - break; - case '-': - string++; - sign = -1; - break; - default: - sign = 1; - break; - } - - // read digits - value = 0; - if ( string[0] != '.' ) { - do { - c = *string++; - if ( c < '0' || c > '9' ) { - break; - } - c -= '0'; - value = value * 10 + c; - } while ( 1 ); - } - - // check for decimal point - if ( c == '.' ) { - double fraction; - - fraction = 0.1; - do { - c = *string++; - if ( c < '0' || c > '9' ) { - break; - } - c -= '0'; - value += c * fraction; - fraction *= 0.1; - } while ( 1 ); - - } - - // not handling 10e10 notation... - *stringPtr = string; - - return value * sign; -} - - -#if !defined( _MSC_VER ) && !defined( __linux__ ) - -int atoi( const char *string ) { - int sign; - int value; - int c; - - - // skip whitespace - while ( *string <= ' ' ) { - if ( !*string ) { - return 0; - } - string++; - } - - // check sign - switch ( *string ) { - case '+': - string++; - sign = 1; - break; - case '-': - string++; - sign = -1; - break; - default: - sign = 1; - break; - } - - // read digits - value = 0; - do { - c = *string++; - if ( c < '0' || c > '9' ) { - break; - } - c -= '0'; - value = value * 10 + c; - } while ( 1 ); - - // not handling 10e10 notation... - - return value * sign; -} - - -int _atoi( const char **stringPtr ) { - int sign; - int value; - int c; - const char *string; - - string = *stringPtr; - - // skip whitespace - while ( *string <= ' ' ) { - if ( !*string ) { - return 0; - } - string++; - } - - // check sign - switch ( *string ) { - case '+': - string++; - sign = 1; - break; - case '-': - string++; - sign = -1; - break; - default: - sign = 1; - break; - } - - // read digits - value = 0; - do { - c = *string++; - if ( c < '0' || c > '9' ) { - break; - } - c -= '0'; - value = value * 10 + c; - } while ( 1 ); - - // not handling 10e10 notation... - - *stringPtr = string; - - return value * sign; -} - -int abs( int n ) { - return n < 0 ? -n : n; -} - -double fabs( double x ) { - return x < 0 ? -x : x; -} - - - -//========================================================= - - -#define ALT 0x00000001 /* alternate form */ -#define HEXPREFIX 0x00000002 /* add 0x or 0X prefix */ -#define LADJUST 0x00000004 /* left adjustment */ -#define LONGDBL 0x00000008 /* long double */ -#define LONGINT 0x00000010 /* long integer */ -#define QUADINT 0x00000020 /* quad integer */ -#define SHORTINT 0x00000040 /* short integer */ -#define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */ -#define FPT 0x00000100 /* floating point number */ - -#define to_digit(c) ((c) - '0') -#define is_digit(c) ((unsigned)to_digit(c) <= 9) -#define to_char(n) ((n) + '0') - -void AddInt( char **buf_p, int val, int width, int flags ) { - char text[32]; - int digits; - int signedVal; - char *buf; - - digits = 0; - signedVal = val; - if ( val < 0 ) { - val = -val; - } - do { - text[digits++] = '0' + val % 10; - val /= 10; - } while ( val ); - - if ( signedVal < 0 ) { - text[digits++] = '-'; - } - - buf = *buf_p; - - if( !( flags & LADJUST ) ) { - while ( digits < width ) { - *buf++ = ( flags & ZEROPAD ) ? '0' : ' '; - width--; - } - } - - while ( digits-- ) { - *buf++ = text[digits]; - width--; - } - - if( flags & LADJUST ) { - while ( width-- ) { - *buf++ = ( flags & ZEROPAD ) ? '0' : ' '; - } - } - - *buf_p = buf; -} - -void AddFloat( char **buf_p, float fval, int width, int prec ) { - char text[32]; - int digits; - float signedVal; - char *buf; - int val; - - // get the sign - signedVal = fval; - if ( fval < 0 ) { - fval = -fval; - } - - // write the float number - digits = 0; - val = (int)fval; - do { - text[digits++] = '0' + val % 10; - val /= 10; - } while ( val ); - - if ( signedVal < 0 ) { - text[digits++] = '-'; - } - - buf = *buf_p; - - while ( digits < width ) { - *buf++ = ' '; - width--; - } - - while ( digits-- ) { - *buf++ = text[digits]; - } - - *buf_p = buf; - - if (prec < 0) - prec = 6; - // write the fraction - digits = 0; - while (digits < prec) { - fval -= (int) fval; - fval *= 10.0; - val = (int) fval; - text[digits++] = '0' + val % 10; - } - - if (digits > 0) { - buf = *buf_p; - *buf++ = '.'; - for (prec = 0; prec < digits; prec++) { - *buf++ = text[prec]; - } - *buf_p = buf; - } -} - - -void AddString( char **buf_p, char *string, int width, int prec ) { - int size; - char *buf; - - buf = *buf_p; - - if ( string == NULL ) { - string = "(null)"; - prec = -1; - } - - if ( prec >= 0 ) { - for( size = 0; size < prec; size++ ) { - if( string[size] == '\0' ) { - break; - } - } - } - else { - size = strlen( string ); - } - - width -= size; - - while( size-- ) { - *buf++ = *string++; - } - - while( width-- > 0 ) { - *buf++ = ' '; - } - - *buf_p = buf; -} - -/* -vsprintf - -I'm not going to support a bunch of the more arcane stuff in here -just to keep it simpler. For example, the '*' and '$' are not -currently supported. I've tried to make it so that it will just -parse and ignore formats we don't support. -*/ -int vsprintf( char *buffer, const char *fmt, va_list argptr ) { - int *arg; - char *buf_p; - char ch; - int flags; - int width; - int prec; - int n; - char sign; - - buf_p = buffer; - arg = (int *)argptr; - - while( qtrue ) { - // run through the format string until we hit a '%' or '\0' - for ( ch = *fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++ ) { - *buf_p++ = ch; - } - if ( ch == '\0' ) { - goto done; - } - - // skip over the '%' - fmt++; - - // reset formatting state - flags = 0; - width = 0; - prec = -1; - sign = '\0'; - -rflag: - ch = *fmt++; -reswitch: - switch( ch ) { - case '-': - flags |= LADJUST; - goto rflag; - case '.': - n = 0; - while( is_digit( ( ch = *fmt++ ) ) ) { - n = 10 * n + ( ch - '0' ); - } - prec = n < 0 ? -1 : n; - goto reswitch; - case '0': - flags |= ZEROPAD; - goto rflag; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - n = 0; - do { - n = 10 * n + ( ch - '0' ); - ch = *fmt++; - } while( is_digit( ch ) ); - width = n; - goto reswitch; - case 'c': - *buf_p++ = (char)*arg; - arg++; - break; - case 'd': - case 'i': - AddInt( &buf_p, *arg, width, flags ); - arg++; - break; - case 'f': - AddFloat( &buf_p, *(double *)arg, width, prec ); -#ifdef __LCC__ - arg += 1; // everything is 32 bit in my compiler -#else - arg += 2; -#endif - break; - case 's': - AddString( &buf_p, (char *)*arg, width, prec ); - arg++; - break; - case '%': - *buf_p++ = ch; - break; - default: - *buf_p++ = (char)*arg; - arg++; - break; - } - } - -done: - *buf_p = 0; - return buf_p - buffer; -} - - -/* this is really crappy */ -int sscanf( const char *buffer, const char *fmt, ... ) { - int cmd; - int **arg; - int count; - - arg = (int **)&fmt + 1; - count = 0; - - while ( *fmt ) { - if ( fmt[0] != '%' ) { - fmt++; - continue; - } - - cmd = fmt[1]; - fmt += 2; - - switch ( cmd ) { - case 'i': - case 'd': - case 'u': - **arg = _atoi( &buffer ); - break; - case 'f': - *(float *)*arg = _atof( &buffer ); - break; - } - arg++; - } - - return count; -} - -#endif diff --git a/src/game/bg_lib.h b/src/game/bg_lib.h deleted file mode 100644 index 306684b0..00000000 --- a/src/game/bg_lib.h +++ /dev/null @@ -1,94 +0,0 @@ -// bg_lib.h -- standard C library replacement routines used by code -// compiled for the virtual machine - -// This file is NOT included on native builds - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -typedef int size_t; - -typedef char * va_list; -#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) -#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) -#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) -#define va_end(ap) ( ap = (va_list)0 ) - -#define CHAR_BIT 8 /* number of bits in a char */ -#define SCHAR_MIN (-128) /* minimum signed char value */ -#define SCHAR_MAX 127 /* maximum signed char value */ -#define UCHAR_MAX 0xff /* maximum unsigned char value */ - -#define SHRT_MIN (-32768) /* minimum (signed) short value */ -#define SHRT_MAX 32767 /* maximum (signed) short value */ -#define USHRT_MAX 0xffff /* maximum unsigned short value */ -#define INT_MIN (-2147483647 - 1) /* minimum (signed) int value */ -#define INT_MAX 2147483647 /* maximum (signed) int value */ -#define UINT_MAX 0xffffffff /* maximum unsigned int value */ -#define LONG_MIN (-2147483647L - 1) /* minimum (signed) long value */ -#define LONG_MAX 2147483647L /* maximum (signed) long value */ -#define ULONG_MAX 0xffffffffUL /* maximum unsigned long value */ - -// Misc functions -typedef int cmp_t(const void *, const void *); -void qsort(void *a, size_t n, size_t es, cmp_t *cmp); -void srand( unsigned seed ); -int rand( void ); - -// String functions -size_t strlen( const char *string ); -char *strcat( char *strDestination, const char *strSource ); -char *strcpy( char *strDestination, const char *strSource ); -int strcmp( const char *string1, const char *string2 ); -char *strchr( const char *string, int c ); -char *strstr( const char *string, const char *strCharSet ); -char *strncpy( char *strDest, const char *strSource, size_t count ); -int tolower( int c ); -int toupper( int c ); - -double atof( const char *string ); -double _atof( const char **stringPtr ); -int atoi( const char *string ); -int _atoi( const char **stringPtr ); - -int vsprintf( char *buffer, const char *fmt, va_list argptr ); -int sscanf( const char *buffer, const char *fmt, ... ); - -// Memory functions -void *memmove( void *dest, const void *src, size_t count ); -void *memset( void *dest, int c, size_t count ); -void *memcpy( void *dest, const void *src, size_t count ); - -// Math functions -double ceil( double x ); -double floor( double x ); -double sqrt( double x ); -double sin( double x ); -double cos( double x ); -double atan2( double y, double x ); -double tan( double x ); -int abs( int n ); -double fabs( double x ); -double acos( double x ); - diff --git a/src/game/bg_local.h b/src/game/bg_local.h deleted file mode 100644 index de2803ec..00000000 --- a/src/game/bg_local.h +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// bg_local.h -- local definitions for the bg (both games) files - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#define MIN_WALK_NORMAL 0.7f // can't walk on very steep slopes - -#define STEPSIZE 18 - -#define JUMP_VELOCITY 270 - -#define TIMER_LAND 130 -#define TIMER_GESTURE (34*66+50) - -#define OVERCLIP 1.001f - -// 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 forward, right, up; - float frametime; - - int msec; - - qboolean walking; - qboolean groundPlane; - trace_t groundTrace; - - float impactSpeed; - - vec3_t previous_origin; - vec3_t previous_velocity; - int previous_waterlevel; -} pml_t; - -//TA: struct that stores smooth ops -// there is an array of these in bg_pmove.c -typedef struct -{ - float time; - - vec3_t rotAxis; - float rotAngle; -} smooth_t; - -//TA: make this into a cvar later.... -#define SMOOTHTIME 300 -#define MAXSMOOTHS 10 - -//TA: wall climbing local -typedef struct -{ - smooth_t sList[ MAXSMOOTHS ]; - - qboolean justFallen; - vec3_t lastNormal; - vec3_t nonSvangles; -} wcl_t; - -extern pmove_t *pm; -extern pml_t pml; - -// movement parameters -extern float pm_stopspeed; -extern float pm_duckScale; -extern float pm_swimScale; -extern float pm_wadeScale; - -extern float pm_accelerate; -extern float pm_airaccelerate; -extern float pm_wateraccelerate; -extern float pm_flyaccelerate; - -extern float pm_friction; -extern float pm_waterfriction; -extern float pm_flightfriction; - -extern int c_pmove; - -void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce ); -void PM_AddTouchEnt( int entityNum ); -void PM_AddEvent( int newEvent ); - -qboolean PM_SlideMove( qboolean gravity ); -void PM_StepSlideMove( qboolean gravity ); - diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c deleted file mode 100644 index 130ff0d8..00000000 --- a/src/game/bg_misc.c +++ /dev/null @@ -1,1709 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// bg_misc.c -- both games misc functions, all completely stateless - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "q_shared.h" -#include "bg_public.h" - -/*QUAKED item_***** ( 0 0 0 ) (-16 -16 -16) (16 16 16) suspended -DO NOT USE THIS CLASS, IT JUST HOLDS GENERAL INFORMATION. -The suspended flag will allow items to hang in the air, otherwise they are dropped to the next surface. - -If an item is the target of another entity, it will not spawn in until fired. - -An item fires all of its targets when it is picked up. If the toucher can't carry it, the targets won't be fired. - -"notfree" if set to 1, don't spawn in free for all games -"notteam" if set to 1, don't spawn in team games -"notsingle" if set to 1, don't spawn in single player games -"wait" override the default wait before respawning. -1 = never respawn automatically, which can be used with targeted spawning. -"random" random number of plus or minus seconds varied from the respawn time -"count" override quantity or duration on most items. -*/ - -gitem_t bg_itemlist[] = -{ - { - NULL, - NULL, - { NULL, - NULL, - 0, 0} , -/* icon */ NULL, -/* pickup */ NULL, - 0, - 0, - 0, -/* precache */ "", -/* sounds */ "" - }, // leave index 0 alone - - // - // ARMOR - // - -/*QUAKED item_armor_shard (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_armor_shard", - "sound/misc/ar1_pkup.wav", - { "models/powerups/armor/shard.md3", - "models/powerups/armor/shard_sphere.md3", - 0, 0} , - "icons/iconr_shard", - "Armor Shard", - 5, - IT_ARMOR, - 0, - "", - "" - },*/ - -/*QUAKED item_armor_combat (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_armor_combat", - "sound/misc/ar2_pkup.wav", - { "models/powerups/armor/armor_yel.md3", - 0, 0, 0}, - "icons/iconr_yellow", - "Armor", - 50, - IT_ARMOR, - 0, - "", - "" - },*/ - -/*QUAKED item_armor_body (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_armor_body", - "sound/misc/ar3_pkup.wav", - { "models/powerups/armor/armor_red.md3", - 0, 0, 0}, - "icons/iconr_red", - "Heavy Armor", - 100, - IT_ARMOR, - 0, - "", - "" - },*/ - - // - // health - // -/*QUAKED item_health_small (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_health_small", - "sound/items/s_health.wav", - { "models/powerups/health/small_cross.md3", - "models/powerups/health/small_sphere.md3", - 0, 0 }, - "icons/iconh_green", - "5 Health", - 5, - IT_HEALTH, - 0, - "", - "" - },*/ - -/*QUAKED item_health (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_health", - "sound/items/n_health.wav", - { "models/powerups/health/medium_cross.md3", - "models/powerups/health/medium_sphere.md3", - 0, 0 }, - "icons/iconh_yellow", - "25 Health", - 25, - IT_HEALTH, - 0, - "", - "" - },*/ - -/*QUAKED item_health_large (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_health_large", - "sound/items/l_health.wav", - { "models/powerups/health/large_cross.md3", - "models/powerups/health/large_sphere.md3", - 0, 0 }, - "icons/iconh_red", - "50 Health", - 50, - IT_HEALTH, - 0, - "", - "" - },*/ - -/*QUAKED item_health_mega (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_health_mega", - "sound/items/m_health.wav", - { "models/powerups/health/mega_cross.md3", - "models/powerups/health/mega_sphere.md3", - 0, 0 }, - "icons/iconh_mega", - "Mega Health", - 100, - IT_HEALTH, - 0, - "", - "" - },*/ - - - // - // WEAPONS - // - -/*QUAKED weapon_gauntlet (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - -//TA:FIXME: must keep gauntlet and machinegun for now or bots have a fit and prevent game working - - { - "weapon_gauntlet", - "sound/misc/w_pkup.wav", - { "models/weapons2/gauntlet/gauntlet.md3", - 0, 0, 0}, - "icons/iconw_gauntlet", - "Gauntlet", - 0, - IT_WEAPON, - WP_GAUNTLET, - "", - "" - }, - -/*QUAKED weapon_venom (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_venom", - "sound/misc/w_pkup.wav", - { "models/weapons2/gauntlet/gauntlet.md3", - 0, 0, 0}, - "icons/iconw_gauntlet", - "Venom", - 0, - IT_WEAPON, - WP_VENOM, - "", - "" - }, - -/*QUAKED weapon_abuild (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_abuild", - "sound/misc/w_pkup.wav", - { "models/weapons2/gauntlet/gauntlet.md3", - 0, 0, 0}, - "icons/iconw_gauntlet", - "ABuild", - 0, - IT_WEAPON, - WP_ABUILD, - "", - "" - }, - -/*QUAKED weapon_hbuild (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_hbuild", - "sound/misc/w_pkup.wav", - { "models/weapons2/gauntlet/gauntlet.md3", - 0, 0, 0}, - "icons/iconw_gauntlet", - "HBuild", - 0, - IT_WEAPON, - WP_HBUILD, - "", - "" - }, - -/*QUAKED weapon_scanner (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_scanner", - "sound/misc/w_pkup.wav", - { "models/weapons2/shotgun/shotgun.md3", - 0, 0, 0}, - "icons/iconw_shotgun", - "Scanner", - 0, - IT_WEAPON, - WP_SCANNER, - "", - "" - }, - -/*QUAKED weapon_shotgun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "weapon_shotgun", - "sound/misc/w_pkup.wav", - { "models/weapons2/shotgun/shotgun.md3", - 0, 0, 0}, - "icons/iconw_shotgun", - "Shotgun", - 10, - IT_WEAPON, - WP_SHOTGUN, - "", - "" - },*/ - -/*QUAKED weapon_machinegun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_machinegun", - "sound/misc/w_pkup.wav", - { "models/weapons2/machinegun/machinegun.md3", - 0, 0, 0}, - "icons/iconw_machinegun", - "Machinegun", - 40, - IT_WEAPON, - WP_MACHINEGUN, - "", - "" - }, - -/*QUAKED weapon_chaingun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_chaingun", - "sound/misc/w_pkup.wav", - { "models/weapons2/machinegun/machinegun.md3", - 0, 0, 0}, - "icons/iconw_machinegun", - "Chaingun", - 40, - IT_WEAPON, - WP_CHAINGUN, - "", - "" - }, - -/*QUAKED weapon_ggrenade (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_ggrenade", - "sound/misc/w_pkup.wav", - { "models/weapons2/gauntlet/gauntlet.md3", - 0, 0, 0}, - "icons/iconw_gauntlet", - "Gas Grenade", - 0, - IT_WEAPON, - WP_GGRENADE, - "", - "" - }, - -/*QUAKED weapon_grenadelauncher (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "weapon_grenadelauncher", - "sound/misc/w_pkup.wav", - { "models/weapons2/grenadel/grenadel.md3", - 0, 0, 0}, - "icons/iconw_grenade", - "Grenade Launcher", - 10, - IT_WEAPON, - WP_GRENADE_LAUNCHER, - "", - "sound/weapons/grenade/hgrenb1a.wav sound/weapons/grenade/hgrenb2a.wav" - },*/ - -/*QUAKED weapon_rocketlauncher (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "weapon_rocketlauncher", - "sound/misc/w_pkup.wav", - { "models/weapons2/rocketl/rocketl.md3", - 0, 0, 0}, - "icons/iconw_rocket", - "Rocket Launcher", - 10, - IT_WEAPON, - WP_ROCKET_LAUNCHER, - "", - "" - },*/ - -/*QUAKED weapon_lightning (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "weapon_lightning", - "sound/misc/w_pkup.wav", - { "models/weapons2/lightning/lightning.md3", - 0, 0, 0}, - "icons/iconw_lightning", - "Lightning Gun", - 100, - IT_WEAPON, - WP_LIGHTNING, - "", - "" - },*/ - -/*QUAKED weapon_railgun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "weapon_railgun", - "sound/misc/w_pkup.wav", - { "models/weapons2/railgun/railgun.md3", - 0, 0, 0}, - "icons/iconw_railgun", - "Railgun", - 10, - IT_WEAPON, - WP_RAILGUN, - "", - "" - },*/ - -/*QUAKED weapon_plasmagun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_plasmagun", - "sound/misc/w_pkup.wav", - { "models/weapons2/plasma/plasma.md3", - 0, 0, 0}, - "icons/iconw_plasma", - "Plasma Gun", - 50, - IT_WEAPON, - WP_PLASMAGUN, - "", - "" - }, - -/*QUAKED weapon_flamer (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_flamer", - "sound/misc/w_pkup.wav", - { "models/weapons2/plasma/plasma.md3", - 0, 0, 0}, - "icons/iconw_plasma", - "Flame Thrower", - 50, - IT_WEAPON, - WP_FLAMER, - "", - "" - }, - -/*QUAKED weapon_bfg (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - { - "weapon_bfg", - "sound/misc/w_pkup.wav", - { "models/weapons2/bfg/bfg.md3", - 0, 0, 0}, - "icons/iconw_bfg", - "Dual BFG", - 0, - IT_WEAPON, - WP_BFG, - "", - "" - }, - -/*QUAKED weapon_grapplinghook (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "weapon_grapplinghook", - "sound/misc/w_pkup.wav", - { "models/weapons2/grapple/grapple.md3", - 0, 0, 0}, - "icons/iconw_grapple", - "Grappling Hook", - 0, - IT_WEAPON, - WP_GRAPPLING_HOOK, - "", - "" - },*/ - - // - // AMMO ITEMS - // - -/*QUAKED ammo_shells (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "ammo_shells", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/shotgunam.md3", - 0, 0, 0}, - "icons/icona_shotgun", - "Shells", - 10, - IT_AMMO, - WP_SHOTGUN, - "", - "" - },*/ - -/*QUAKED ammo_bullets (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "ammo_bullets", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/machinegunam.md3", - 0, 0, 0}, - "icons/icona_machinegun", - "Bullets", - 50, - IT_AMMO, - WP_MACHINEGUN, - "", - "" - },*/ - -/*QUAKED ammo_grenades (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "ammo_grenades", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/grenadeam.md3", - 0, 0, 0}, - "icons/icona_grenade", - "Grenades", - 5, - IT_AMMO, - WP_GRENADE_LAUNCHER, - "", - "" - },*/ - -/*QUAKED ammo_cells (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "ammo_cells", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/plasmaam.md3", - 0, 0, 0}, - "icons/icona_plasma", - "Cells", - 30, - IT_AMMO, - WP_PLASMAGUN, - "", - "" - },*/ - -/*QUAKED ammo_lightning (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "ammo_lightning", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/lightningam.md3", - 0, 0, 0}, - "icons/icona_lightning", - "Lightning", - 60, - IT_AMMO, - WP_LIGHTNING, - "", - "" - },*/ - -/*QUAKED ammo_rockets (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "ammo_rockets", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/rocketam.md3", - 0, 0, 0}, - "icons/icona_rocket", - "Rockets", - 5, - IT_AMMO, - WP_ROCKET_LAUNCHER, - "", - "" - },*/ - -/*QUAKED ammo_slugs (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "ammo_slugs", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/railgunam.md3", - 0, 0, 0}, - "icons/icona_railgun", - "Slugs", - 10, - IT_AMMO, - WP_RAILGUN, - "", - "" - },*/ - -/*QUAKED ammo_bfg (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "ammo_bfg", - "sound/misc/am_pkup.wav", - { "models/powerups/ammo/bfgam.md3", - 0, 0, 0}, - "icons/icona_bfg", - "Bfg Ammo", - 15, - IT_AMMO, - WP_BFG, - "", - "" - },*/ - - // - // HOLDABLE ITEMS - // -/*QUAKED holdable_teleporter (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "holdable_teleporter", - "sound/items/holdable.wav", - { "models/powerups/holdable/teleporter.md3", - 0, 0, 0}, - "icons/teleporter", - "Personal Teleporter", - 60, - IT_HOLDABLE, - HI_TELEPORTER, - "", - "" - },*/ - -/*QUAKED holdable_medkit (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "holdable_medkit", - "sound/items/holdable.wav", - { "models/powerups/holdable/medkit.md3", - "models/powerups/holdable/medkit_sphere.md3", - 0, 0}, - "icons/medkit", - "Medkit", - 60, - IT_HOLDABLE, - HI_MEDKIT, - "", - "sound/items/use_medkit.wav" - },*/ - - // - // POWERUP ITEMS - // -/*QUAKED item_quad (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_quad", - "sound/items/quaddamage.wav", - { "models/powerups/instant/quad.md3", - "models/powerups/instant/quad_ring.md3", - 0, 0 }, - "icons/quad", - "Quad Damage", - 30, - IT_POWERUP, - PW_QUAD, - "", - "sound/items/damage2.wav sound/items/damage3.wav" - },*/ - -/*QUAKED item_enviro (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_enviro", - "sound/items/protect.wav", - { "models/powerups/instant/enviro.md3", - "models/powerups/instant/enviro_ring.md3", - 0, 0 }, - "icons/envirosuit", - "Battle Suit", - 30, - IT_POWERUP, - PW_BATTLESUIT, - "", - "sound/items/airout.wav sound/items/protect3.wav" - },*/ - -/*QUAKED item_haste (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_haste", - "sound/items/haste.wav", - { "models/powerups/instant/haste.md3", - "models/powerups/instant/haste_ring.md3", - 0, 0 }, - "icons/haste", - "Speed", - 30, - IT_POWERUP, - PW_HASTE, - "", - "" - },*/ - -/*QUAKED item_invis (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_invis", - "sound/items/invisibility.wav", - { "models/powerups/instant/invis.md3", - "models/powerups/instant/invis_ring.md3", - 0, 0 }, - "icons/invis", - "Invisibility", - 30, - IT_POWERUP, - PW_INVIS, - "", - "" - },*/ - -/*QUAKED item_regen (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_regen", - "sound/items/regeneration.wav", - { "models/powerups/instant/regen.md3", - "models/powerups/instant/regen_ring.md3", - 0, 0 }, - "icons/regen", - "Regeneration", - 30, - IT_POWERUP, - PW_REGEN, - "", - "sound/items/regen.wav" - },*/ - -/*QUAKED item_flight (.3 .3 1) (-16 -16 -16) (16 16 16) suspended -*/ - /*{ - "item_flight", - "sound/items/flight.wav", - { "models/powerups/instant/flight.md3", - "models/powerups/instant/flight_ring.md3", - 0, 0 }, - "icons/flight", - "Flight", - 60, - IT_POWERUP, - PW_FLIGHT, - "", - "sound/items/flight.wav" - },*/ - -/*QUAKED team_droid_spawn (0 0 1) (-16 -16 -16) (16 16 16) -TA: droid spawn item -*/ - { - "team_droid_spawn", - "sound/items/holdable.wav", - { "models/bitems/aspawn.md3", 0, 0, 0 }, - "icons/teleporter", //icon - "Droid Spawn", //pickup - 0, - IT_BUILDABLE, - BA_A_SPAWN, - "", //precache - "" //sounds - }, - -/*QUAKED team_droid_def1 (0 0 1) (-16 -16 -16) (16 16 16) -TA: droid defense item -*/ - { - "team_droid_def1", - "sound/items/holdable.wav", - { "models/bitems/adef1.md3", 0, 0, 0 }, - "icons/teleporter", //icon - "Droid Defense", //pickup - 0, - IT_BUILDABLE, - BA_A_DEF1, - "", //precache - "" //sounds - }, - -/*QUAKED team_human_spawn (0 0 1) (-16 -16 -16) (16 16 16) -TA: human spawn item -*/ - { - "team_human_spawn", - "sound/items/holdable.wav", - { "models/bitems/hspawn.md3", 0, 0, 0 }, - "icons/teleporter", //icon - "Human Spawn", //pickup - 0, - IT_BUILDABLE, - BA_H_SPAWN, - "", //precache - "" //sounds - }, - -/*QUAKED team_human_def1 (0 0 1) (-16 -16 -16) (16 16 16) -TA: human defense item -*/ - { - "team_human_def1", - "sound/items/holdable.wav", - { "models/bitems/turret-base.md3", "models/bitems/turret-top.md3", 0, 0 }, - "icons/teleporter", //icon - "Human Defense", //pickup - 0, - IT_BUILDABLE, - BA_H_DEF1, - "", //precache - "" //sounds - }, - -/*QUAKED team_human_mcu (0 0 1) (-16 -16 -16) (16 16 16) -TA: human defense item -*/ - { - "team_human_mcu", - "sound/items/holdable.wav", - { "models/bitems/adef1.md3", 0, 0, 0 }, - "icons/teleporter", //icon - "Human MCU", //pickup - 0, - IT_BUILDABLE, - BA_H_MCU, - "", //precache - "" //sounds - }, - -/*QUAKED upgrade_torch (0 0 1) (-16 -16 -16) (16 16 16) -*/ - { - "upgrade_torch", - "sound/items/holdable.wav", - { 0, 0, 0, 0 }, - "icons/teleporter", //icon - "Torch", //pickup - 0, - IT_UPGRADE, - UP_TORCH, - "", //precache - "" //sounds - }, - -/*QUAKED upgrade_nvg (0 0 1) (-16 -16 -16) (16 16 16) -*/ - { - "upgrade_nvg", - "sound/items/holdable.wav", - { 0, 0, 0, 0 }, - "icons/teleporter", //icon - "NVG", //pickup - 0, - IT_UPGRADE, - UP_NVG, - "", //precache - "" //sounds - }, - -/*QUAKED team_CTF_redflag (1 0 0) (-16 -16 -16) (16 16 16) -Only in CTF games -*/ - /*{ - "team_CTF_redflag", - "sound/teamplay/flagtk_red.wav", - { "models/flags/r_flag.md3", - 0, 0, 0 }, - "icons/iconf_red1", - "Red Flag", - 0, - IT_TEAM, - PW_REDFLAG, - "", - "sound/teamplay/flagcap_red.wav sound/teamplay/flagtk_red.wav sound/teamplay/flagret_red.wav" - },*/ - -/*QUAKED team_CTF_blueflag (0 0 1) (-16 -16 -16) (16 16 16) -Only in CTF games -*/ - /*{ - "team_CTF_blueflag", - "sound/teamplay/flagtk_blu.wav", - { "models/flags/b_flag.md3", - 0, 0, 0 }, - "icons/iconf_blu1", - "Blue Flag", - 0, - IT_TEAM, - PW_BLUEFLAG, - "", - "sound/teamplay/flagcap_blu.wav sound/teamplay/flagtk_blu.wav sound/teamplay/flagret_blu.wav" - },*/ - - // end of list marker - {NULL} -}; - -int bg_numItems = sizeof(bg_itemlist) / sizeof(bg_itemlist[0]) - 1; - - -/* -============== -BG_FindItemForPowerup -============== -*/ -gitem_t *BG_FindItemForPowerup( powerup_t pw ) { - int i; - - for ( i = 0 ; i < bg_numItems ; i++ ) { - if ( (bg_itemlist[i].giType == IT_POWERUP /*|| - bg_itemlist[i].giType == IT_TEAM || - bg_itemlist[i].giType == IT_PERSISTANT_POWERUP*/) && - bg_itemlist[i].giTag == pw ) { - return &bg_itemlist[i]; - } - } - - return NULL; -} - - -/* -============== -BG_FindItemForHoldable -============== -*/ -gitem_t *BG_FindItemForHoldable( holdable_t pw ) { - int i; - - for ( i = 0 ; i < bg_numItems ; i++ ) { - if ( bg_itemlist[i].giType == IT_HOLDABLE && bg_itemlist[i].giTag == pw ) { - return &bg_itemlist[i]; - } - } - - Com_Error( ERR_DROP, "HoldableItem not found" ); - - return NULL; -} - - -/* -=============== -BG_FindItemForWeapon - -=============== -*/ -gitem_t *BG_FindItemForWeapon( weapon_t weapon ) { - gitem_t *it; - - for ( it = bg_itemlist + 1 ; it->classname ; it++) { - if ( it->giType == IT_WEAPON && it->giTag == weapon ) { - return it; - } - } - - Com_Error( ERR_DROP, "Couldn't find item for weapon %i", weapon); - return NULL; -} - - -/* -=============== -BG_FindItemForBuildable - -TA: new function for finding buildable items -=============== -*/ -gitem_t *BG_FindItemForBuildable( buildable_t buildable ) { - gitem_t *it; - - for ( it = bg_itemlist + 1 ; it->classname ; it++) { - if ( it->giType == IT_BUILDABLE && it->giTag == buildable ) { - return it; - } - } - - Com_Error( ERR_DROP, "Couldn't find item for buildable %i", buildable); - return NULL; -} - - -/* -=============== -BG_FindItemForUpgrade - -TA: new function for finding upgrade items -=============== -*/ -gitem_t *BG_FindItemForUpgrade( upgrade_t upgrade ) { - gitem_t *it; - - for ( it = bg_itemlist + 1 ; it->classname ; it++) { - if ( it->giType == IT_UPGRADE && it->giTag == upgrade ) { - return it; - } - } - - Com_Error( ERR_DROP, "Couldn't find item for upgrade %i", upgrade); - return NULL; -} - - -/* -=============== -BG_FindItem - -=============== -*/ -gitem_t *BG_FindItem( const char *pickupName ) { - gitem_t *it; - - for ( it = bg_itemlist + 1 ; it->classname ; it++ ) { - if ( !Q_stricmp( it->pickup_name, pickupName ) ) - return it; - } - - return NULL; -} - -/* -============ -BG_PlayerTouchesItem - -Items can be picked up without actually touching their physical bounds to make -grabbing them easier -============ -*/ -qboolean BG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTime ) { - vec3_t origin; - - BG_EvaluateTrajectory( &item->pos, atTime, origin ); - - // we are ignoring ducked differences here - if ( ps->origin[0] - origin[0] > 44 - || ps->origin[0] - origin[0] < -50 - || ps->origin[1] - origin[1] > 36 - || ps->origin[1] - origin[1] < -36 - || ps->origin[2] - origin[2] > 36 - || ps->origin[2] - origin[2] < -36 ) { - return qfalse; - } - - return qtrue; -} - -/* -================ -BG_CanItemBeGrabbed - -Returns false if the item should not be picked up. -This needs to be the same for client side prediction and server use. -================ -*/ -qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const playerState_t *ps ) { - gitem_t *item; - - if ( ent->modelindex < 1 || ent->modelindex >= bg_numItems ) { - Com_Error( ERR_DROP, "BG_CanItemBeGrabbed: index out of range" ); - } - - item = &bg_itemlist[ent->modelindex]; - - switch( item->giType ) { - case IT_WEAPON: - return qtrue; // weapons are always picked up - - case IT_AMMO: - if ( ps->ammo[ item->giTag ] >= 200 ) { - return qfalse; // can't hold any more - } - return qtrue; - - case IT_ARMOR: - if ( ps->stats[STAT_ARMOR] >= ps->stats[STAT_MAX_HEALTH] * 2 ) { - return qfalse; - } - return qtrue; - - case IT_HEALTH: - // small and mega healths will go over the max, otherwise - // don't pick up if already at max - if ( item->quantity == 5 || item->quantity == 100 ) { - if ( ps->stats[STAT_HEALTH] >= ps->stats[STAT_MAX_HEALTH] * 2 ) { - return qfalse; - } - return qtrue; - } - - if ( ps->stats[STAT_HEALTH] >= ps->stats[STAT_MAX_HEALTH] ) { - return qfalse; - } - return qtrue; - - case IT_POWERUP: - return qtrue; // powerups are always picked up - - case IT_TEAM: // team items, such as flags - // ent->modelindex2 is non-zero on items if they are dropped - // we need to know this because we can pick up our dropped flag (and return it) - // but we can't pick up our flag at base - if (ps->persistant[PERS_TEAM] == TEAM_HUMANS) { - //TA: remove powerups - /*if (item->giTag == PW_BLUEFLAG || - (item->giTag == PW_REDFLAG && ent->modelindex2) || - (item->giTag == PW_REDFLAG && ps->powerups[PW_BLUEFLAG])) - return qtrue;*/ - } else if (ps->persistant[PERS_TEAM] == TEAM_DROIDS) { - /*if (item->giTag == PW_REDFLAG || - (item->giTag == PW_BLUEFLAG && ent->modelindex2) || - (item->giTag == PW_BLUEFLAG && ps->powerups[PW_REDFLAG])) - return qtrue;*/ - } - return qfalse; - - //TA: not using the q3 holdable items code - /*case IT_HOLDABLE: - // can only hold one item at a time - if ( ps->stats[STAT_HOLDABLE_ITEM] ) { - return qfalse; - } - return qtrue;*/ - - case IT_BAD: - Com_Error( ERR_DROP, "BG_CanItemBeGrabbed: IT_BAD" ); - } - - return qfalse; -} - -//====================================================================== - -/* -================ -BG_EvaluateTrajectory - -================ -*/ -void BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result ) { - float deltaTime; - float phase; - - switch( tr->trType ) { - case TR_STATIONARY: - case TR_INTERPOLATE: - VectorCopy( tr->trBase, result ); - break; - case TR_LINEAR: - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds - VectorMA( tr->trBase, deltaTime, tr->trDelta, result ); - break; - case TR_SINE: - deltaTime = ( atTime - tr->trTime ) / (float) tr->trDuration; - phase = sin( deltaTime * M_PI * 2 ); - VectorMA( tr->trBase, phase, tr->trDelta, result ); - break; - case TR_LINEAR_STOP: - if ( atTime > tr->trTime + tr->trDuration ) { - atTime = tr->trTime + tr->trDuration; - } - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds - if ( deltaTime < 0 ) { - deltaTime = 0; - } - VectorMA( tr->trBase, deltaTime, tr->trDelta, result ); - break; - case TR_GRAVITY: - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds - VectorMA( tr->trBase, deltaTime, tr->trDelta, result ); - result[2] -= 0.5 * DEFAULT_GRAVITY * deltaTime * deltaTime; // FIXME: local gravity... - break; - default: - Com_Error( ERR_DROP, "BG_EvaluateTrajectory: unknown trType: %i", tr->trTime ); - break; - } -} - -/* -================ -BG_EvaluateTrajectoryDelta - -For determining velocity at a given time -================ -*/ -void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t result ) { - float deltaTime; - float phase; - - switch( tr->trType ) { - case TR_STATIONARY: - case TR_INTERPOLATE: - VectorClear( result ); - break; - case TR_LINEAR: - VectorCopy( tr->trDelta, result ); - break; - case TR_SINE: - deltaTime = ( atTime - tr->trTime ) / (float) tr->trDuration; - phase = cos( deltaTime * M_PI * 2 ); // derivative of sin = cos - phase *= 0.5; - VectorScale( tr->trDelta, phase, result ); - break; - case TR_LINEAR_STOP: - if ( atTime > tr->trTime + tr->trDuration ) { - VectorClear( result ); - return; - } - VectorCopy( tr->trDelta, result ); - break; - case TR_GRAVITY: - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds - VectorCopy( tr->trDelta, result ); - result[2] -= DEFAULT_GRAVITY * deltaTime; // FIXME: local gravity... - break; - default: - Com_Error( ERR_DROP, "BG_EvaluateTrajectoryDelta: unknown trType: %i", tr->trTime ); - break; - } -} - -char *eventnames[] = { - "EV_NONE", - - "EV_FOOTSTEP", - "EV_FOOTSTEP_METAL", - "EV_FOOTSPLASH", - "EV_FOOTWADE", - "EV_SWIM", - - "EV_STEP_4", - "EV_STEP_8", - "EV_STEP_12", - "EV_STEP_16", - - "EV_FALL_SHORT", - "EV_FALL_MEDIUM", - "EV_FALL_FAR", - - "EV_JUMP_PAD", // boing sound at origin", jump sound on player - - "EV_JUMP", - "EV_WATER_TOUCH", // foot touches - "EV_WATER_LEAVE", // foot leaves - "EV_WATER_UNDER", // head touches - "EV_WATER_CLEAR", // head leaves - - "EV_ITEM_PICKUP", // normal item pickups are predictable - "EV_GLOBAL_ITEM_PICKUP", // powerup / team sounds are broadcast to everyone - - "EV_NOAMMO", - "EV_CHANGE_WEAPON", - "EV_FIRE_WEAPON", - - "EV_USE_ITEM0", - "EV_USE_ITEM1", - "EV_USE_ITEM2", - "EV_USE_ITEM3", - "EV_USE_ITEM4", - "EV_USE_ITEM5", - "EV_USE_ITEM6", - "EV_USE_ITEM7", - "EV_USE_ITEM8", - "EV_USE_ITEM9", - "EV_USE_ITEM10", - "EV_USE_ITEM11", - "EV_USE_ITEM12", - "EV_USE_ITEM13", - "EV_USE_ITEM14", - "EV_USE_ITEM15", - - "EV_ITEM_RESPAWN", - "EV_ITEM_POP", - "EV_PLAYER_TELEPORT_IN", - "EV_PLAYER_TELEPORT_OUT", - - "EV_GRENADE_BOUNCE", // eventParm will be the soundindex - - "EV_GENERAL_SOUND", - "EV_GLOBAL_SOUND", // no attenuation - "EV_GLOBAL_TEAM_SOUND", - - "EV_BULLET_HIT_FLESH", - "EV_BULLET_HIT_WALL", - - "EV_MISSILE_HIT", - "EV_MISSILE_MISS", - "EV_MISSILE_MISS_METAL", - "EV_RAILTRAIL", - "EV_SHOTGUN", - "EV_BULLET", // otherEntity is the shooter - - "EV_PAIN", - "EV_DEATH1", - "EV_DEATH2", - "EV_DEATH3", - "EV_OBITUARY", - - "EV_POWERUP_QUAD", - "EV_POWERUP_BATTLESUIT", - "EV_POWERUP_REGEN", - - "EV_GIB_PLAYER", // gib a previously living player - "EV_SCOREPLUM", // score plum - -//#ifdef MISSIONPACK - "EV_PROXIMITY_MINE_STICK", - "EV_PROXIMITY_MINE_TRIGGER", - "EV_KAMIKAZE", // kamikaze explodes - "EV_OBELISKEXPLODE", // obelisk explodes - "EV_INVUL_IMPACT", // invulnerability sphere impact - "EV_JUICED", // invulnerability juiced effect - "EV_LIGHTNINGBOLT", // lightning bolt bounced of invulnerability sphere -//#endif - - "EV_DEBUG_LINE", - "EV_STOPLOOPINGSOUND", - "EV_TAUNT" - -}; - -/* -=============== -BG_AddPredictableEventToPlayerstate - -Handles the sequence numbers -=============== -*/ - -void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ); - -void BG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps ) { -#ifdef _DEBUG - { - char buf[256]; - trap_Cvar_VariableStringBuffer("showevents", buf, sizeof(buf)); - if ( atof(buf) != 0 ) { -#ifdef QAGAME - Com_Printf(" game event svt %5d -> %5d: num = %20s parm %d\n", ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence, eventnames[newEvent], eventParm); -#else - Com_Printf("Cgame event svt %5d -> %5d: num = %20s parm %d\n", ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence, eventnames[newEvent], eventParm); -#endif - } - } -#endif - ps->events[ps->eventSequence & (MAX_PS_EVENTS-1)] = newEvent; - ps->eventParms[ps->eventSequence & (MAX_PS_EVENTS-1)] = eventParm; - ps->eventSequence++; -} - - -/* -======================== -BG_TouchJumpPad -======================== -*/ -void BG_TouchJumpPad( playerState_t *ps, entityState_t *jumppad ) { - vec3_t angles; - float p; - int effectNum; - - // spectators don't use jump pads - if ( ps->pm_type != PM_NORMAL ) { - return; - } - - // flying characters don't hit bounce pads - if ( ps->powerups[PW_FLIGHT] ) { - return; - } - - // if we didn't hit this same jumppad the previous frame - // then don't play the event sound again if we are in a fat trigger - if ( ps->jumppad_ent != jumppad->number ) { - - vectoangles( jumppad->origin2, angles); - p = fabs( AngleNormalize180( angles[PITCH] ) ); - if( p < 45 ) { - effectNum = 0; - } else { - effectNum = 1; - } - BG_AddPredictableEventToPlayerstate( EV_JUMP_PAD, effectNum, ps ); - } - // remember hitting this jumppad this frame - ps->jumppad_ent = jumppad->number; - ps->jumppad_frame = ps->pmove_framecount; - // give the player the velocity from the jumppad - VectorCopy( jumppad->origin2, ps->velocity ); -} - - -/* -======================== -BG_PlayerStateToEntityState - -This is done after each set of usercmd_t on the server, -and after local prediction on the client -======================== -*/ -void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean snap ) { - int i; - vec3_t ceilingNormal = { 0, 0, -1 }; - - if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR ) { - s->eType = ET_INVISIBLE; - } else if ( ps->stats[STAT_HEALTH] <= GIB_HEALTH ) { - s->eType = ET_INVISIBLE; - } else { - s->eType = ET_PLAYER; - } - - s->number = ps->clientNum; - - s->pos.trType = TR_INTERPOLATE; - VectorCopy( ps->origin, s->pos.trBase ); - if ( snap ) { - SnapVector( s->pos.trBase ); - } - //set the trDelta for flag direction - VectorCopy( ps->velocity, s->pos.trDelta ); - - s->apos.trType = TR_INTERPOLATE; - VectorCopy( ps->viewangles, s->apos.trBase ); - if ( snap ) { - SnapVector( s->apos.trBase ); - } - - //TA: i need for other things :) - //s->angles2[YAW] = ps->movementDir; - s->time2 = ps->movementDir; - s->legsAnim = ps->legsAnim; - s->torsoAnim = ps->torsoAnim; - s->clientNum = ps->clientNum; // ET_PLAYER looks here instead of at number - // so corpses can also reference the proper config - s->eFlags = ps->eFlags; - if ( ps->stats[STAT_HEALTH] <= 0 ) { - s->eFlags |= EF_DEAD; - } else { - s->eFlags &= ~EF_DEAD; - } - - if ( ps->externalEvent ) { - s->event = ps->externalEvent; - s->eventParm = ps->externalEventParm; - } else { - int seq; - - if ( ps->entityEventSequence < ps->eventSequence - MAX_PS_EVENTS) { - ps->entityEventSequence = ps->eventSequence - MAX_PS_EVENTS; - } - seq = (ps->entityEventSequence-1) & (MAX_PS_EVENTS-1); - s->event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 ); - s->eventParm = ps->eventParms[ seq ]; - if ( ps->entityEventSequence < ps->eventSequence ) { - ps->entityEventSequence++; - } - } - - s->weapon = ps->weapon; - s->groundEntityNum = ps->groundEntityNum; - - /*s->powerups = 0; - for ( i = 0 ; i < MAX_POWERUPS ; i++ ) { - if ( ps->powerups[ i ] ) { - s->powerups |= 1 << i; - } - }*/ - - //TA: use powerups field to store team/class info: - s->powerups = ps->stats[ STAT_PTEAM ] | ( ps->stats[ STAT_PCLASS ] << 8 ); - - //TA: have to get the surfNormal thru somehow... - if( ps->stats[ STAT_STATE ] & SS_GPISROTVEC ) - { - VectorCopy( ceilingNormal, s->angles2 ); - } - else - { - VectorCopy( ps->grapplePoint, s->angles2 ); - } - - s->loopSound = ps->loopSound; - s->generic1 = ps->generic1; -} - - -/* -======================== -BG_PlayerStateToEntityStateExtraPolate - -This is done after each set of usercmd_t on the server, -and after local prediction on the client -======================== -*/ -void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s, int time, qboolean snap ) { - int i; - vec3_t ceilingNormal = { 0, 0, -1 }; - - if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR ) { - s->eType = ET_INVISIBLE; - } else if ( ps->stats[STAT_HEALTH] <= GIB_HEALTH ) { - s->eType = ET_INVISIBLE; - } else { - s->eType = ET_PLAYER; - } - - s->number = ps->clientNum; - - s->pos.trType = TR_LINEAR_STOP; - VectorCopy( ps->origin, s->pos.trBase ); - if ( snap ) { - SnapVector( s->pos.trBase ); - } - // set the trDelta for flag direction and linear prediction - VectorCopy( ps->velocity, s->pos.trDelta ); - // set the time for linear prediction - s->pos.trTime = time; - // set maximum extra polation time - s->pos.trDuration = 50; // 1000 / sv_fps (default = 20) - - s->apos.trType = TR_INTERPOLATE; - VectorCopy( ps->viewangles, s->apos.trBase ); - if ( snap ) { - SnapVector( s->apos.trBase ); - } - - //TA: i need for other things :) - //s->angles2[YAW] = ps->movementDir; - s->time2 = ps->movementDir; - s->legsAnim = ps->legsAnim; - s->torsoAnim = ps->torsoAnim; - s->clientNum = ps->clientNum; // ET_PLAYER looks here instead of at number - // so corpses can also reference the proper config - s->eFlags = ps->eFlags; - if ( ps->stats[STAT_HEALTH] <= 0 ) { - s->eFlags |= EF_DEAD; - } else { - s->eFlags &= ~EF_DEAD; - } - - if ( ps->externalEvent ) { - s->event = ps->externalEvent; - s->eventParm = ps->externalEventParm; - } else { - int seq; - - if ( ps->entityEventSequence < ps->eventSequence - MAX_PS_EVENTS) { - ps->entityEventSequence = ps->eventSequence - MAX_PS_EVENTS; - } - seq = (ps->entityEventSequence-1) & (MAX_PS_EVENTS-1); - s->event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 ); - s->eventParm = ps->eventParms[ seq ]; - if ( ps->entityEventSequence < ps->eventSequence ) { - ps->entityEventSequence++; - } - } - - s->weapon = ps->weapon; - s->groundEntityNum = ps->groundEntityNum; - - /*s->powerups = 0; - for ( i = 0 ; i < MAX_POWERUPS ; i++ ) { - if ( ps->powerups[ i ] ) { - s->powerups |= 1 << i; - } - }*/ - - //TA: use powerups field to store team/class info: - s->powerups = ps->stats[ STAT_PTEAM ] | ( ps->stats[ STAT_PCLASS ] << 8 ); - - //TA: have to get the surfNormal thru somehow... - if( ps->stats[ STAT_STATE ] & SS_GPISROTVEC ) - { - VectorCopy( ceilingNormal, s->angles2 ); - } - else - { - VectorCopy( ps->grapplePoint, s->angles2 ); - } - - s->loopSound = ps->loopSound; - s->generic1 = ps->generic1; -} - - -//TA: extract the ammo quantity from the array -void BG_unpackAmmoArray( int weapon, int ammo[ ], int ammo2[ ], int *quan, int *clips, int *maxclips ) -{ - int ammoarray[32]; - int i; - - for( i = 0; i <= 15; i++ ) - ammoarray[ i ] = ammo[ i ]; - - for( i = 16; i <= 31; i++ ) - ammoarray[ i ] = ammo2[ i - 16 ]; - - if( quan != NULL ) - *quan = ammoarray[ weapon ] & 0x03FF; - - if( clips != NULL ) - *clips = ( ammoarray[ weapon ] >> 10 ) & 0x07; - - if( maxclips != NULL ) - *maxclips = ( ammoarray[ weapon ] >> 13 ) & 0x07; -} - -//TA: pack the ammo quantity into the array -void BG_packAmmoArray( int weapon, int ammo[ ], int ammo2[ ], int quan, int clips, int maxclips ) -{ - int weaponvalue; - - weaponvalue = quan | ( clips << 10 ) | ( maxclips << 13 ); - - if( weapon <= 15 ) - ammo[ weapon ] = weaponvalue; - else if( weapon >= 16 ) - ammo2[ weapon - 16 ] = weaponvalue; -} - -//TA: check whether infinite ammo -qboolean BG_infiniteAmmo( int weapon ) -{ - switch( weapon ) - { - case WP_VENOM: - case WP_ABUILD: - case WP_HBUILD: - case WP_SCANNER: - return qtrue; - break; - - //nothing else has infinite ammo - default: - return qfalse; - break; - } -} - -//TA: pack weapons into the array -void BG_packWeapon( int weapon, int stats[ ] ) -{ - int weaponList, i; - - weaponList = ( stats[ STAT_WEAPONS ] & 0x0000FFFF ) | ( ( stats[ STAT_WEAPONS2 ] << 16 ) & 0xFFFF0000 ); - - weaponList |= ( 1 << weapon ); - - stats[ STAT_WEAPONS ] = weaponList & 0x0000FFFF; - stats[ STAT_WEAPONS2 ] = ( weaponList & 0xFFFF0000 ) >> 16; - -} - -//TA: check whether array contains weapon -qboolean BG_gotWeapon( int weapon, int stats[ ] ) -{ - int weaponList, i; - - weaponList = ( stats[ STAT_WEAPONS ] & 0x0000FFFF ) | ( ( stats[ STAT_WEAPONS2 ] << 16 ) & 0xFFFF0000 ); - - return( weaponList & ( 1 << weapon ) ); -} - -//TA: pack items into array -void BG_packItem( int item, int stats[ ] ) -{ - stats[ STAT_ITEMS ] |= ( 1 << item ); -} - -//TA: remove items from array -void BG_removeItem( int item, int stats[ ] ) -{ - stats[ STAT_ITEMS ] &= ~( 1 << item ); -} - -//TA: check if item is in array -qboolean BG_gotItem( int item, int stats[ ] ) -{ - return( stats[ STAT_ITEMS ] & ( 1 << item ) ); -} - -//TA: set item active in array -void BG_activateItem( int item, int stats[ ] ) -{ - stats[ STAT_ACTIVEITEMS ] |= ( 1 << item ); -} - -//TA: set item deactive in array -void BG_deactivateItem( int item, int stats[ ] ) -{ - stats[ STAT_ACTIVEITEMS ] &= ~( 1 << item ); -} - -//TA: check if item active in array -qboolean BG_activated( int item, int stats[ ] ) -{ - return( stats[ STAT_ACTIVEITEMS ] & ( 1 << item ) ); -} - -//TA: set attributes in array -void BG_packAttributes( int fov, int bob, int steptime, int stats[ ] ) -{ - stats[ STAT_ATTRIBS ] = ( ( (int)( (float)fov/10.0 ) & 0x1F ) << 10 ) | ( ( bob & 0x1F ) << 5 ) | ( (int)( (float)steptime/25.0 ) & 0x1F ); -} - -//TA: get attributes from array -void BG_unpackAttributes( int *fov, int *bob, int *steptime, int stats[ ] ) -{ - if( fov != NULL ) - *fov = ( ( stats[ STAT_ATTRIBS ] >> 10 ) & 0x1F ) * 10; - - if( bob != NULL ) - *bob = ( stats[ STAT_ATTRIBS ] >> 5 ) & 0x1F; - - if( steptime != NULL ) - *steptime = ( stats[ STAT_ATTRIBS ] & 0x1F ) * 25; -} diff --git a/src/game/bg_pmove.c b/src/game/bg_pmove.c deleted file mode 100644 index e7be5798..00000000 --- a/src/game/bg_pmove.c +++ /dev/null @@ -1,2818 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// bg_pmove.c -- both games player movement code -// takes a playerstate and a usercmd as input and returns a modifed playerstate - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "q_shared.h" -#include "bg_public.h" -#include "bg_local.h" - -pmove_t *pm; -pml_t pml; - -//TA: wall climbing struct for EVERY client. Not c/s communicated so -// size isn't that important -wcl_t wcl[ MAX_CLIENTS ]; - -// movement parameters -float pm_stopspeed = 100.0f; -float pm_duckScale = 0.25f; -float pm_swimScale = 0.50f; -float pm_wadeScale = 0.70f; - -float pm_accelerate = 10.0f; -float pm_airaccelerate = 1.0f; -float pm_wateraccelerate = 4.0f; -float pm_flyaccelerate = 8.0f; - -float pm_friction = 6.0f; -float pm_waterfriction = 1.0f; -float pm_flightfriction = 3.0f; -float pm_spectatorfriction = 5.0f; - -int c_pmove = 0; - -/* -================ -PM_AddSmoothOp - -Add a smoothing operation to the smoothing queue -================ -*/ -static void PM_AddSmoothOp( vec3_t rotAxis, float rotAngle ) -{ - int i; - - //hack to prevent multiple identical rotations being added to the queue - //this happens often because groundtrace is called twice a frame - for( i = 0; i < MAXSMOOTHS; i++ ) - { - if( wcl[ pm->ps->clientNum ].sList[ i ].time >= pm->cmd.serverTime-100 ) - return; - - /*if( VectorCompare( sList[ i ].rotAxis, rotAxis ) ) - return;*/ - - } - - //iterate through smoothing array - for( i = 0; i < MAXSMOOTHS; i++ ) - { - //if a smooth has been performed it can be overwritten - if( wcl[ pm->ps->clientNum ].sList[ i ].time + SMOOTHTIME < pm->cmd.serverTime ) - { - //copy the new smooth into the array and stop - VectorCopy( rotAxis, wcl[ pm->ps->clientNum ].sList[ i ].rotAxis ); - wcl[ pm->ps->clientNum ].sList[ i ].rotAngle = rotAngle; - wcl[ pm->ps->clientNum ].sList[ i ].time = pm->cmd.serverTime; - return; - } - } - - //there are no free smooth slots -} - - -/* -================ -PM_PerformSmoothOps - -Perform all the smoothing operations in the smoothing queue -================ -*/ -static qboolean PM_PerformSmoothOps( vec3_t in[3], vec3_t out[3] ) -{ - int i; - float stLocal, sFraction; - vec3_t localIn[3], localOut[3]; - qboolean performed = qfalse; - - AxisCopy( in, localIn ); - - //iterate through smoothing array - for( i = 0; i < MAXSMOOTHS; i++ ) - { - //perform smooth - if( ( pm->cmd.serverTime < wcl[ pm->ps->clientNum ].sList[ i ].time + SMOOTHTIME ) && - ( VectorLength( wcl[ pm->ps->clientNum ].sList[ i ].rotAxis ) != 0 ) ) - { - //the rotAxis /should/ never be of zero length but q3 *will* crash if it is... - //better to be safe than sorry :) - - stLocal = 1.0 - ( ( ( wcl[ pm->ps->clientNum ].sList[ i ].time + SMOOTHTIME ) - pm->cmd.serverTime ) / SMOOTHTIME ); - - //some ppl might prefer this smoothing function: - //sFraction = -( 1.0 - sin( stLocal * M_PI / 2 ) ); - sFraction = -( cos( stLocal * M_PI ) + 1 ) / 2; - - RotatePointAroundVector( localOut[0], wcl[ pm->ps->clientNum ].sList[ i ].rotAxis, localIn[0], sFraction * wcl[ pm->ps->clientNum ].sList[ i ].rotAngle ); - RotatePointAroundVector( localOut[1], wcl[ pm->ps->clientNum ].sList[ i ].rotAxis, localIn[1], sFraction * wcl[ pm->ps->clientNum ].sList[ i ].rotAngle ); - RotatePointAroundVector( localOut[2], wcl[ pm->ps->clientNum ].sList[ i ].rotAxis, localIn[2], sFraction * wcl[ pm->ps->clientNum ].sList[ i ].rotAngle ); - - AxisCopy( localOut, localIn ); - performed = qtrue; - } - } - - AxisCopy( localOut, out ); - - return performed; -} - - -/* -=============== -PM_AddEvent - -=============== -*/ -void PM_AddEvent( int newEvent ) { - BG_AddPredictableEventToPlayerstate( newEvent, 0, pm->ps ); -} - -/* -=============== -PM_AddTouchEnt -=============== -*/ -void PM_AddTouchEnt( int entityNum ) { - int i; - - if ( entityNum == ENTITYNUM_WORLD ) { - return; - } - if ( pm->numtouch == MAXTOUCH ) { - return; - } - - // see if it is already added - for ( i = 0 ; i < pm->numtouch ; i++ ) { - if ( pm->touchents[ i ] == entityNum ) { - return; - } - } - - // add it - pm->touchents[pm->numtouch] = entityNum; - pm->numtouch++; -} - -/* -=================== -PM_StartTorsoAnim -=================== -*/ -static void PM_StartTorsoAnim( int anim ) { - if ( pm->ps->pm_type >= PM_DEAD ) { - return; - } - pm->ps->torsoAnim = ( ( pm->ps->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) - | anim; -} -static void PM_StartLegsAnim( int anim ) { - if ( pm->ps->pm_type >= PM_DEAD ) { - return; - } - if ( pm->ps->legsTimer > 0 ) { - return; // a high priority animation is running - } - pm->ps->legsAnim = ( ( pm->ps->legsAnim & ( ANIM_TOGGLEBIT | ANIM_WALLCLIMBING ) ) ^ ANIM_TOGGLEBIT ) - | anim; -} - -static void PM_ContinueLegsAnim( int anim ) { - if ( ( pm->ps->legsAnim & ~( ANIM_TOGGLEBIT | ANIM_WALLCLIMBING ) ) == anim ) { - return; - } - if ( pm->ps->legsTimer > 0 ) { - return; // a high priority animation is running - } - PM_StartLegsAnim( anim ); -} - -static void PM_ContinueTorsoAnim( int anim ) { - if ( ( pm->ps->torsoAnim & ~( ANIM_TOGGLEBIT | ANIM_WALLCLIMBING ) ) == anim ) { - return; - } - if ( pm->ps->torsoTimer > 0 ) { - return; // a high priority animation is running - } - PM_StartTorsoAnim( anim ); -} - -static void PM_ForceLegsAnim( int anim ) { - pm->ps->legsTimer = 0; - PM_StartLegsAnim( anim ); -} - - -/* -================== -PM_ClipVelocity - -Slide off of the impacting surface -================== -*/ -void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce ) { - float backoff; - float change; - int i; - - backoff = DotProduct (in, normal); - - if ( backoff < 0 ) { - backoff *= overbounce; - } else { - backoff /= overbounce; - } - - for ( i=0 ; i<3 ; i++ ) { - change = normal[i]*backoff; - out[i] = in[i] - change; - } -} - - -/* -================== -PM_Friction - -Handles both ground friction and water friction -================== -*/ -static void PM_Friction( void ) { - vec3_t vec; - float *vel; - float speed, newspeed, control; - float drop; - - vel = pm->ps->velocity; - - //TA: make sure vertical velocity is NOT set to zero when wall climbing - VectorCopy( vel, vec ); - if ( pml.walking && - pm->ps->stats[ STAT_STATE ] & ~SS_WALLCLIMBING ) { - vec[2] = 0; // ignore slope movement - } - - speed = VectorLength(vec); - if (speed < 1) { - vel[0] = 0; - vel[1] = 0; // allow sinking underwater - // FIXME: still have z friction underwater? - return; - } - - drop = 0; - - // apply ground friction - if ( pm->waterlevel <= 1 ) { - if ( pml.walking && !(pml.groundTrace.surfaceFlags & SURF_SLICK) ) { - // if getting knocked back, no friction - if ( ! (pm->ps->pm_flags & PMF_TIME_KNOCKBACK) ) { - control = speed < pm_stopspeed ? pm_stopspeed : speed; - drop += control*pm_friction*pml.frametime; - } - } - } - - // apply water friction even if just wading - if ( pm->waterlevel ) { - drop += speed*pm_waterfriction*pm->waterlevel*pml.frametime; - } - - // apply flying friction - if ( pm->ps->pm_type == PM_SPECTATOR ) { - drop += speed*pm_spectatorfriction*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 -============== -*/ -static void PM_Accelerate( vec3_t wishdir, float wishspeed, float accel ) { -#if 1 - // q2 style - int i; - float addspeed, accelspeed, currentspeed; - - currentspeed = DotProduct (pm->ps->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++) { - pm->ps->velocity[i] += accelspeed*wishdir[i]; - } -#else - // proper way (avoids strafe jump maxspeed bug), but feels bad - vec3_t wishVelocity; - vec3_t pushDir; - float pushLen; - float canPush; - - VectorScale( wishdir, wishspeed, wishVelocity ); - VectorSubtract( wishVelocity, pm->ps->velocity, pushDir ); - pushLen = VectorNormalize( pushDir ); - - canPush = accel*pml.frametime*wishspeed; - if (canPush > pushLen) { - canPush = pushLen; - } - - VectorMA( pm->ps->velocity, canPush, pushDir, pm->ps->velocity ); -#endif -} - - - -/* -============ -PM_CmdScale - -Returns the scale factor to apply to cmd movements -This allows the clients to use axial -127 to 127 values for all directions -without getting a sqrt(2) distortion in speed. -============ -*/ -static float PM_CmdScale( usercmd_t *cmd ) { - int max; - float total; - float scale; - float modifier = 1.0; - static int time; - int dTime; - int aForward, aRight; - - dTime = pm->cmd.serverTime - time; - time = pm->cmd.serverTime; - - if( pm->ps->stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - if( !( pm->ps->stats[ STAT_STATE ] & SS_SPEEDBOOST ) ) - { - //if not sprinting - modifier *= 0.8; - } - else - { - //subtract stamina - pm->ps->stats[ STAT_STAMINA ] -= (dTime/4); - } - - aForward = abs( cmd->forwardmove ); - aRight = abs( cmd->rightmove ); - - if( ( aForward <= 64 && aForward > 5 ) && ( aRight <= 64 && aRight > 5 ) ) - { - //restore stamina - pm->ps->stats[ STAT_STAMINA ] += (dTime/5); - } - else if( aForward <= 5 && aRight <= 5 ) - { - //restore stamina faster - pm->ps->stats[ STAT_STAMINA ] += (dTime/4); - } - - if( cmd->forwardmove < 0 ) - { - //can't run backwards - modifier *= 0.5; - } - else if( cmd->rightmove ) - { - //can't move that fast sideways - modifier *= 0.75; - } - - //cap stamina - if( pm->ps->stats[ STAT_STAMINA ] > 1000 ) - pm->ps->stats[ STAT_STAMINA ] = 1000; - if( pm->ps->stats[ STAT_STAMINA ] < -1000 ) - pm->ps->stats[ STAT_STAMINA ] = -1000; - - //if not trying to run then not trying to sprint - if( abs( cmd->forwardmove ) <= 64 ) - pm->ps->stats[ STAT_STATE ] &= ~SS_SPEEDBOOST; - - //must have +ve stamina to jump - if( pm->ps->stats[ STAT_STAMINA ] < 0 ) - cmd->upmove = 0; - - //slow down once stamina depletes - if( pm->ps->stats[ STAT_STAMINA ] <= -500 ) - modifier *= (float)( pm->ps->stats[ STAT_STAMINA ] + 1000 ) / 500.0f; - } - - if( !( pm->ps->stats[ STAT_ABILITIES ] & SCA_CANJUMP ) ) - cmd->upmove = 0; - - max = abs( cmd->forwardmove ); - if ( abs( cmd->rightmove ) > max ) { - max = abs( cmd->rightmove ); - } - if ( abs( cmd->upmove ) > max ) { - max = abs( cmd->upmove ); - } - if ( !max ) { - return 0; - } - - if( ( pm->ps->stats[ STAT_ABILITIES ] & SCA_WALLCLIMBER ) && - ( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) ) - { - total = sqrt( cmd->forwardmove * cmd->forwardmove + cmd->rightmove * cmd->rightmove ); - } - else - { - total = sqrt( cmd->forwardmove * cmd->forwardmove - + cmd->rightmove * cmd->rightmove + cmd->upmove * cmd->upmove ); - } - scale = (float)pm->ps->speed * max / ( 127.0 * total ) * modifier; - - return scale; -} - - -/* -================ -PM_SetMovementDir - -Determine the rotation of the legs reletive -to the facing dir -================ -*/ -static void PM_SetMovementDir( void ) { - if ( pm->cmd.forwardmove || pm->cmd.rightmove ) { - if ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove > 0 ) { - pm->ps->movementDir = 0; - } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove > 0 ) { - pm->ps->movementDir = 1; - } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove == 0 ) { - pm->ps->movementDir = 2; - } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove < 0 ) { - pm->ps->movementDir = 3; - } else if ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove < 0 ) { - pm->ps->movementDir = 4; - } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove < 0 ) { - pm->ps->movementDir = 5; - } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove == 0 ) { - pm->ps->movementDir = 6; - } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove > 0 ) { - pm->ps->movementDir = 7; - } - } else { - // if they aren't actively going directly sideways, - // change the animation to the diagonal so they - // don't stop too crooked - if ( pm->ps->movementDir == 2 ) { - pm->ps->movementDir = 1; - } else if ( pm->ps->movementDir == 6 ) { - pm->ps->movementDir = 7; - } - } -} - - -/* -============= -PM_CheckJump -============= -*/ -static qboolean PM_CheckJump( void ) { - if( !( pm->ps->stats[ STAT_ABILITIES ] & SCA_CANJUMP ) ) return qfalse; - - if( ( pm->ps->stats[ STAT_PTEAM ] == PTE_HUMANS ) && - ( pm->ps->stats[ STAT_STAMINA ] < 0 ) ) - return qfalse; - - if ( pm->ps->pm_flags & PMF_RESPAWNED ) { - return qfalse; // don't allow jump until all buttons are up - } - - if ( pm->cmd.upmove < 10 ) { - // not holding jump - return qfalse; - } - - // must wait for jump to be released - if ( pm->ps->pm_flags & PMF_JUMP_HELD ) { - // clear upmove so cmdscale doesn't lower running speed - pm->cmd.upmove = 0; - return qfalse; - } - - pml.groundPlane = qfalse; // jumping away - pml.walking = qfalse; - pm->ps->pm_flags |= PMF_JUMP_HELD; - - //TA: take some stamina off - if( pm->ps->stats[ STAT_PTEAM ] == PTE_HUMANS ) - pm->ps->stats[ STAT_STAMINA ] -= 500; - - pm->ps->groundEntityNum = ENTITYNUM_NONE; - pm->ps->velocity[2] = JUMP_VELOCITY; - PM_AddEvent( EV_JUMP ); - - if ( pm->cmd.forwardmove >= 0 ) { - PM_ForceLegsAnim( LEGS_JUMP ); - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; - } else { - PM_ForceLegsAnim( LEGS_JUMPB ); - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; - } - - return qtrue; -} - -/* -============= -PM_CheckWaterJump -============= -*/ -static qboolean PM_CheckWaterJump( void ) { - vec3_t spot; - int cont; - vec3_t flatforward; - - if (pm->ps->pm_time) { - return qfalse; - } - - // check for water jump - if ( pm->waterlevel != 2 ) { - return qfalse; - } - - flatforward[0] = pml.forward[0]; - flatforward[1] = pml.forward[1]; - flatforward[2] = 0; - VectorNormalize (flatforward); - - VectorMA (pm->ps->origin, 30, flatforward, spot); - spot[2] += 4; - cont = pm->pointcontents (spot, pm->ps->clientNum ); - if ( !(cont & CONTENTS_SOLID) ) { - return qfalse; - } - - spot[2] += 16; - cont = pm->pointcontents (spot, pm->ps->clientNum ); - if ( cont ) { - return qfalse; - } - - // jump out of water - VectorScale (pml.forward, 200, pm->ps->velocity); - pm->ps->velocity[2] = 350; - - pm->ps->pm_flags |= PMF_TIME_WATERJUMP; - pm->ps->pm_time = 2000; - - return qtrue; -} - -//============================================================================ - - -/* -=================== -PM_WaterJumpMove - -Flying out of the water -=================== -*/ -static void PM_WaterJumpMove( void ) { - // waterjump has no control, but falls - - PM_StepSlideMove( qtrue ); - - pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime; - if (pm->ps->velocity[2] < 0) { - // cancel as soon as we are falling down again - pm->ps->pm_flags &= ~PMF_ALL_TIMES; - pm->ps->pm_time = 0; - } -} - -/* -=================== -PM_WaterMove - -=================== -*/ -static void PM_WaterMove( void ) { - int i; - vec3_t wishvel; - float wishspeed; - vec3_t wishdir; - float scale; - float vel; - - if ( PM_CheckWaterJump() ) { - PM_WaterJumpMove(); - return; - } -#if 0 - // jump = head for surface - if ( pm->cmd.upmove >= 10 ) { - if (pm->ps->velocity[2] > -300) { - if ( pm->watertype == CONTENTS_WATER ) { - pm->ps->velocity[2] = 100; - } else if (pm->watertype == CONTENTS_SLIME) { - pm->ps->velocity[2] = 80; - } else { - pm->ps->velocity[2] = 50; - } - } - } -#endif - PM_Friction (); - - scale = PM_CmdScale( &pm->cmd ); - // - // user intentions - // - if ( !scale ) { - wishvel[0] = 0; - wishvel[1] = 0; - wishvel[2] = -60; // sink towards bottom - } else { - for (i=0 ; i<3 ; i++) - wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove; - - wishvel[2] += scale * pm->cmd.upmove; - } - - VectorCopy (wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - - if ( wishspeed > pm->ps->speed * pm_swimScale ) { - wishspeed = pm->ps->speed * pm_swimScale; - } - - PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate); - - // make sure we can go up slopes easily under water - if ( pml.groundPlane && DotProduct( pm->ps->velocity, pml.groundTrace.plane.normal ) < 0 ) { - vel = VectorLength(pm->ps->velocity); - // slide along the ground plane - PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, - pm->ps->velocity, OVERCLIP ); - - VectorNormalize(pm->ps->velocity); - VectorScale(pm->ps->velocity, vel, pm->ps->velocity); - } - - PM_SlideMove( qfalse ); -} - - - -/* -=================== -PM_FlyMove - -Only with the flight powerup -=================== -*/ -static void PM_FlyMove( void ) { - int i; - vec3_t wishvel; - float wishspeed; - vec3_t wishdir; - float scale; - - // normal slowdown - PM_Friction (); - - scale = PM_CmdScale( &pm->cmd ); - // - // user intentions - // - if ( !scale ) { - wishvel[0] = 0; - wishvel[1] = 0; - wishvel[2] = 0; - } else { - for (i=0 ; i<3 ; i++) { - wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove; - } - - wishvel[2] += scale * pm->cmd.upmove; - } - - VectorCopy (wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - - PM_Accelerate (wishdir, wishspeed, pm_flyaccelerate); - - PM_StepSlideMove( qfalse ); -} - - -/* -=================== -PM_AirMove - -=================== -*/ -static void PM_AirMove( void ) { - int i; - vec3_t wishvel; - float fmove, smove; - vec3_t wishdir; - float wishspeed; - float scale; - usercmd_t cmd; - - PM_Friction(); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - cmd = pm->cmd; - scale = PM_CmdScale( &cmd ); - - // set the movementDir so clients can rotate the legs for strafing - PM_SetMovementDir(); - - // project moves down to flat plane - 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; - - VectorCopy (wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - wishspeed *= scale; - - // not on ground, so little effect on velocity - PM_Accelerate (wishdir, wishspeed, pm_airaccelerate); - - // we may have a ground plane that is very steep, even - // though we don't have a groundentity - // slide along the steep plane - if ( pml.groundPlane ) { - PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, - pm->ps->velocity, OVERCLIP ); - } - -#if 0 - //ZOID: If we are on the grapple, try stair-stepping - //this allows a player to use the grapple to pull himself - //over a ledge - if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) - PM_StepSlideMove ( qtrue ); - else - PM_SlideMove ( qtrue ); -#endif - - PM_StepSlideMove ( qtrue ); -} - -/* -=================== -PM_GrappleMove - -=================== -*/ -static void PM_GrappleMove( void ) { - vec3_t vel, v; - float vlen; - - VectorScale(pml.forward, -16, v); - VectorAdd(pm->ps->grapplePoint, v, v); - VectorSubtract(v, pm->ps->origin, vel); - vlen = VectorLength(vel); - VectorNormalize( vel ); - - if (vlen <= 100) - VectorScale(vel, 10 * vlen, vel); - else - VectorScale(vel, 800, vel); - - VectorCopy(vel, pm->ps->velocity); - - pml.groundPlane = qfalse; -} - - -/* -=================== -PM_ClimbMove - -=================== -*/ -static void PM_ClimbMove( void ) { - int i; - vec3_t wishvel; - float fmove, smove; - vec3_t wishdir; - float wishspeed; - float scale; - usercmd_t cmd; - float accelerate; - float vel; - - if ( pm->waterlevel > 2 && DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) { - // begin swimming - PM_WaterMove(); - return; - } - - - if ( PM_CheckJump () ) { - // jumped away - if ( pm->waterlevel > 1 ) { - PM_WaterMove(); - } else { - PM_AirMove(); - } - return; - } - - PM_Friction (); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - cmd = pm->cmd; - scale = PM_CmdScale( &cmd ); - - // set the movementDir so clients can rotate the legs for strafing - PM_SetMovementDir(); - - // project the forward and right directions onto the ground plane - PM_ClipVelocity (pml.forward, pml.groundTrace.plane.normal, pml.forward, OVERCLIP ); - PM_ClipVelocity (pml.right, pml.groundTrace.plane.normal, pml.right, OVERCLIP ); - // - VectorNormalize (pml.forward); - VectorNormalize (pml.right); - - for ( i = 0 ; i < 3 ; i++ ) { - wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove; - } - // when going up or down slopes the wish velocity should Not be zero -// wishvel[2] = 0; - - VectorCopy (wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - wishspeed *= scale; - - // clamp the speed lower if ducking - if ( pm->ps->pm_flags & PMF_DUCKED ) { - if ( wishspeed > pm->ps->speed * pm_duckScale ) { - wishspeed = pm->ps->speed * pm_duckScale; - } - } - - // clamp the speed lower if wading or walking on the bottom - if ( pm->waterlevel ) { - float waterScale; - - waterScale = pm->waterlevel / 3.0; - waterScale = 1.0 - ( 1.0 - pm_swimScale ) * waterScale; - if ( wishspeed > pm->ps->speed * waterScale ) { - wishspeed = pm->ps->speed * waterScale; - } - } - - // when a player gets hit, they temporarily lose - // full control, which allows them to be moved a bit - if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) { - accelerate = pm_airaccelerate; - } else { - accelerate = pm_accelerate; - } - - PM_Accelerate (wishdir, wishspeed, accelerate); - - //Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]); - //Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity)); - - if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) { - pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime; - } else { - // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; - } - - vel = VectorLength(pm->ps->velocity); - - // slide along the ground plane - PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, - pm->ps->velocity, OVERCLIP ); - - // don't decrease velocity when going up or down a slope - VectorNormalize(pm->ps->velocity); - VectorScale(pm->ps->velocity, vel, pm->ps->velocity); - - // don't do anything if standing still - if (!pm->ps->velocity[0] && !pm->ps->velocity[1] && !pm->ps->velocity[2]) { - return; - } - - PM_StepSlideMove( qfalse ); - - //Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity)); - -} - - -/* -=================== -PM_WalkMove - -=================== -*/ -static void PM_WalkMove( void ) { - int i; - vec3_t wishvel; - float fmove, smove; - vec3_t wishdir; - float wishspeed; - float scale; - usercmd_t cmd; - float accelerate; - float vel; - - if ( pm->waterlevel > 2 && DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) { - // begin swimming - PM_WaterMove(); - return; - } - - - if ( PM_CheckJump () ) { - // jumped away - if ( pm->waterlevel > 1 ) { - PM_WaterMove(); - } else { - PM_AirMove(); - } - return; - } - - PM_Friction (); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - cmd = pm->cmd; - scale = PM_CmdScale( &cmd ); - - // set the movementDir so clients can rotate the legs for strafing - PM_SetMovementDir(); - - // project moves down to flat plane - pml.forward[2] = 0; - pml.right[2] = 0; - - // project the forward and right directions onto the ground plane - PM_ClipVelocity (pml.forward, pml.groundTrace.plane.normal, pml.forward, OVERCLIP ); - PM_ClipVelocity (pml.right, pml.groundTrace.plane.normal, pml.right, OVERCLIP ); - // - VectorNormalize (pml.forward); - VectorNormalize (pml.right); - - for ( i = 0 ; i < 3 ; i++ ) { - wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove; - } - // when going up or down slopes the wish velocity should Not be zero -// wishvel[2] = 0; - - VectorCopy (wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - wishspeed *= scale; - - // clamp the speed lower if ducking - if ( pm->ps->pm_flags & PMF_DUCKED ) { - if ( wishspeed > pm->ps->speed * pm_duckScale ) { - wishspeed = pm->ps->speed * pm_duckScale; - } - } - - // clamp the speed lower if wading or walking on the bottom - if ( pm->waterlevel ) { - float waterScale; - - waterScale = pm->waterlevel / 3.0; - waterScale = 1.0 - ( 1.0 - pm_swimScale ) * waterScale; - if ( wishspeed > pm->ps->speed * waterScale ) { - wishspeed = pm->ps->speed * waterScale; - } - } - - // when a player gets hit, they temporarily lose - // full control, which allows them to be moved a bit - if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) { - accelerate = pm_airaccelerate; - } else { - accelerate = pm_accelerate; - } - - PM_Accelerate (wishdir, wishspeed, accelerate); - - //Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]); - //Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity)); - - if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) { - pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime; - } else { - // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; - } - - vel = VectorLength(pm->ps->velocity); - - // slide along the ground plane - PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, - pm->ps->velocity, OVERCLIP ); - - // don't decrease velocity when going up or down a slope - VectorNormalize(pm->ps->velocity); - VectorScale(pm->ps->velocity, vel, pm->ps->velocity); - - // don't do anything if standing still - if (!pm->ps->velocity[0] && !pm->ps->velocity[1]) { - return; - } - - PM_StepSlideMove( qfalse ); - - //Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity)); - -} - - -/* -============== -PM_DeadMove -============== -*/ -static void PM_DeadMove( void ) { - float forward; - - if ( !pml.walking ) { - return; - } - - // extra friction - - forward = VectorLength (pm->ps->velocity); - forward -= 20; - if ( forward <= 0 ) { - VectorClear (pm->ps->velocity); - } else { - VectorNormalize (pm->ps->velocity); - VectorScale (pm->ps->velocity, forward, pm->ps->velocity); - } -} - - -/* -=============== -PM_NoclipMove -=============== -*/ -static void PM_NoclipMove( void ) { - float speed, drop, friction, control, newspeed; - int i; - vec3_t wishvel; - float fmove, smove; - vec3_t wishdir; - float wishspeed; - float scale; - - pm->ps->viewheight = DEFAULT_VIEWHEIGHT; - - // friction - - speed = VectorLength (pm->ps->velocity); - if (speed < 1) - { - VectorCopy (vec3_origin, pm->ps->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 (pm->ps->velocity, newspeed, pm->ps->velocity); - } - - // accelerate - scale = PM_CmdScale( &pm->cmd ); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - 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); - wishspeed *= scale; - - PM_Accelerate( wishdir, wishspeed, pm_accelerate ); - - // move - VectorMA (pm->ps->origin, pml.frametime, pm->ps->velocity, pm->ps->origin); -} - -//============================================================================ - -/* -================ -PM_FootstepForSurface - -Returns an event number apropriate for the groundsurface -================ -*/ -static int PM_FootstepForSurface( void ) -{ - //TA: - if ( pm->ps->stats[ STAT_STATE ] & SS_CREEPSLOWED ) - return EV_FOOTSTEP_SQUELCH; - - if ( pml.groundTrace.surfaceFlags & SURF_NOSTEPS ) - return 0; - - if ( pml.groundTrace.surfaceFlags & SURF_METALSTEPS ) - return EV_FOOTSTEP_METAL; - - return EV_FOOTSTEP; -} - - -/* -================= -PM_CrashLand - -Check for hard landings that generate sound events -================= -*/ -static void PM_CrashLand( void ) { - float delta; - float dist; - float vel, acc; - float t; - float a, b, c, den; - - // decide which landing animation to use - if ( pm->ps->pm_flags & PMF_BACKWARDS_JUMP ) { - PM_ForceLegsAnim( LEGS_LANDB ); - } else { - PM_ForceLegsAnim( LEGS_LAND ); - } - - pm->ps->legsTimer = TIMER_LAND; - - // calculate the exact velocity on landing - dist = pm->ps->origin[2] - pml.previous_origin[2]; - vel = pml.previous_velocity[2]; - acc = -pm->ps->gravity; - - a = acc / 2; - b = vel; - c = -dist; - - den = b * b - 4 * a * c; - if ( den < 0 ) { - return; - } - t = (-b - sqrt( den ) ) / ( 2 * a ); - - delta = vel + t * acc; - delta = delta*delta * 0.0001; - - // ducking while falling doubles damage - if ( pm->ps->pm_flags & PMF_DUCKED ) { - delta *= 2; - } - - // never take falling damage if completely underwater - if ( pm->waterlevel == 3 ) { - return; - } - - // reduce falling damage if there is standing water - if ( pm->waterlevel == 2 ) { - delta *= 0.25; - } - if ( pm->waterlevel == 1 ) { - delta *= 0.5; - } - - if ( delta < 1 ) { - return; - } - - // create a local entity event to play the sound - - // SURF_NODAMAGE is used for bounce pads where you don't ever - // want to take damage or play a crunch sound - if ( !(pml.groundTrace.surfaceFlags & SURF_NODAMAGE) ) { - if ( delta > 60 ) { - PM_AddEvent( EV_FALL_FAR ); - } else if ( delta > 40 ) { - // this is a pain grunt, so don't play it if dead - if ( pm->ps->stats[STAT_HEALTH] > 0 ) { - PM_AddEvent( EV_FALL_MEDIUM ); - } - } else if ( delta > 7 ) { - PM_AddEvent( EV_FALL_SHORT ); - } else { - PM_AddEvent( PM_FootstepForSurface() ); - } - } - - // start footstep cycle over - pm->ps->bobCycle = 0; -} - - -/* -============= -PM_CorrectAllSolid -============= -*/ -static int PM_CorrectAllSolid( trace_t *trace ) { - int i, j, k; - vec3_t point; - - if ( pm->debugLevel ) { - Com_Printf("%i:allsolid\n", c_pmove); - } - - // jitter around - for (i = -1; i <= 1; i++) { - for (j = -1; j <= 1; j++) { - for (k = -1; k <= 1; k++) { - VectorCopy(pm->ps->origin, point); - point[0] += (float) i; - point[1] += (float) j; - point[2] += (float) k; - pm->trace (trace, point, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - if ( !trace->allsolid ) { - point[0] = pm->ps->origin[0]; - point[1] = pm->ps->origin[1]; - point[2] = pm->ps->origin[2] - 0.25; - - pm->trace (trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - pml.groundTrace = *trace; - return qtrue; - } - } - } - } - - pm->ps->groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = qfalse; - pml.walking = qfalse; - - return qfalse; -} - - -/* -============= -PM_GroundTraceMissed - -The ground trace didn't hit a surface, so we are in freefall -============= -*/ -static void PM_GroundTraceMissed( void ) { - trace_t trace; - vec3_t point; - - if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) { - // we just transitioned into freefall - if ( pm->debugLevel ) { - Com_Printf("%i:lift\n", c_pmove); - } - - // if they aren't in a jumping animation and the ground is a ways away, force into it - // if we didn't do the trace, the player would be backflipping down staircases - VectorCopy( pm->ps->origin, point ); - point[2] -= 64; - - pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - if ( trace.fraction == 1.0 ) { - if ( pm->cmd.forwardmove >= 0 ) { - PM_ForceLegsAnim( LEGS_JUMP ); - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; - } else { - PM_ForceLegsAnim( LEGS_JUMPB ); - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; - } - } - } - - pm->ps->groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = qfalse; - pml.walking = qfalse; -} - - -/* -============= -PM_GroundClimbTrace -============= -*/ -static void PM_GroundClimbTrace( void ) -{ - vec3_t surfNormal, movedir, forward, right, point, srotAxis; - vec3_t refNormal = { 0, 0, 1 }; - vec3_t ceilingNormal = { 0, 0, -1 }; - float toAngles[3], surfAngles[3], srotAngle; - trace_t trace; - int i; - qboolean smoothed = qtrue; - - //TA: If we're on the ceiling then grapplePoint is a rotation normal.. otherwise its a surface normal. - // would have been nice if Carmack had left a few random variables in the ps struct for mod makers - if( pm->ps->stats[ STAT_STATE ] & SS_GPISROTVEC ) - VectorCopy( ceilingNormal, surfNormal ); - else - VectorCopy( pm->ps->grapplePoint, surfNormal ); - - //construct a vector which reflects the direction the player is looking wrt the surface normal - AngleVectors( wcl[ pm->ps->clientNum ].nonSvangles, forward, NULL, NULL ); - CrossProduct( forward, surfNormal, right ); - VectorNormalize( right ); - CrossProduct( surfNormal, right, movedir ); - VectorNormalize( movedir ); - - //rotate this direction vector based upon what direction the player is /trying/ to move to - /*if( pm->cmd.forwardmove || pm->cmd.rightmove ) - { - if( ( pm->cmd.rightmove < 0 ) && ( pm->cmd.forwardmove > 0 ) ) - RotatePointAroundVector( movedir, surfNormal, movedir, 45 ); - else if( ( pm->cmd.rightmove < 0 ) && ( pm->cmd.forwardmove == 0 ) ) - RotatePointAroundVector( movedir, surfNormal, movedir, 90 ); - else if( ( pm->cmd.rightmove < 0 ) && ( pm->cmd.forwardmove < 0 ) ) - RotatePointAroundVector( movedir, surfNormal, movedir, 135 ); - else if( ( pm->cmd.rightmove == 0 ) && ( pm->cmd.forwardmove < 0 ) ) - RotatePointAroundVector( movedir, surfNormal, movedir, 180 ); - else if( ( pm->cmd.rightmove > 0 ) && ( pm->cmd.forwardmove < 0 ) ) - RotatePointAroundVector( movedir, surfNormal, movedir, -135 ); - else if( ( pm->cmd.rightmove > 0 ) && ( pm->cmd.forwardmove == 0 ) ) - RotatePointAroundVector( movedir, surfNormal, movedir, -90 ); - else if( ( pm->cmd.rightmove > 0 ) && ( pm->cmd.forwardmove > 0 ) ) - RotatePointAroundVector( movedir, surfNormal, movedir, -45 ); - }*/ - - //TA: 3am, code make no sense, but code work... leave it be... - if( pm->cmd.forwardmove < 0 ) - VectorInverse( movedir ); - //RotatePointAroundVector( movedir, surfNormal, movedir, 180 ); - - for(i = 0; i <= 3; i++) - { - - switch ( i ) - { - case 0: - //trace into direction we are moving - VectorMA( pm->ps->origin, 0.25, movedir, point ); - pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - break; - - case 1: - //trace straight down anto "ground" surface - VectorMA( pm->ps->origin, -0.25, surfNormal, point ); - pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - break; - - case 2: - //trace "underneath" BBOX so we can traverse angles > 180deg - //TA: I can't believe this actually works :0 - its gotta be messing with something - // I would like a better way if one exists... - if( pml.groundPlane != qfalse ) - { - VectorMA( pm->ps->origin, -16, surfNormal, point ); - VectorMA( point, -16, movedir, point ); - pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - } - break; - - case 3: - //fall back so we don't have to modify PM_GroundTrace too much - VectorCopy( pm->ps->origin, point ); - point[2] = pm->ps->origin[2] - 0.25; - pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - break; - } - - //experimental: slow down speed around transitions - pm->ps->stats[ STAT_STATE ] &= ~SS_WALLTRANSIDING; - - //if we hit something - if( trace.fraction < 1.0 && !( trace.surfaceFlags & ( SURF_SKY | SURF_NOIMPACT ) ) && !( trace.entityNum != 1022 && i != 3 ) ) - { - if( i == 2 ) - VectorCopy( trace.endpos, pm->ps->origin ); - - //if the trace result and old surface normal are different then we must have transided to a new - //surface... do some stuff... - if( !VectorCompare( trace.plane.normal, surfNormal ) ) - { - //experimental: slow down speed around transitions - pm->ps->stats[ STAT_STATE ] |= SS_WALLTRANSIDING; - - //if the trace result or the old vector is not the floor or ceiling correct the YAW angle - if( !VectorCompare( trace.plane.normal, refNormal ) && !VectorCompare( surfNormal, refNormal ) && - !VectorCompare( trace.plane.normal, ceilingNormal ) && !VectorCompare( surfNormal, ceilingNormal ) ) - { - vectoangles( trace.plane.normal, toAngles ); - vectoangles( surfNormal, surfAngles ); - - pm->ps->delta_angles[1] -= ANGLE2SHORT( surfAngles[1] - toAngles[1] ); - } - - //transition from wall to ceiling - //normal for subsequent viewangle rotations - if( VectorCompare( trace.plane.normal, ceilingNormal ) ) - { - CrossProduct( surfNormal, trace.plane.normal, pm->ps->grapplePoint ); - VectorNormalize( pm->ps->grapplePoint ); - pm->ps->stats[ STAT_STATE ] |= SS_GPISROTVEC; - } - - //transition from ceiling to wall - //we need to do some different angle correction here cos GPISROTVEC - if( VectorCompare( surfNormal, ceilingNormal ) ) - { - vectoangles( trace.plane.normal, toAngles ); - vectoangles( pm->ps->grapplePoint, surfAngles ); - - pm->ps->delta_angles[1] -= ANGLE2SHORT( ( ( surfAngles[1] - toAngles[1] ) * 2 ) - 180 ); - } - - //TA: smooth transitions - CrossProduct( surfNormal, trace.plane.normal, srotAxis ); - VectorNormalize( srotAxis ); - srotAngle = abs( RAD2DEG( arccos( DotProduct( surfNormal, trace.plane.normal ) ) ) ); - - PM_AddSmoothOp( srotAxis, srotAngle ); - smoothed = qfalse; - } - - pml.groundTrace = trace; - - //so everything knows where we're wallclimbing - pm->ps->stats[ STAT_STATE ] |= SS_WALLCLIMBING; - pm->ps->legsAnim |= ANIM_WALLCLIMBING; - - //if we're not stuck to the ceiling then set grapplePoint to be a surface normal - if( !VectorCompare( trace.plane.normal, ceilingNormal ) ) - { - //so we know what surface we're stuck to - VectorCopy( trace.plane.normal, pm->ps->grapplePoint ); - pm->ps->stats[ STAT_STATE ] &= ~SS_GPISROTVEC; - } - - //so that surf -> empty space is smoothed - wcl[ pm->ps->clientNum ].justFallen = qtrue; - VectorCopy( pm->ps->grapplePoint, wcl[ pm->ps->clientNum ].lastNormal ); - - //IMPORTANT: break out of the for loop if we've hit something - break; - } - else if ( trace.allsolid ) - { - // do something corrective if the trace starts in a solid... - //TA: fuck knows what this does with all my new stuff :( - if ( !PM_CorrectAllSolid(&trace) ) - return; - } - } - - if ( trace.fraction >= 1.0 ) - { - // if the trace didn't hit anything, we are in free fall - //Com_Printf("trace missed\n"); - PM_GroundTraceMissed(); - pml.groundPlane = qfalse; - pml.walking = qfalse; - pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBING; - pm->ps->legsAnim &= ~ANIM_WALLCLIMBING; - - if( wcl[ pm->ps->clientNum ].justFallen && !smoothed ) - { - if( pm->ps->stats[ STAT_STATE ] & SS_GPISROTVEC ) - { - //FIXME: need some delta-correction here - //pm->ps->delta_angles[1] -= ANGLE2SHORT( ( ( nonSvangles[1] - pm->ps->grapplePoint[1] ) * 2) ); - AngleVectors( pm->ps->viewangles, NULL, srotAxis, NULL ); - - srotAngle = 180; - } - else - { - CrossProduct( wcl[ pm->ps->clientNum ].lastNormal, refNormal, srotAxis ); - VectorNormalize( srotAxis ); - srotAngle = abs( RAD2DEG( arccos( DotProduct( refNormal, wcl[ pm->ps->clientNum ].lastNormal ) ) ) ); - } - - PM_AddSmoothOp( srotAxis, srotAngle ); - } - - pm->ps->stats[ STAT_STATE ] &= ~SS_GPISROTVEC; - - //we get very bizarre effects if we don't do this :0 - VectorCopy( refNormal, pm->ps->grapplePoint ); - wcl[ pm->ps->clientNum ].justFallen = qfalse; - return; - } - - pml.groundPlane = qtrue; - pml.walking = qtrue; - - // hitting solid ground will end a waterjump - if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) - { - pm->ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND); - pm->ps->pm_time = 0; - } - - pm->ps->groundEntityNum = trace.entityNum; - - // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; - - PM_AddTouchEnt( trace.entityNum ); -} - - -/* -============= -PM_GroundTrace -============= -*/ -static void PM_GroundTrace( void ) { - vec3_t point, forward, srotAxis; - vec3_t refNormal = { 0, 0, 1 }; - vec3_t ceilingNormal = { 0, 0, -1 }; - trace_t trace; - float srotAngle; - - if( ( pm->ps->stats[ STAT_ABILITIES ] & SCA_WALLCLIMBER ) && ( pm->cmd.upmove < 0 ) ) - { - PM_GroundClimbTrace( ); - return; - } - - pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBING; - pm->ps->legsAnim &= ~ANIM_WALLCLIMBING; - - //make sure that the surfNormal is reset to the ground - VectorCopy( refNormal, pm->ps->grapplePoint ); - - point[0] = pm->ps->origin[0]; - point[1] = pm->ps->origin[1]; - point[2] = pm->ps->origin[2] - 0.25; - - pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - pml.groundTrace = trace; - - // do something corrective if the trace starts in a solid... - if ( trace.allsolid ) { - if ( !PM_CorrectAllSolid(&trace) ) - return; - } - - if( wcl[ pm->ps->clientNum ].justFallen ) - { - if( pm->ps->stats[ STAT_STATE ] & SS_GPISROTVEC ) - { - //FIXME: need some delta-correction here - //pm->ps->delta_angles[1] -= ANGLE2SHORT( ( ( nonSvangles[1] - pm->ps->grapplePoint[1] ) * 2) ); - AngleVectors( wcl[ pm->ps->clientNum ].nonSvangles, NULL, srotAxis, NULL ); - - srotAngle = 180; - } - else - { - CrossProduct( wcl[ pm->ps->clientNum ].lastNormal, refNormal, srotAxis ); - VectorNormalize( srotAxis ); - - srotAngle = abs( RAD2DEG( arccos( DotProduct( refNormal, wcl[ pm->ps->clientNum ].lastNormal ) ) ) ); - } - - PM_AddSmoothOp( srotAxis, srotAngle ); - } - - //things have already been smoothed.. - wcl[ pm->ps->clientNum ].justFallen = qfalse; - - // if the trace didn't hit anything, we are in free fall - if ( trace.fraction == 1.0 ) { - PM_GroundTraceMissed(); - pml.groundPlane = qfalse; - pml.walking = qfalse; - - pm->ps->stats[ STAT_STATE ] &= ~SS_GPISROTVEC; - - //we get very bizarre effects if we don't do this :0 - VectorCopy( refNormal, pm->ps->grapplePoint ); - - return; - } - - // check if getting thrown off the ground - if ( pm->ps->velocity[2] > 0 && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10 ) { - if ( pm->debugLevel ) { - Com_Printf("%i:kickoff\n", c_pmove); - } - // go into jump animation - if ( pm->cmd.forwardmove >= 0 ) { - PM_ForceLegsAnim( LEGS_JUMP ); - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; - } else { - PM_ForceLegsAnim( LEGS_JUMPB ); - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; - } - - pm->ps->groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = qfalse; - pml.walking = qfalse; - return; - } - - // slopes that are too steep will not be considered onground - if ( trace.plane.normal[2] < MIN_WALK_NORMAL ) { - if ( pm->debugLevel ) { - Com_Printf("%i:steep\n", c_pmove); - } - // FIXME: if they can't slide down the slope, let them - // walk (sharp crevices) - pm->ps->groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = qtrue; - pml.walking = qfalse; - return; - } - - pml.groundPlane = qtrue; - pml.walking = qtrue; - - // hitting solid ground will end a waterjump - if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) - { - pm->ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND); - pm->ps->pm_time = 0; - } - - if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) { - // just hit the ground - if ( pm->debugLevel ) { - Com_Printf("%i:Land\n", c_pmove); - } - - if( pm->ps->stats[ STAT_ABILITIES ] & SCA_TAKESFALLDAMAGE ) - PM_CrashLand(); - - // don't do landing time if we were just going down a slope - if ( pml.previous_velocity[2] < -200 ) { - // don't allow another jump for a little while - pm->ps->pm_flags |= PMF_TIME_LAND; - pm->ps->pm_time = 250; - } - } - - pm->ps->groundEntityNum = trace.entityNum; - - // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; - - PM_AddTouchEnt( trace.entityNum ); -} - - -/* -============= -PM_SetWaterLevel FIXME: avoid this twice? certainly if not moving -============= -*/ -static void PM_SetWaterLevel( void ) { - vec3_t point; - int cont; - int sample1; - int sample2; - - // - // get waterlevel, accounting for ducking - // - pm->waterlevel = 0; - pm->watertype = 0; - - point[0] = pm->ps->origin[0]; - point[1] = pm->ps->origin[1]; - point[2] = pm->ps->origin[2] + MINS_Z + 1; - cont = pm->pointcontents( point, pm->ps->clientNum ); - - if ( cont & MASK_WATER ) { - sample2 = pm->ps->viewheight - MINS_Z; - sample1 = sample2 / 2; - - pm->watertype = cont; - pm->waterlevel = 1; - point[2] = pm->ps->origin[2] + MINS_Z + sample1; - cont = pm->pointcontents (point, pm->ps->clientNum ); - if ( cont & MASK_WATER ) { - pm->waterlevel = 2; - point[2] = pm->ps->origin[2] + MINS_Z + sample2; - cont = pm->pointcontents (point, pm->ps->clientNum ); - if ( cont & MASK_WATER ){ - pm->waterlevel = 3; - } - } - } - -} - - - -/* -============== -PM_CheckDuck - -Sets mins, maxs, and pm->ps->viewheight -============== -*/ -static void PM_CheckDuck (void) -{ - trace_t trace; - vec3_t PCmins, PCmaxs, PCcmaxs; - int PCvh, PCcvh; - - switch( pm->ps->stats[ STAT_PCLASS ] ) - { - case PCL_D_BUILDER: - VectorSet( PCmins, -15, -15, -20 ); - VectorSet( PCmaxs, 15, 15, 20 ); - VectorSet( PCcmaxs, 15, 15, 20 ); - PCvh = 12; - PCcvh = 12; - break; - - case PCL_D_BASE: - VectorSet( PCmins, -15, -15, -15 ); - VectorSet( PCmaxs, 15, 15, 15 ); - VectorSet( PCcmaxs, 15, 15, 15 ); - PCvh = 4; - PCcvh = 4; - break; - - case PCL_H_BASE: - VectorSet( PCmins, -15, -15, -24 ); - VectorSet( PCmaxs, 15, 15, 32 ); - VectorSet( PCcmaxs, 15, 15, 16 ); - PCvh = 26; - PCcvh = 12; - break; - - default: - VectorSet( PCmins, -15, -15, MINS_Z ); - VectorSet( PCmaxs, 15, 15, 32 ); - VectorSet( PCcmaxs, 15, 15, 16 ); - PCvh = DEFAULT_VIEWHEIGHT; - PCcvh = CROUCH_VIEWHEIGHT; - } - - //TA: iD bug? you can still crouch when you're a spectator - if( pm->ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) - PCcvh = PCvh; - - pm->mins[0] = PCmins[0]; - pm->mins[1] = PCmins[1]; - - pm->maxs[0] = PCmaxs[0]; - pm->maxs[1] = PCmaxs[1]; - - pm->mins[2] = PCmins[2]; - - if (pm->ps->pm_type == PM_DEAD) - { - pm->maxs[2] = -8; - pm->ps->viewheight = DEAD_VIEWHEIGHT; - return; - } - - //TA: If the standing and crouching viewheights are the same the class can't crouch - if ( ( pm->cmd.upmove < 0 ) && ( PCvh != PCcvh ) ) - { // duck - pm->ps->pm_flags |= PMF_DUCKED; - } - else - { // stand up if possible - if (pm->ps->pm_flags & PMF_DUCKED) - { - // try to stand up - pm->maxs[2] = PCmaxs[2]; - pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, pm->ps->origin, pm->ps->clientNum, pm->tracemask ); - if (!trace.allsolid) - pm->ps->pm_flags &= ~PMF_DUCKED; - } - } - - if (pm->ps->pm_flags & PMF_DUCKED) - { - pm->maxs[2] = PCcmaxs[2]; - pm->ps->viewheight = PCcvh; - } - else - { - pm->maxs[2] = PCmaxs[2]; - pm->ps->viewheight = PCvh; - } -} - - - -//=================================================================== - - -/* -=============== -PM_Footsteps -=============== -*/ -static void PM_Footsteps( void ) { - float bobmove; - int old; - qboolean footstep; - - // - // calculate speed and cycle to be used for - // all cyclic walking effects - // - if( ( pm->ps->stats[STAT_ABILITIES] & SCA_WALLCLIMBER ) && ( pml.groundPlane ) ) - { - pm->xyspeed = DotProduct(pm->ps->velocity, pml.groundTrace.plane.normal); - } - else - pm->xyspeed = sqrt( pm->ps->velocity[0] * pm->ps->velocity[0] - + pm->ps->velocity[1] * pm->ps->velocity[1] ); - - if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) { - // airborne leaves position in cycle intact, but doesn't advance - if ( pm->waterlevel > 1 ) { - PM_ContinueLegsAnim( LEGS_SWIM ); - } - return; - } - - // if not trying to move - if ( !pm->cmd.forwardmove && !pm->cmd.rightmove ) { - if ( pm->xyspeed < 5 ) { - pm->ps->bobCycle = 0; // start at beginning of cycle again - if ( pm->ps->pm_flags & PMF_DUCKED ) { - PM_ContinueLegsAnim( LEGS_IDLECR ); - } else { - PM_ContinueLegsAnim( LEGS_IDLE ); - } - } - return; - } - - - footstep = qfalse; - - if ( pm->ps->pm_flags & PMF_DUCKED ) { - bobmove = 0.5; // ducked characters bob much faster - if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) { - PM_ContinueLegsAnim( LEGS_BACKCR ); - } - else { - PM_ContinueLegsAnim( LEGS_WALKCR ); - } - // ducked characters never play footsteps - /* - } else if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) { - if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) { - bobmove = 0.4; // faster speeds bob faster - footstep = qtrue; - } else { - bobmove = 0.3; - } - PM_ContinueLegsAnim( LEGS_BACK ); - */ - } else { - //TA: switch walking/running anims based on speed - //if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) { - if ( pm->xyspeed > 160 ) { - bobmove = 0.4f; // faster speeds bob faster - if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) { - PM_ContinueLegsAnim( LEGS_BACK ); - } - else { - PM_ContinueLegsAnim( LEGS_RUN ); - } - footstep = qtrue; - } else { - bobmove = 0.3f; // walking bobs slow - if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) { - PM_ContinueLegsAnim( LEGS_BACKWALK ); - } - else { - PM_ContinueLegsAnim( LEGS_WALK ); - } - } - } - - // check for footstep / splash sounds - old = pm->ps->bobCycle; - pm->ps->bobCycle = (int)( old + bobmove * pml.msec ) & 255; - - // if we just crossed a cycle boundary, play an apropriate footstep event - if ( ( ( old + 64 ) ^ ( pm->ps->bobCycle + 64 ) ) & 128 ) { - if ( pm->waterlevel == 0 ) { - // on ground will only play sounds if running - if ( footstep && !pm->noFootsteps ) { - PM_AddEvent( PM_FootstepForSurface() ); - } - } else if ( pm->waterlevel == 1 ) { - // splashing - PM_AddEvent( EV_FOOTSPLASH ); - } else if ( pm->waterlevel == 2 ) { - // wading / swimming at surface - PM_AddEvent( EV_SWIM ); - } else if ( pm->waterlevel == 3 ) { - // no sound when completely underwater - - } - } -} - -/* -============== -PM_WaterEvents - -Generate sound events for entering and leaving water -============== -*/ -static void PM_WaterEvents( void ) { // FIXME? - // - // if just entered a water volume, play a sound - // - if (!pml.previous_waterlevel && pm->waterlevel) { - PM_AddEvent( EV_WATER_TOUCH ); - } - - // - // if just completely exited a water volume, play a sound - // - if (pml.previous_waterlevel && !pm->waterlevel) { - PM_AddEvent( EV_WATER_LEAVE ); - } - - // - // check for head just going under water - // - if (pml.previous_waterlevel != 3 && pm->waterlevel == 3) { - PM_AddEvent( EV_WATER_UNDER ); - } - - // - // check for head just coming out of water - // - if (pml.previous_waterlevel == 3 && pm->waterlevel != 3) { - PM_AddEvent( EV_WATER_CLEAR ); - } -} - - -/* -=============== -PM_BeginWeaponChange -=============== -*/ -static void PM_BeginWeaponChange( int weapon ) { - if ( weapon <= WP_NONE || weapon >= WP_NUM_WEAPONS ) { - return; - } - - if ( !BG_gotWeapon( weapon, pm->ps->stats ) ) { - return; - } - - if ( pm->ps->weaponstate == WEAPON_DROPPING ) { - return; - } - - PM_AddEvent( EV_CHANGE_WEAPON ); - pm->ps->weaponstate = WEAPON_DROPPING; - pm->ps->weaponTime += 200; - PM_StartTorsoAnim( TORSO_DROP ); -} - - -/* -=============== -PM_FinishWeaponChange -=============== -*/ -static void PM_FinishWeaponChange( void ) { - int weapon; - - weapon = pm->cmd.weapon; - if ( weapon < WP_NONE || weapon >= WP_NUM_WEAPONS ) { - weapon = WP_NONE; - } - - if ( !BG_gotWeapon( weapon, pm->ps->stats ) ) { - weapon = WP_NONE; - } - - pm->ps->weapon = weapon; - pm->ps->weaponstate = WEAPON_RAISING; - pm->ps->weaponTime += 250; - PM_StartTorsoAnim( TORSO_RAISE ); -} - - -/* -============== -PM_TorsoAnimation - -============== -*/ -static void PM_TorsoAnimation( void ) { - if ( pm->ps->weaponstate == WEAPON_READY ) { - if ( pm->ps->weapon == WP_GAUNTLET ) { - PM_ContinueTorsoAnim( TORSO_STAND2 ); - } else { - PM_ContinueTorsoAnim( TORSO_STAND ); - } - return; - } -} - - -/* -============== -PM_Weapon - -Generates weapon events and modifes the weapon counter -============== -*/ -static void PM_Weapon( void ) { - int addTime; - int ammo, clips, maxclips; - static int chainGunAddTime; - - // don't allow attack until all buttons are up - if ( pm->ps->pm_flags & PMF_RESPAWNED ) { - return; - } - - // ignore if spectator - if ( pm->ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) { - return; - } - - // check for dead player - if ( pm->ps->stats[STAT_HEALTH] <= 0 ) { - pm->ps->weapon = WP_NONE; - return; - } - - // check for item using - //TA: not using q3 holdable item code - /*if ( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) - { - if ( ! ( pm->ps->pm_flags & PMF_USE_ITEM_HELD ) ) - { - if ( bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag == HI_MEDKIT - && pm->ps->stats[STAT_HEALTH] >= pm->ps->stats[STAT_MAX_HEALTH] ) - { - // don't use medkit if at max health - } - else - { - pm->ps->pm_flags |= PMF_USE_ITEM_HELD; - PM_AddEvent( EV_USE_ITEM0 + bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag ); - pm->ps->stats[STAT_HOLDABLE_ITEM] = 0; - } - return; - } - } - else - { - pm->ps->pm_flags &= ~PMF_USE_ITEM_HELD; - }*/ - - - // make weapon function - if ( pm->ps->weaponTime > 0 ) { - pm->ps->weaponTime -= pml.msec; - } - - // check for weapon change - // can't change if weapon is firing, but can change - // again if lowering or raising - if ( pm->ps->weaponTime <= 0 || pm->ps->weaponstate != WEAPON_FIRING ) { - //TA: must press use to switch weapons - if( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) - { - if( !( pm->ps->pm_flags & PMF_USE_ITEM_HELD ) ) - { - if( pm->cmd.weapon <= 32 ) - { - //if trying to select a weapon, select it - if ( pm->ps->weapon != pm->cmd.weapon ) - PM_BeginWeaponChange( pm->cmd.weapon ); - } - else if( pm->cmd.weapon > 32 ) - { - //if trying to toggle an upgrade, toggle it - if( BG_gotItem( pm->cmd.weapon - 32, pm->ps->stats ) ) //sanity check - { - if( BG_activated( pm->cmd.weapon - 32, pm->ps->stats ) ) - { - BG_deactivateItem( pm->cmd.weapon - 32, pm->ps->stats ); - } - else - { - BG_activateItem( pm->cmd.weapon - 32, pm->ps->stats ); - } - } - } - pm->ps->pm_flags |= PMF_USE_ITEM_HELD; - } - } - else - pm->ps->pm_flags &= ~PMF_USE_ITEM_HELD; - } - - if ( pm->ps->weaponTime > 0 ) { - return; - } - - // change weapon if time - if ( pm->ps->weaponstate == WEAPON_DROPPING ) { - PM_FinishWeaponChange(); - return; - } - - if ( pm->ps->weaponstate == WEAPON_RAISING ) { - pm->ps->weaponstate = WEAPON_READY; - if ( pm->ps->weapon == WP_GAUNTLET ) { - PM_StartTorsoAnim( TORSO_STAND2 ); - } else { - PM_StartTorsoAnim( TORSO_STAND ); - } - return; - } - - if( pm->ps->weapon == WP_SCANNER ) - return; //doesn't actually do anything - - // check for fire - if ( ! (pm->cmd.buttons & BUTTON_ATTACK) ) { - pm->ps->weaponTime = 0; - pm->ps->weaponstate = WEAPON_READY; - chainGunAddTime = 120; - return; - } - - // start the animation even if out of ammo - if ( pm->ps->weapon == WP_GAUNTLET ) { - // the guantlet only "fires" when it actually hits something - if ( !pm->gauntletHit ) { - pm->ps->weaponTime = 0; - pm->ps->weaponstate = WEAPON_READY; - return; - } - PM_StartTorsoAnim( TORSO_ATTACK2 ); - } else { - PM_StartTorsoAnim( TORSO_ATTACK ); - } - - BG_unpackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, &ammo, &clips, &maxclips ); - - // check for out of ammo - if ( !ammo && !clips && !BG_infiniteAmmo( pm->ps->weapon ) ) { - PM_AddEvent( EV_NOAMMO ); - pm->ps->weaponTime += 200; - return; - } - - //done reloading so give em some ammo - if( pm->ps->weaponstate == WEAPON_RELOADING ) - { - - switch( pm->ps->weapon ) - { - default: - case WP_MACHINEGUN: - clips--; - ammo = CS_MG; - break; - - } - - BG_packAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips, maxclips ); - } - - // check for end of clip - if ( !ammo && clips ) - { - pm->ps->weaponstate = WEAPON_RELOADING; - - switch( pm->ps->weapon ) - { - default: - case WP_MACHINEGUN: - addTime = 2000; - break; - - } - - pm->ps->weaponTime += addTime; - return; - } - - pm->ps->weaponstate = WEAPON_FIRING; - - // take an ammo away if not infinite - if( !BG_infiniteAmmo( pm->ps->weapon ) ) - { - ammo--; - BG_packAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips, maxclips ); - } - - // fire weapon - PM_AddEvent( EV_FIRE_WEAPON ); - - switch( pm->ps->weapon ) { - default: - case WP_GAUNTLET: - addTime = 400; - break; - case WP_LIGHTNING: - addTime = 50; - break; - case WP_SHOTGUN: - addTime = 1000; - break; - case WP_MACHINEGUN: - addTime = 100; - break; - case WP_CHAINGUN: - if( chainGunAddTime > 30 ) chainGunAddTime -= 2; - addTime = chainGunAddTime; - break; - case WP_GRENADE_LAUNCHER: - addTime = 800; - break; - case WP_ROCKET_LAUNCHER: - addTime = 800; - break; - case WP_FLAMER: - addTime = 80; - break; - case WP_RAILGUN: - addTime = 1500; - break; - case WP_BFG: - addTime = 200; - break; - case WP_GRAPPLING_HOOK: - addTime = 400; - break; - case WP_VENOM: - addTime = 200; - break; - case WP_ABUILD: - addTime = 1000; - break; - case WP_HBUILD: - addTime = 1000; - break; - case WP_SCANNER: - addTime = 1000; //abritutary since scaner doesn't "fire" - break; - } - - /*if ( pm->ps->powerups[PW_HASTE] ) { - addTime /= 1.3; - }*/ - - if( pm->ps->weapon == WP_CHAINGUN ) - { - if( pm->ps->pm_flags & PMF_DUCKED ) - { - pm->ps->delta_angles[ PITCH ] -= ANGLE2SHORT( ( ( random() * 0.5 ) - 0.125 ) * ( 30 / (float)addTime ) ); - pm->ps->delta_angles[ YAW ] -= ANGLE2SHORT( ( ( random() * 0.5 ) - 0.25 ) * ( 30.0 / (float)addTime ) ); - } - else - { - pm->ps->delta_angles[ PITCH ] -= ANGLE2SHORT( ( ( random() * 8 ) - 2 ) * ( 30.0 / (float)addTime ) ); - pm->ps->delta_angles[ YAW ] -= ANGLE2SHORT( ( ( random() * 8 ) - 4 ) * ( 30.0 / (float)addTime ) ); - } - } - - pm->ps->weaponTime += addTime; -} - -/* -================ -PM_Animate -================ -*/ -static void PM_Animate( void ) { - if ( pm->cmd.buttons & BUTTON_GESTURE ) { - if ( pm->ps->torsoTimer == 0 ) { - PM_StartTorsoAnim( TORSO_GESTURE ); - pm->ps->torsoTimer = TIMER_GESTURE; - PM_AddEvent( EV_TAUNT ); - } - } -} - - -/* -================ -PM_DropTimers -================ -*/ -static void PM_DropTimers( void ) { - // drop misc timing counter - if ( pm->ps->pm_time ) { - if ( pml.msec >= pm->ps->pm_time ) { - pm->ps->pm_flags &= ~PMF_ALL_TIMES; - pm->ps->pm_time = 0; - } else { - pm->ps->pm_time -= pml.msec; - } - } - - // drop animation counter - if ( pm->ps->legsTimer > 0 ) { - pm->ps->legsTimer -= pml.msec; - if ( pm->ps->legsTimer < 0 ) { - pm->ps->legsTimer = 0; - } - } - - if ( pm->ps->torsoTimer > 0 ) { - pm->ps->torsoTimer -= pml.msec; - if ( pm->ps->torsoTimer < 0 ) { - pm->ps->torsoTimer = 0; - } - } -} - - -/* -================ -PM_UpdateViewAngles - -This can be used as another entry point when only the viewangles -are being updated isntead of a full move -================ -*/ -void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ) { - short temp[3]; - int i; - vec3_t surfNormal, xNormal; - vec3_t axis[3], rotaxis[3], smoothaxis[3]; - vec3_t refNormal = { 0, 0, 1 }; - vec3_t ceilingNormal = { 0, 0, -1 }; - float rotAngle; - vec3_t tempang, tempang2; - - if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPINTERMISSION ) { - return; // no view changes at all - } - - if ( ps->pm_type != PM_SPECTATOR && ps->stats[STAT_HEALTH] <= 0 ) { - return; // no view changes at all - } - - // circularly clamp the angles with deltas - for (i=0 ; i<3 ; i++) { - temp[i] = cmd->angles[i] + ps->delta_angles[i]; - - if ( i == PITCH ) { - // don't let the player look up or down more than 90 degrees - if ( temp[i] > 16000 ) { - ps->delta_angles[i] = 16000 - cmd->angles[i]; - temp[i] = 16000; - } else if ( temp[i] < -16000 ) { - ps->delta_angles[i] = -16000 - cmd->angles[i]; - temp[i] = -16000; - } - } - tempang[i] = SHORT2ANGLE( temp[i] ); - } - - /*Com_Printf( "%1.2f ", ps->grapplePoint[ 0 ] ); - Com_Printf( "%1.2f ", ps->grapplePoint[ 1 ] ); - Com_Printf( "%1.2f ", ps->grapplePoint[ 2 ] ); - Com_Printf( "\n" );*/ - - //convert viewangles -> axis - AnglesToAxis( tempang, axis ); - - //the grapplePoint being a surfNormal rotation Normal hack... see above :) - if( ps->stats[ STAT_STATE ] & SS_GPISROTVEC ) - { - VectorCopy( ceilingNormal, surfNormal ); - VectorCopy( ps->grapplePoint, xNormal ); - } - else - { - //cross the reference normal and the surface normal to get the rotation axis - VectorCopy( ps->grapplePoint, surfNormal ); - if( surfNormal[2] <= 0 ) - { - CrossProduct( refNormal, surfNormal, xNormal ); - } - else - { - CrossProduct( surfNormal, refNormal, xNormal ); - } - - VectorNormalize( xNormal ); - } - - //if we're a wall climber.. and we're climbing rotate the axis - if( ( pm->ps->stats[ STAT_ABILITIES ] & SCA_WALLCLIMBER ) && - ( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) && - ( VectorLength( xNormal ) != 0 ) ) - { - //if the normal pointing straight down then the rotAngle will always be 180deg - if( surfNormal[2] == -1 ) - rotAngle = 180; - /*else if( abs( RAD2DEG( arccos( DotProduct( ps->grapplePoint, surfNormal ) ) ) ) <= 90 ) - { - //WEIRD-BUG_WORKAROUND: - //for some reason surface normals on curves in a specfic quadrant are inverted.. dunno why - VectorInverse( surfNormal ); - rotAngle = -RAD2DEG( arccos( DotProduct( surfNormal, refNormal ) ) ); - }*/ - else - rotAngle = -RAD2DEG( arccos( DotProduct( surfNormal, refNormal ) ) ); - - //hmmm could get away with only one rotation and some clever stuff later... but i'm lazy - RotatePointAroundVector( rotaxis[0], xNormal, axis[0], rotAngle ); - RotatePointAroundVector( rotaxis[1], xNormal, axis[1], rotAngle ); - RotatePointAroundVector( rotaxis[2], xNormal, axis[2], rotAngle ); - //MAJOR FIXME: try to reduce the number of vector rotations.. they kill the QVM - } - else - { - //we can't wall climb/aren't wall climbing - rotAngle = 0; - AxisCopy( axis, rotaxis ); - } - - AxisToAngles( rotaxis, wcl[ pm->ps->clientNum ].nonSvangles ); - - //force angles to -180 <= x <= 180 - for( i = 0; i < 3; i++ ) - { - while( wcl[ pm->ps->clientNum ].nonSvangles[ i ] > 180 ) - wcl[ pm->ps->clientNum ].nonSvangles[ i ] -= 360; - - while( wcl[ pm->ps->clientNum ].nonSvangles[ i ] < 180 ) - wcl[ pm->ps->clientNum ].nonSvangles[ i ] += 360; - } - //AnglesSubtract( wcl[ pm->ps->clientNum ].nonSvangles, 0, wcl[ pm->ps->clientNum ].nonSvangles ); - - //smooth transitions - if( !PM_PerformSmoothOps( rotaxis, smoothaxis ) ) - AxisCopy( rotaxis, smoothaxis ); - - //convert the new axis back to angles - AxisToAngles( smoothaxis, tempang2 ); - - //force angles to -180 <= x <= 180 - //AnglesSubtract( tempang2, 0, tempang2 ); - for( i = 0; i < 3; i++ ) - { - while( tempang2[ i ] > 180 ) - tempang2[ i ] -= 360; - - while( tempang2[ i ] < 180 ) - tempang2[ i ] += 360; - } - - //actually set the viewangles - for (i=0 ; i<3 ; i++) { - ps->viewangles[i] = tempang2[i]; - } -} - - -/* -================ -PmoveSingle - -================ -*/ -void trap_SnapVector( float *v ); - -void PmoveSingle (pmove_t *pmove) -{ - int ammo, clips, maxclips; - pm = pmove; - - BG_unpackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, &ammo, &clips, &maxclips ); - - // this counter lets us debug movement problems with a journal - // by setting a conditional breakpoint fot the previous frame - c_pmove++; - - // clear results - pm->numtouch = 0; - pm->watertype = 0; - pm->waterlevel = 0; - - if ( pm->ps->stats[STAT_HEALTH] <= 0 ) { - pm->tracemask &= ~CONTENTS_BODY; // corpses can fly through bodies - } - - // make sure walking button is clear if they are running, to avoid - // proxy no-footsteps cheats - if ( abs( pm->cmd.forwardmove ) > 64 || abs( pm->cmd.rightmove ) > 64 ) { - pm->cmd.buttons &= ~BUTTON_WALKING; - } - - // set the talk balloon flag - if ( pm->cmd.buttons & BUTTON_TALK ) { - pm->ps->eFlags |= EF_TALK; - } else { - pm->ps->eFlags &= ~EF_TALK; - } - - // set the firing flag for continuous beam weapons - if ( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION - && ( pm->cmd.buttons & BUTTON_ATTACK ) && ( ammo > 0 || clips > 0 ) ) { - pm->ps->eFlags |= EF_FIRING; - } else { - pm->ps->eFlags &= ~EF_FIRING; - } - - // clear the respawned flag if attack and use are cleared - if ( pm->ps->stats[STAT_HEALTH] > 0 && - !( pm->cmd.buttons & (BUTTON_ATTACK | BUTTON_USE_HOLDABLE) ) ) { - pm->ps->pm_flags &= ~PMF_RESPAWNED; - } - - // if talk button is down, dissallow all other input - // this is to prevent any possible intercept proxy from - // adding fake talk balloons - if ( pmove->cmd.buttons & BUTTON_TALK ) { - pmove->cmd.buttons = BUTTON_TALK; - pmove->cmd.forwardmove = 0; - pmove->cmd.rightmove = 0; - pmove->cmd.upmove = 0; - } - - // clear all pmove local vars - memset (&pml, 0, sizeof(pml)); - - // determine the time - pml.msec = pmove->cmd.serverTime - pm->ps->commandTime; - if ( pml.msec < 1 ) { - pml.msec = 1; - } else if ( pml.msec > 200 ) { - pml.msec = 200; - } - pm->ps->commandTime = pmove->cmd.serverTime; - - // save old org in case we get stuck - VectorCopy (pm->ps->origin, pml.previous_origin); - - // save old velocity for crashlanding - VectorCopy (pm->ps->velocity, pml.previous_velocity); - - pml.frametime = pml.msec * 0.001; - - AngleVectors (pm->ps->viewangles, pml.forward, pml.right, pml.up); - - if ( pm->cmd.upmove < 10 ) { - // not holding jump - pm->ps->pm_flags &= ~PMF_JUMP_HELD; - } - - // decide if backpedaling animations should be used - if ( pm->cmd.forwardmove < 0 ) { - pm->ps->pm_flags |= PMF_BACKWARDS_RUN; - } else if ( pm->cmd.forwardmove > 0 || ( pm->cmd.forwardmove == 0 && pm->cmd.rightmove ) ) { - pm->ps->pm_flags &= ~PMF_BACKWARDS_RUN; - } - - if ( pm->ps->pm_type >= PM_DEAD ) { - pm->cmd.forwardmove = 0; - pm->cmd.rightmove = 0; - pm->cmd.upmove = 0; - } - - if ( pm->ps->pm_type == PM_SPECTATOR ) { - // update the viewangles - PM_UpdateViewAngles( pm->ps, &pm->cmd ); - PM_CheckDuck (); - PM_FlyMove (); - PM_DropTimers (); - return; - } - - if ( pm->ps->pm_type == PM_NOCLIP ) { - PM_NoclipMove (); - PM_DropTimers (); - return; - } - - if (pm->ps->pm_type == PM_FREEZE) { - return; // no movement at all - } - - if ( pm->ps->pm_type == PM_INTERMISSION || pm->ps->pm_type == PM_SPINTERMISSION ) { - return; // no movement at all - } - - // set watertype, and waterlevel - PM_SetWaterLevel(); - pml.previous_waterlevel = pmove->waterlevel; - - // set mins, maxs, and viewheight - PM_CheckDuck (); - - // set groundentity - PM_GroundTrace(); - // update the viewangles - PM_UpdateViewAngles( pm->ps, &pm->cmd ); - - if ( pm->ps->pm_type == PM_DEAD ) { - PM_DeadMove (); - } - - PM_DropTimers(); - - /*if ( pm->ps->powerups[PW_FLIGHT] ) { - // flight powerup doesn't allow jump and has different friction - PM_FlyMove(); - } else*/ if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) { - PM_GrappleMove(); - // We can wiggle a bit - PM_AirMove(); - } else if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) { - PM_WaterJumpMove(); - } else if ( pm->waterlevel > 1 ) { - // swimming - PM_WaterMove(); - } else if ( pml.walking ) { - if( ( pm->ps->stats[ STAT_ABILITIES ] & SCA_WALLCLIMBER ) && - ( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) ) - PM_ClimbMove(); //TA: walking on any surface - else - PM_WalkMove(); // walking on ground - } else { - // airborne - PM_AirMove(); - } - - PM_Animate(); - - // set groundentity, watertype, and waterlevel - PM_GroundTrace(); - //TA: must update after every GroundTrace() - yet more clock cycles down the drain :( (14 vec rotations/frame) - // update the viewangles - PM_UpdateViewAngles( pm->ps, &pm->cmd ); - - PM_SetWaterLevel(); - - // weapons - PM_Weapon(); - - // torso animation - PM_TorsoAnimation(); - - // footstep events / legs animations - PM_Footsteps(); - - // entering / leaving water splashes - PM_WaterEvents(); - - // snap some parts of playerstate to save network bandwidth - trap_SnapVector( pm->ps->velocity ); -} - - -/* -================ -Pmove - -Can be called by either the server or the client -================ -*/ -void Pmove (pmove_t *pmove) { - int finalTime; - - finalTime = pmove->cmd.serverTime; - - if ( finalTime < pmove->ps->commandTime ) { - return; // should not happen - } - - if ( finalTime > pmove->ps->commandTime + 1000 ) { - pmove->ps->commandTime = finalTime - 1000; - } - - pmove->ps->pmove_framecount = (pmove->ps->pmove_framecount+1) & ((1<ps->commandTime != finalTime ) { - int msec; - - msec = finalTime - pmove->ps->commandTime; - - if ( pmove->pmove_fixed ) { - if ( msec > pmove->pmove_msec ) { - msec = pmove->pmove_msec; - } - } - else { - if ( msec > 66 ) { - msec = 66; - } - } - - - pmove->cmd.serverTime = pmove->ps->commandTime + msec; - PmoveSingle( pmove ); - - if ( pmove->ps->pm_flags & PMF_JUMP_HELD ) { - pmove->cmd.upmove = 20; - } - } - -} diff --git a/src/game/bg_public.h b/src/game/bg_public.h deleted file mode 100644 index fb8ffc66..00000000 --- a/src/game/bg_public.h +++ /dev/null @@ -1,783 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// bg_public.h -- definitions shared by both the server game and client game modules - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -// because games can change separately from the main system version, we need a -// second version that must match between game and cgame -#define GAME_VERSION "baseq3-1" - -#define DEFAULT_GRAVITY 800 -#define GIB_HEALTH -40 -#define ARMOR_PROTECTION 0.66 - -#define MAX_ITEMS 256 - -#define RANK_TIED_FLAG 0x4000 - -#define DEFAULT_SHOTGUN_SPREAD 700 -#define DEFAULT_SHOTGUN_COUNT 11 - -#define ITEM_RADIUS 15 // item sizes are needed for client side pickup detection - -#define LIGHTNING_RANGE 768 - -#define SCORE_NOT_PRESENT -9999 // for the CS_SCORES[12] when only one player is present - -#define VOTE_TIME 30000 // 30 seconds before vote times out - -#define MINS_Z -24 -#define DEFAULT_VIEWHEIGHT 26 -#define CROUCH_VIEWHEIGHT 12 -#define DEAD_VIEWHEIGHT -16 - -// -// config strings are a general means of communicating variable length strings -// from the server to all connected clients. -// - -// CS_SERVERINFO and CS_SYSTEMINFO are defined in q_shared.h -#define CS_MUSIC 2 -#define CS_MESSAGE 3 // from the map worldspawn's message field -#define CS_MOTD 4 // g_motd string for server message of the day -#define CS_WARMUP 5 // server time when the match will be restarted -#define CS_SCORES1 6 -#define CS_SCORES2 7 -#define CS_VOTE_TIME 8 -#define CS_VOTE_STRING 9 -#define CS_VOTE_YES 10 -#define CS_VOTE_NO 11 - -#define CS_TEAMVOTE_TIME 12 -#define CS_TEAMVOTE_STRING 14 -#define CS_TEAMVOTE_YES 16 -#define CS_TEAMVOTE_NO 18 - -#define CS_GAME_VERSION 20 -#define CS_LEVEL_START_TIME 21 // so the timer only shows the current level -#define CS_INTERMISSION 22 // when 1, fraglimit/timelimit has been hit and intermission will start in a second or two -#define CS_FLAGSTATUS 23 // string indicating flag status in CTF -#define CS_SHADERSTATE 24 -#define CS_BOTINFO 25 - -#define CS_ITEMS 27 // string of 0's and 1's that tell which items are present - -//TA: extra stuff: -#define CS_ABPOINTS 28 -#define CS_HBPOINTS 29 - -#define CS_MODELS 32 -#define CS_SOUNDS (CS_MODELS+MAX_MODELS) -#define CS_PLAYERS (CS_SOUNDS+MAX_SOUNDS) -#define MAX_PRECACHES 32 -#define CS_LOCATIONS (CS_PLAYERS+MAX_CLIENTS+MAX_PRECACHES) - -#define CS_MAX (CS_LOCATIONS+MAX_LOCATIONS) - -#if (CS_MAX) > MAX_CONFIGSTRINGS -#error overflow: (CS_MAX) > MAX_CONFIGSTRINGS -#endif - -typedef enum { - GT_FFA, // free for all - GT_TOURNAMENT, // one on one tournament - GT_SINGLE_PLAYER, // single player ffa - - //-- team games go after this -- - - GT_TEAM, // team deathmatch - GT_CTF, // capture the flag - GT_1FCTF, - GT_OBELISK, - GT_HARVESTER, - - GT_MAX_GAME_TYPE -} gametype_t; - -typedef enum { GENDER_MALE, GENDER_FEMALE, GENDER_NEUTER } gender_t; - -/* -=================================================================================== - -PMOVE MODULE - -The pmove code takes a player_state_t and a usercmd_t and generates a new player_state_t -and some other output data. Used for local prediction on the client game and true -movement on the server game. -=================================================================================== -*/ - -typedef enum { - PM_NORMAL, // can accelerate and turn - PM_NOCLIP, // noclip movement - PM_SPECTATOR, // still run into walls - PM_DEAD, // no acceleration or turning, but free falling - PM_FREEZE, // stuck in place with no control - PM_INTERMISSION, // no movement or status bar - PM_SPINTERMISSION // no movement or status bar -} pmtype_t; - -typedef enum { - WEAPON_READY, - WEAPON_RAISING, - WEAPON_DROPPING, - WEAPON_FIRING, - WEAPON_RELOADING -} weaponstate_t; - -//TA: clip-size defines -#define CS_MG 30 //clip-size -#define CS_CG 500 -#define CS_BFG 100 -#define CS_FLAMER 400 - -//TA: bitmasks to get ammo, clips and maxclips out of ammo array -#define BM_AMMO 0x3F -#define BM_CLIPS 0xC0 - -//TA: bitmasks to get weapons out of weapons store -#define BM_SWB 0x0000FFFF -#define BM_SW2B 0xFFFF0000 - -//TA: buildable item type -#define BIT_DROIDS 1 -#define BIT_HUMANS 2 - - -// pmove->pm_flags -#define PMF_DUCKED 1 -#define PMF_JUMP_HELD 2 -#define PMF_BACKWARDS_JUMP 8 // go into backwards land -#define PMF_BACKWARDS_RUN 16 // coast down to backwards run -#define PMF_TIME_LAND 32 // pm_time is time before rejump -#define PMF_TIME_KNOCKBACK 64 // pm_time is an air-accelerate only time -#define PMF_TIME_WATERJUMP 256 // pm_time is waterjump -#define PMF_RESPAWNED 512 // clear after attack and jump buttons come up -#define PMF_USE_ITEM_HELD 1024 -#define PMF_GRAPPLE_PULL 2048 // pull towards grapple location -#define PMF_FOLLOW 4096 // spectate following another player -#define PMF_SCOREBOARD 8192 // spectate as a scoreboard -#define PMF_INVULEXPAND 16384 // invulnerability sphere set to full size - - -#define PMF_ALL_TIMES (PMF_TIME_WATERJUMP|PMF_TIME_LAND|PMF_TIME_KNOCKBACK) - -#define MAXTOUCH 32 -typedef struct { - // state (in / out) - playerState_t *ps; - - // command (in) - usercmd_t cmd; - int tracemask; // collide against these types of surfaces - int debugLevel; // if set, diagnostic output will be printed - qboolean noFootsteps; // if the game is setup for no footsteps by the server - qboolean gauntletHit; // true if a gauntlet attack would actually hit something - - int framecount; - - // results (out) - int numtouch; - int touchents[MAXTOUCH]; - - vec3_t mins, maxs; // bounding box size - - int watertype; - int waterlevel; - - float xyspeed; - - // for fixed msec Pmove - int pmove_fixed; - int pmove_msec; - - // callbacks to test the world - // these will be different functions during game and cgame - void (*trace)( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentMask ); - int (*pointcontents)( const vec3_t point, int passEntityNum ); -} pmove_t; - -// if a full pmove isn't done on the client, you can just update the angles -void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ); -void Pmove (pmove_t *pmove); - -//=================================================================================== - - -// player_state->stats[] indexes -typedef enum { - STAT_HEALTH, - STAT_ITEMS, - STAT_ACTIVEITEMS, - STAT_WEAPONS, // 16 bit fields - STAT_WEAPONS2, //TA: another 16 bits to push the max weapon count up - STAT_ARMOR, - STAT_DEAD_YAW, // look this direction when dead (FIXME: get rid of?) - STAT_CLIENTS_READY, // bit mask of clients wishing to exit the intermission (FIXME: configstring?) - STAT_MAX_HEALTH, // health / armor limit, changable by handicap - STAT_PCLASS, //TA: player class (for droids AND humans) - STAT_PTEAM, //TA: player team - STAT_ABILITIES, //TA: client abilities (based on class) - STAT_ATTRIBS, - STAT_STAMINA, //TA: stamina (human only) - STAT_STATE //TA: client states e.g. wall climbing -} statIndex_t; - -#define SCA_WALLCLIMBER 1 -#define SCA_TAKESFALLDAMAGE 2 -#define SCA_CANZOOM 4 -#define SCA_CANJUMP 8 -#define SCA_NOWEAPONDRIFT 16 - -#define SS_WALLCLIMBING 1 -#define SS_GPISROTVEC 2 -#define SS_CREEPSLOWED 4 -#define SS_WALLTRANSIDING 8 -#define SS_SPEEDBOOST 16 - - -// player_state->persistant[] indexes -// these fields are the only part of player_state that isn't -// cleared on respawn -typedef enum { - PERS_SCORE, // !!! MUST NOT CHANGE, SERVER AND GAME BOTH REFERENCE !!! - PERS_HITS, // total points damage inflicted so damage beeps can sound on change - PERS_RANK, - PERS_TEAM, - PERS_SPAWN_COUNT, // incremented every respawn - PERS_PLAYEREVENTS, // 16 bits that can be flipped for events - PERS_REWARD, // a reward_t - PERS_ATTACKER, // clientnum of last damage inflicter - PERS_KILLED, // count of the number of times you died - // these were added for single player awards tracking - PERS_IMPRESSIVE_COUNT, - PERS_EXCELLENT_COUNT, - PERS_GAUNTLET_FRAG_COUNT, - PERS_ACCURACY_SHOTS, - PERS_ACCURACY_HITS, - //TA: FIXME: /\ get rid of award counts to make some room - - //TA: extra gubbins - PERS_POINTS, - PERS_TOTALPOINTS -} persEnum_t; - - -// entityState_t->eFlags -#define EF_DEAD 0x00000001 // don't draw a foe marker over players with EF_DEAD -#define EF_TELEPORT_BIT 0x00000004 // toggled every time the origin abruptly changes -#define EF_AWARD_EXCELLENT 0x00000008 // draw an excellent sprite -#define EF_BOUNCE 0x00000010 // for missiles -#define EF_BOUNCE_HALF 0x00000020 // for missiles -#define EF_AWARD_GAUNTLET 0x00000040 // draw a gauntlet sprite -#define EF_NODRAW 0x00000080 // may have an event, but no model (unspawned items) -#define EF_FIRING 0x00000100 // for lightning gun -#define EF_MOVER_STOP 0x00000400 // will push otherwise -#define EF_TALK 0x00001000 // draw a talk balloon -#define EF_CONNECTION 0x00002000 // draw a connection trouble sprite -#define EF_VOTED 0x00004000 // already cast a vote -#define EF_TEAMVOTED 0x00008000 // already cast a vote -#define EF_AWARD_IMPRESSIVE 0x00010000 // draw an impressive sprite - -typedef enum { - PW_NONE, - - PW_QUAD, - PW_BATTLESUIT, - PW_HASTE, - PW_INVIS, - PW_REGEN, - PW_FLIGHT, - - PW_REDFLAG, - PW_BLUEFLAG, - PW_BALL, - - PW_NUM_POWERUPS -} powerup_t; - -typedef enum { - HI_NONE, - - HI_TELEPORTER, - HI_MEDKIT, - - HI_NUM_HOLDABLE -} holdable_t; - -typedef enum { - WP_NONE, - - WP_GAUNTLET, - WP_MACHINEGUN, - WP_CHAINGUN, - WP_SHOTGUN, - WP_GRENADE_LAUNCHER, - WP_ROCKET_LAUNCHER, - WP_LIGHTNING, - WP_RAILGUN, - WP_FLAMER, - WP_PLASMAGUN, - WP_BFG, - WP_GRAPPLING_HOOK, - WP_VENOM, - WP_HBUILD, - WP_ABUILD, - WP_SCANNER, - WP_GGRENADE, - - WP_NUM_WEAPONS -} weapon_t; - -typedef enum { - UP_NONE, - - UP_TORCH, - UP_NVG, - UP_CHESTARMOUR, - UP_LIMBARMOUR, - UP_HELMET, - UP_ANTITOXIN, - UP_BATTPACK, - UP_JETPACK, - UP_THREATHELMET, - UP_BATTLESUIT, - UP_IMPANTKIT, - - UP_NUM_UPGRADES -} upgrade_t; - -typedef enum { - BA_NONE, - - BA_A_SPAWN, - BA_A_DEF1, - BA_H_SPAWN, - BA_H_DEF1, - BA_H_MCU, - - BA_NUM_BUILDABLES -} buildable_t; - -// reward sounds (stored in ps->persistant[PERS_PLAYEREVENTS]) -#define PLAYEREVENT_DENIEDREWARD 0x0001 -#define PLAYEREVENT_GAUNTLETREWARD 0x0002 -#define PLAYEREVENT_HOLYSHIT 0x0004 - -// entityState_t->event values -// entity events are for effects that take place reletive -// to an existing entities origin. Very network efficient. - -// two bits at the top of the entityState->event field -// will be incremented with each change in the event so -// that an identical event started twice in a row can -// be distinguished. And off the value with ~EV_EVENT_BITS -// to retrieve the actual event number -#define EV_EVENT_BIT1 0x00000100 -#define EV_EVENT_BIT2 0x00000200 -#define EV_EVENT_BITS (EV_EVENT_BIT1|EV_EVENT_BIT2) - -typedef enum { - EV_NONE, - - EV_FOOTSTEP, - EV_FOOTSTEP_METAL, - EV_FOOTSTEP_SQUELCH, - EV_FOOTSPLASH, - EV_FOOTWADE, - EV_SWIM, - - EV_STEP_4, - EV_STEP_8, - EV_STEP_12, - EV_STEP_16, - - EV_FALL_SHORT, - EV_FALL_MEDIUM, - EV_FALL_FAR, - - EV_JUMP_PAD, // boing sound at origin, jump sound on player - - EV_JUMP, - EV_WATER_TOUCH, // foot touches - EV_WATER_LEAVE, // foot leaves - EV_WATER_UNDER, // head touches - EV_WATER_CLEAR, // head leaves - - EV_ITEM_PICKUP, // normal item pickups are predictable - EV_GLOBAL_ITEM_PICKUP, // powerup / team sounds are broadcast to everyone - - EV_NOAMMO, - EV_CHANGE_WEAPON, - EV_FIRE_WEAPON, - - EV_USE_ITEM0, - EV_USE_ITEM1, - EV_USE_ITEM2, - EV_USE_ITEM3, - EV_USE_ITEM4, - EV_USE_ITEM5, - EV_USE_ITEM6, - EV_USE_ITEM7, - EV_USE_ITEM8, - EV_USE_ITEM9, - EV_USE_ITEM10, - EV_USE_ITEM11, - EV_USE_ITEM12, - EV_USE_ITEM13, - EV_USE_ITEM14, - EV_USE_ITEM15, - - EV_ITEM_RESPAWN, - EV_ITEM_GROW, //droid items that grow - EV_ITEM_POP, - EV_PLAYER_TELEPORT_IN, - EV_PLAYER_TELEPORT_OUT, - - EV_GRENADE_BOUNCE, // eventParm will be the soundindex - - EV_GENERAL_SOUND, - EV_GLOBAL_SOUND, // no attenuation - - EV_BULLET_HIT_FLESH, - EV_BULLET_HIT_WALL, - - EV_MISSILE_HIT, - EV_MISSILE_MISS, - EV_MISSILE_MISS_METAL, - EV_ITEM_EXPLOSION, //TA: human item explosions - EV_RAILTRAIL, - EV_SHOTGUN, - EV_BULLET, // otherEntity is the shooter - - EV_PAIN, - EV_DEATH1, - EV_DEATH2, - EV_DEATH3, - EV_OBITUARY, - - EV_POWERUP_QUAD, - EV_POWERUP_BATTLESUIT, - EV_POWERUP_REGEN, - - EV_GIB_PLAYER, // gib a previously living player - EV_GIB_GENERIC, //TA: generic green gib for droids - - EV_DEBUG_LINE, - EV_STOPLOOPINGSOUND, - EV_TAUNT, - EV_TAUNT_YES, - EV_TAUNT_NO, - EV_TAUNT_FOLLOWME, - EV_TAUNT_GETFLAG, - EV_TAUNT_GUARDBASE, - EV_TAUNT_PATROL, - - EV_MENU //TA: menu event - -} entity_event_t; - -typedef enum -{ - MN_TEAM, - MN_DROID, - MN_HUMAN, - MN_ABUILD, - MN_HBUILD -} dynMenu_t; - -// animations -typedef enum { - BOTH_DEATH1, - BOTH_DEAD1, - BOTH_DEATH2, - BOTH_DEAD2, - BOTH_DEATH3, - BOTH_DEAD3, - - TORSO_GESTURE, - - TORSO_ATTACK, - TORSO_ATTACK2, - - TORSO_DROP, - TORSO_RAISE, - - TORSO_STAND, - TORSO_STAND2, - - LEGS_WALKCR, - LEGS_WALK, - LEGS_RUN, - LEGS_BACK, - LEGS_SWIM, - - LEGS_JUMP, - LEGS_LAND, - - LEGS_JUMPB, - LEGS_LANDB, - - LEGS_IDLE, - LEGS_IDLECR, - - LEGS_TURN, - -#ifdef NEW_ANIMS - TORSO_GETFLAG, - TORSO_GUARDBASE, - TORSO_PATROL, - TORSO_FOLLOWME, - TORSO_AFFIRMATIVE, - TORSO_NEGATIVE, -#endif - - MAX_ANIMATIONS, - - LEGS_BACKCR, - LEGS_BACKWALK, - FLAG_RUN, - FLAG_STAND, - FLAG_STAND2RUN, - - MAX_TOTALANIMATIONS -} animNumber_t; - - -typedef struct animation_s { - int firstFrame; - int numFrames; - int loopFrames; // 0 to numFrames - int frameLerp; // msec between frames - int initialLerp; // msec to get to first frame - int reversed; // true if animation is reversed - int flipflop; // true if animation should flipflop back to base -} animation_t; - - -// flip the togglebit every time an animation -// changes so a restart of the same anim can be detected -#define ANIM_TOGGLEBIT 128 -#define ANIM_WALLCLIMBING 64 - - -typedef enum { - TEAM_FREE, - TEAM_HUMANS, - TEAM_DROIDS, - TEAM_SPECTATOR, - - TEAM_NUM_TEAMS -} team_t; - -// Time between location updates -#define TEAM_LOCATION_UPDATE_TIME 1000 - -// How many players on the overlay -#define TEAM_MAXOVERLAY 32 - -//FIXME: switch to enums at some point -//TA: player classes -#define PCL_D_BUILDER 1 -#define PCL_D_BASE 2 -#define PCL_D_OFF1 3 -#define PCL_D_OFF2 4 -#define PCL_D_OFF3 5 -#define PCL_D_OFF4 6 -#define PCL_D_OFF5 7 -#define PCL_D_OFF6 8 -#define PCL_D_OFF7 9 -#define PCL_D_OFF8 10 - -#define PCL_H_BASE 11 - -//TA: player teams -#define PTE_NONE 0 -#define PTE_DROIDS 1 -#define PTE_HUMANS 2 - - -// means of death -typedef enum { - MOD_UNKNOWN, - MOD_SHOTGUN, - MOD_GAUNTLET, - MOD_MACHINEGUN, - MOD_CHAINGUN, - MOD_GRENADE, - MOD_GRENADE_SPLASH, - MOD_ROCKET, - MOD_ROCKET_SPLASH, - MOD_FLAMER, - MOD_FLAMER_SPLASH, - MOD_RAILGUN, - MOD_LIGHTNING, - MOD_BFG, - MOD_BFG_SPLASH, - MOD_WATER, - MOD_SLIME, - MOD_LAVA, - MOD_CRUSH, - MOD_TELEFRAG, - MOD_FALLING, - MOD_SUICIDE, - MOD_TARGET_LASER, - MOD_TRIGGER_HURT, - MOD_GRAPPLE, - MOD_VENOM, - MOD_HSPAWN, - MOD_ASPAWN -} meansOfDeath_t; - - -//--------------------------------------------------------- - -// gitem_t->type -typedef enum { - IT_BAD, - IT_WEAPON, // EFX: rotate + upscale + minlight - IT_BUILDABLE, //TA: gitem_t->type for buildable items (spawns etc.) - IT_UPGRADE, //TA: gitem_t->type for human upgrades - IT_AMMO, // EFX: rotate - IT_ARMOR, // EFX: rotate + minlight - IT_HEALTH, // EFX: static external sphere + rotating internal - IT_POWERUP, // instant on, timer based - // EFX: rotate + external ring that rotates - IT_HOLDABLE, // single use, holdable item - // EFX: rotate + bob - IT_TEAM -} itemType_t; - -#define MAX_ITEM_MODELS 4 - -typedef struct gitem_s { - char *classname; // spawning name - char *pickup_sound; - char *world_model[MAX_ITEM_MODELS]; - - char *icon; - char *pickup_name; // for printing on pickup - - int quantity; // for ammo how much, or duration of powerup - itemType_t giType; // IT_* flags - - int giTag; - - char *precaches; // string of all models and images this item will use - char *sounds; // string of all sounds this item will use -} gitem_t; - -// included in both the game dll and the client -extern gitem_t bg_itemlist[]; -extern int bg_numItems; - -gitem_t *BG_FindItem( const char *pickupName ); -gitem_t *BG_FindItemForWeapon( weapon_t weapon ); -gitem_t *BG_FindItemForBuildable( buildable_t buildable ); -gitem_t *BG_FindItemForUpgrade( upgrade_t upgrade ); -gitem_t *BG_FindItemForPowerup( powerup_t pw ); -gitem_t *BG_FindItemForHoldable( holdable_t pw ); -#define ITEM_INDEX(x) ((x)-bg_itemlist) - -qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const playerState_t *ps ); - - -// g_dmflags->integer flags -#define DF_NO_FALLING 8 -#define DF_FIXED_FOV 16 -#define DF_NO_FOOTSTEPS 32 - -// content masks -#define MASK_ALL (-1) -#define MASK_SOLID (CONTENTS_SOLID) -#define MASK_PLAYERSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY) -#define MASK_DEADSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP) -#define MASK_WATER (CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME) -#define MASK_OPAQUE (CONTENTS_SOLID|CONTENTS_SLIME|CONTENTS_LAVA) -#define MASK_SHOT (CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_CORPSE) - - -// -// entityState_t->eType -// -typedef enum { - ET_GENERAL, - ET_PLAYER, - ET_ITEM, - - ET_BUILDABLE, //TA: buildable type - ET_CREEP, //TA: creep type - - ET_MISSILE, - ET_MOVER, - ET_BEAM, - ET_PORTAL, - ET_SPEAKER, - ET_PUSH_TRIGGER, - ET_TELEPORT_TRIGGER, - ET_INVISIBLE, - ET_GRAPPLE, // grapple hooked on wall - - ET_TORCH, //TA: torch type - ET_CORPSE, - - ET_EVENTS // any of the EV_* events can be added freestanding - // by setting eType to ET_EVENTS + eventNum - // this avoids having to set eFlags and eventNum -} entityType_t; - -void BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result ); -void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t result ); - -void BG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps ); - -void BG_TouchJumpPad( playerState_t *ps, entityState_t *jumppad ); - -void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean snap ); -void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s, int time, qboolean snap ); - -qboolean BG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTime ); - -//TA: extra bits: (which I apparently dont need) -/*void BG_unpackAmmoArray( int weapon, int ammo[ ], int ammo2[ ], int *quan, int *clips, int *maxclips ); -void BG_packAmmoArray( int weapon, int ammo[ ], int ammo2[ ], int quan, int clips, int maxclips ); -qboolean BG_infiniteAmmo( int weapon ); -void BG_packWeapon( int weapon, int stats[ ] ); -qboolean BG_gotWeapon( int weapon, int stats[ ] );*/ - -#define CREEP_BASESIZE 120 - -#define ARENAS_PER_TIER 4 -#define MAX_ARENAS 1024 -#define MAX_ARENAS_TEXT 8192 - -#define MAX_BOTS 1024 -#define MAX_BOTS_TEXT 8192 - -//TA: conceptually should live in q_shared.h -void AxisToAngles( vec3_t axis[3], vec3_t angles); -float arccos( float x ); - diff --git a/src/game/bg_slidemove.c b/src/game/bg_slidemove.c deleted file mode 100644 index 00ca010a..00000000 --- a/src/game/bg_slidemove.c +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// bg_slidemove.c -- part of bg_pmove functionality - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "q_shared.h" -#include "bg_public.h" -#include "bg_local.h" - -/* - -input: origin, velocity, bounds, groundPlane, trace function - -output: origin, velocity, impacts, stairup boolean - -*/ - -/* -================== -PM_SlideMove - -Returns qtrue if the velocity was clipped in some way -================== -*/ -#define MAX_CLIP_PLANES 5 -qboolean PM_SlideMove( qboolean gravity ) { - int bumpcount, numbumps; - vec3_t dir; - float d; - int numplanes; - vec3_t planes[MAX_CLIP_PLANES]; - vec3_t primal_velocity; - vec3_t clipVelocity; - int i, j, k; - trace_t trace; - vec3_t end; - float time_left; - float into; - vec3_t endVelocity; - vec3_t endClipVelocity; - - numbumps = 4; - - VectorCopy (pm->ps->velocity, primal_velocity); - - if ( gravity ) { - VectorCopy( pm->ps->velocity, endVelocity ); - endVelocity[2] -= pm->ps->gravity * pml.frametime; - pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5; - primal_velocity[2] = endVelocity[2]; - if ( pml.groundPlane ) { - // slide along the ground plane - PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, - pm->ps->velocity, OVERCLIP ); - } - } - - time_left = pml.frametime; - - // never turn against the ground plane - if ( pml.groundPlane ) { - numplanes = 1; - VectorCopy( pml.groundTrace.plane.normal, planes[0] ); - } else { - numplanes = 0; - } - - // never turn against original velocity - VectorNormalize2( pm->ps->velocity, planes[numplanes] ); - numplanes++; - - for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) { - - // calculate position we are trying to move to - VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end ); - - // see if we can make it there - pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask); - - if (trace.allsolid) { - // entity is completely trapped in another solid - pm->ps->velocity[2] = 0; // don't build up falling damage, but allow sideways acceleration - return qtrue; - } - - if (trace.fraction > 0) { - // actually covered some distance - VectorCopy (trace.endpos, pm->ps->origin); - } - - if (trace.fraction == 1) { - break; // moved the entire distance - } - - // save entity for contact - PM_AddTouchEnt( trace.entityNum ); - - time_left -= time_left * trace.fraction; - - if (numplanes >= MAX_CLIP_PLANES) { - // this shouldn't really happen - VectorClear( pm->ps->velocity ); - return qtrue; - } - - // - // if this is the same plane we hit before, nudge velocity - // out along it, which fixes some epsilon issues with - // non-axial planes - // - for ( i = 0 ; i < numplanes ; i++ ) { - if ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) { - VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity ); - break; - } - } - if ( i < numplanes ) { - continue; - } - VectorCopy (trace.plane.normal, planes[numplanes]); - numplanes++; - - // - // modify velocity so it parallels all of the clip planes - // - - // find a plane that it enters - for ( i = 0 ; i < numplanes ; i++ ) { - into = DotProduct( pm->ps->velocity, planes[i] ); - if ( into >= 0.1 ) { - continue; // move doesn't interact with the plane - } - - // see how hard we are hitting things - if ( -into > pml.impactSpeed ) { - pml.impactSpeed = -into; - } - - // slide along the plane - PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP ); - - // slide along the plane - PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP ); - - // see if there is a second plane that the new move enters - for ( j = 0 ; j < numplanes ; j++ ) { - if ( j == i ) { - continue; - } - if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) { - continue; // move doesn't interact with the plane - } - - // try clipping the move to the plane - PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP ); - PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP ); - - // see if it goes back into the first clip plane - if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) { - continue; - } - - // slide the original velocity along the crease - CrossProduct (planes[i], planes[j], dir); - VectorNormalize( dir ); - d = DotProduct( dir, pm->ps->velocity ); - VectorScale( dir, d, clipVelocity ); - - CrossProduct (planes[i], planes[j], dir); - VectorNormalize( dir ); - d = DotProduct( dir, endVelocity ); - VectorScale( dir, d, endClipVelocity ); - - // see if there is a third plane the the new move enters - for ( k = 0 ; k < numplanes ; k++ ) { - if ( k == i || k == j ) { - continue; - } - if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) { - continue; // move doesn't interact with the plane - } - - // stop dead at a tripple plane interaction - VectorClear( pm->ps->velocity ); - return qtrue; - } - } - - // if we have fixed all interactions, try another move - VectorCopy( clipVelocity, pm->ps->velocity ); - VectorCopy( endClipVelocity, endVelocity ); - break; - } - } - - if ( gravity ) { - VectorCopy( endVelocity, pm->ps->velocity ); - } - - // don't change velocity if in a timer (FIXME: is this correct?) - if ( pm->ps->pm_time ) { - VectorCopy( primal_velocity, pm->ps->velocity ); - } - - return ( bumpcount != 0 ); -} - -/* -================== -PM_StepSlideMove - -================== -*/ -void PM_StepSlideMove( qboolean gravity ) { - vec3_t start_o, start_v; - vec3_t down_o, down_v; - trace_t trace; -// float down_dist, up_dist; -// vec3_t delta, delta2; - vec3_t up, down; - - VectorCopy (pm->ps->origin, start_o); - VectorCopy (pm->ps->velocity, start_v); - - if ( PM_SlideMove( gravity ) == 0 ) { - return; // we got exactly where we wanted to go first try - } - - VectorCopy(start_o, down); - down[2] -= STEPSIZE; - pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask); - VectorSet(up, 0, 0, 1); - // never step up when you still have up velocity - if ( pm->ps->velocity[2] > 0 && (trace.fraction == 1.0 || - DotProduct(trace.plane.normal, up) < 0.7)) { - return; - } - - VectorCopy (pm->ps->origin, down_o); - VectorCopy (pm->ps->velocity, down_v); - - VectorCopy (start_o, up); - up[2] += STEPSIZE; - - // test the player position if they were a stepheight higher - pm->trace (&trace, up, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask); - if ( trace.allsolid ) { - if ( pm->debugLevel ) { - Com_Printf("%i:bend can't step\n", c_pmove); - } - return; // can't step up - } - - // try slidemove from this position - VectorCopy (up, pm->ps->origin); - VectorCopy (start_v, pm->ps->velocity); - - PM_SlideMove( gravity ); - - // push down the final amount - VectorCopy (pm->ps->origin, down); - down[2] -= STEPSIZE; - pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask); - if ( !trace.allsolid ) { - VectorCopy (trace.endpos, pm->ps->origin); - } - if ( trace.fraction < 1.0 ) { - PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP ); - } - -#if 0 - // if the down trace can trace back to the original position directly, don't step - pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, start_o, pm->ps->clientNum, pm->tracemask); - if ( trace.fraction == 1.0 ) { - // use the original move - VectorCopy (down_o, pm->ps->origin); - VectorCopy (down_v, pm->ps->velocity); - if ( pm->debugLevel ) { - Com_Printf("%i:bend\n", c_pmove); - } - } else -#endif - { - // use the step move - float delta; - - delta = pm->ps->origin[2] - start_o[2]; - if ( delta > 2 ) { - if ( delta < 7 ) { - PM_AddEvent( EV_STEP_4 ); - } else if ( delta < 11 ) { - PM_AddEvent( EV_STEP_8 ); - } else if ( delta < 15 ) { - PM_AddEvent( EV_STEP_12 ); - } else { - PM_AddEvent( EV_STEP_16 ); - } - } - if ( pm->debugLevel ) { - Com_Printf("%i:stepped\n", c_pmove); - } - } -} - diff --git a/src/game/g_active.c b/src/game/g_active.c deleted file mode 100644 index d8519184..00000000 --- a/src/game/g_active.c +++ /dev/null @@ -1,1059 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "g_local.h" - -/* -=============== -G_DamageFeedback - -Called just before a snapshot is sent to the given player. -Totals up all damage and generates both the player_state_t -damage values to that client for pain blends and kicks, and -global pain sound events for all clients. -=============== -*/ -void P_DamageFeedback( gentity_t *player ) { - gclient_t *client; - float count; - vec3_t angles; - - client = player->client; - if ( client->ps.pm_type == PM_DEAD ) { - return; - } - - // total points of damage shot at the player this frame - count = client->damage_blood + client->damage_armor; - if ( count == 0 ) { - return; // didn't take any damage - } - - if ( count > 255 ) { - count = 255; - } - - // send the information to the client - - // world damage (falling, slime, etc) uses a special code - // to make the blend blob centered instead of positional - if ( client->damage_fromWorld ) { - client->ps.damagePitch = 255; - client->ps.damageYaw = 255; - - client->damage_fromWorld = qfalse; - } else { - vectoangles( client->damage_from, angles ); - client->ps.damagePitch = angles[PITCH]/360.0 * 256; - client->ps.damageYaw = angles[YAW]/360.0 * 256; - } - - // play an apropriate pain sound - if ( (level.time > player->pain_debounce_time) && !(player->flags & FL_GODMODE) ) { - player->pain_debounce_time = level.time + 700; - G_AddEvent( player, EV_PAIN, player->health ); - client->ps.damageEvent++; - } - - - client->ps.damageCount = count; - - // - // clear totals - // - client->damage_blood = 0; - client->damage_armor = 0; - client->damage_knockback = 0; -} - - - -/* -============= -P_WorldEffects - -Check for lava / slime contents and drowning -============= -*/ -void P_WorldEffects( gentity_t *ent ) { - qboolean envirosuit; - int waterlevel; - - if ( ent->client->noclip ) { - ent->client->airOutTime = level.time + 12000; // don't need air - return; - } - - waterlevel = ent->waterlevel; - - envirosuit = /*ent->client->ps.powerups[PW_BATTLESUIT]*/ 0 > level.time; - - // - // check for drowning - // - if ( waterlevel == 3 ) { - // envirosuit give air - if ( envirosuit ) { - ent->client->airOutTime = level.time + 10000; - } - - // if out of air, start drowning - if ( ent->client->airOutTime < level.time) { - // drown! - ent->client->airOutTime += 1000; - if ( ent->health > 0 ) { - // take more damage the longer underwater - ent->damage += 2; - if (ent->damage > 15) - ent->damage = 15; - - // play a gurp sound instead of a normal pain sound - if (ent->health <= ent->damage) { - G_Sound(ent, CHAN_VOICE, G_SoundIndex("*drown.wav")); - } else if (rand()&1) { - G_Sound(ent, CHAN_VOICE, G_SoundIndex("sound/player/gurp1.wav")); - } else { - G_Sound(ent, CHAN_VOICE, G_SoundIndex("sound/player/gurp2.wav")); - } - - // don't play a normal pain sound - ent->pain_debounce_time = level.time + 200; - - G_Damage (ent, NULL, NULL, NULL, NULL, - ent->damage, DAMAGE_NO_ARMOR, MOD_WATER); - } - } - } else { - ent->client->airOutTime = level.time + 12000; - ent->damage = 2; - } - - // - // check for sizzle damage (move to pmove?) - // - if (waterlevel && - (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) { - if (ent->health > 0 - && ent->pain_debounce_time <= level.time ) { - - if ( envirosuit ) { - G_AddEvent( ent, EV_POWERUP_BATTLESUIT, 0 ); - } else { - if (ent->watertype & CONTENTS_LAVA) { - G_Damage (ent, NULL, NULL, NULL, NULL, - 30*waterlevel, 0, MOD_LAVA); - } - - if (ent->watertype & CONTENTS_SLIME) { - G_Damage (ent, NULL, NULL, NULL, NULL, - 10*waterlevel, 0, MOD_SLIME); - } - } - } - } -} - - - -/* -=============== -G_SetClientSound -=============== -*/ -void G_SetClientSound( gentity_t *ent ) { - if (ent->waterlevel && (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) { - ent->client->ps.loopSound = level.snd_fry; - } else { - ent->client->ps.loopSound = 0; - } -} - - - -//============================================================== - -/* -============== -ClientImpacts -============== -*/ -void ClientImpacts( gentity_t *ent, pmove_t *pm ) { - int i, j; - trace_t trace; - gentity_t *other; - - memset( &trace, 0, sizeof( trace ) ); - for (i=0 ; inumtouch ; i++) { - for (j=0 ; jtouchents[j] == pm->touchents[i] ) { - break; - } - } - if (j != i) { - continue; // duplicated - } - other = &g_entities[ pm->touchents[i] ]; - - if ( ( ent->r.svFlags & SVF_BOT ) && ( ent->touch ) ) { - ent->touch( ent, other, &trace ); - } - - if ( !other->touch ) { - continue; - } - - other->touch( other, ent, &trace ); - } - -} - -/* -============ -G_TouchTriggers - -Find all trigger entities that ent's current position touches. -Spectators will only interact with teleporters. -============ -*/ -void G_TouchTriggers( gentity_t *ent ) { - int i, num; - int touch[MAX_GENTITIES]; - gentity_t *hit; - trace_t trace; - vec3_t mins, maxs; - static vec3_t range = { 40, 40, 52 }; - - if ( !ent->client ) { - return; - } - - // dead clients don't activate triggers! - if ( ent->client->ps.stats[STAT_HEALTH] <= 0 ) { - return; - } - - VectorSubtract( ent->client->ps.origin, range, mins ); - VectorAdd( ent->client->ps.origin, range, maxs ); - - num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES ); - - // can't use ent->absmin, because that has a one unit pad - VectorAdd( ent->client->ps.origin, ent->r.mins, mins ); - VectorAdd( ent->client->ps.origin, ent->r.maxs, maxs ); - - for ( i=0 ; itouch && !ent->touch ) { - continue; - } - if ( !( hit->r.contents & CONTENTS_TRIGGER ) ) { - continue; - } - - // ignore most entities if a spectator - if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) { - if ( hit->s.eType != ET_TELEPORT_TRIGGER && - // this is ugly but adding a new ET_? type will - // most likely cause network incompatibilities - hit->touch != Touch_DoorTrigger) { - continue; - } - } - - // use seperate code for determining if an item is picked up - // so you don't have to actually contact its bounding box - if ( hit->s.eType == ET_ITEM || hit->s.eType == ET_BUILDABLE ) { - if ( !BG_PlayerTouchesItem( &ent->client->ps, &hit->s, level.time ) ) { - continue; - } - } else { - if ( !trap_EntityContact( mins, maxs, hit ) ) { - continue; - } - } - - memset( &trace, 0, sizeof(trace) ); - - if ( hit->touch ) { - hit->touch (hit, ent, &trace); - } - - if ( ( ent->r.svFlags & SVF_BOT ) && ( ent->touch ) ) { - ent->touch( ent, hit, &trace ); - } - } - - // if we didn't touch a jump pad this pmove frame - if ( ent->client->ps.jumppad_frame != ent->client->ps.pmove_framecount ) { - ent->client->ps.jumppad_frame = 0; - ent->client->ps.jumppad_ent = 0; - } -} - -/* -================= -SpectatorThink -================= -*/ -void SpectatorThink( gentity_t *ent, usercmd_t *ucmd ) { - pmove_t pm; - gclient_t *client; - - client = ent->client; - - if ( client->sess.spectatorState != SPECTATOR_FOLLOW ) { - - if( client->sess.spectatorState == SPECTATOR_LOCKED ) - client->ps.pm_type = PM_FREEZE; - else - client->ps.pm_type = PM_SPECTATOR; - - client->ps.speed = 400; // faster than normal - - // set up for pmove - memset (&pm, 0, sizeof(pm)); - pm.ps = &client->ps; - pm.cmd = *ucmd; - pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY; // spectators can fly through bodies - pm.trace = trap_Trace; - pm.pointcontents = trap_PointContents; - - // perform a pmove - Pmove (&pm); - - // save results of pmove - VectorCopy( client->ps.origin, ent->s.origin ); - - G_TouchTriggers( ent ); - trap_UnlinkEntity( ent ); - } - - client->oldbuttons = client->buttons; - client->buttons = ucmd->buttons; - - if ( ( client->buttons & BUTTON_ATTACK ) && !( client->oldbuttons & BUTTON_ATTACK ) ) - { - if( client->pers.pteam == PTE_NONE ) - { - G_AddPredictableEvent( ent, EV_MENU, MN_TEAM ); - } - else if( client->pers.pteam == PTE_DROIDS ) - { - G_AddPredictableEvent( ent, EV_MENU, MN_DROID ); - } - else if( client->pers.pteam == PTE_HUMANS ) - { - G_AddPredictableEvent( ent, EV_MENU, MN_HUMAN ); - } - } - - // attack button cycles through spectators - //TA: messes with the menus - /*if ( ( client->buttons & BUTTON_ATTACK ) && - !( client->oldbuttons & BUTTON_ATTACK ) && - ( client->sess.spectatorState != SPECTATOR_LOCKED ) ) - Cmd_FollowCycle_f( ent, 1 );*/ -} - - - -/* -================= -ClientInactivityTimer - -Returns qfalse if the client is dropped -================= -*/ -qboolean ClientInactivityTimer( gclient_t *client ) { - if ( ! g_inactivity.integer ) { - // give everyone some time, so if the operator sets g_inactivity during - // gameplay, everyone isn't kicked - client->inactivityTime = level.time + 60 * 1000; - client->inactivityWarning = qfalse; - } else if ( client->pers.cmd.forwardmove || - client->pers.cmd.rightmove || - client->pers.cmd.upmove || - (client->pers.cmd.buttons & BUTTON_ATTACK) ) { - client->inactivityTime = level.time + g_inactivity.integer * 1000; - client->inactivityWarning = qfalse; - } else if ( !client->pers.localClient ) { - if ( level.time > client->inactivityTime ) { - trap_DropClient( client - level.clients, "Dropped due to inactivity" ); - return qfalse; - } - if ( level.time > client->inactivityTime - 10000 && !client->inactivityWarning ) { - client->inactivityWarning = qtrue; - trap_SendServerCommand( client - level.clients, "cp \"Ten seconds until inactivity drop!\n\"" ); - } - } - return qtrue; -} - -/* -================== -ClientTimerActions - -Actions that happen once a second -================== -*/ -void ClientTimerActions( gentity_t *ent, int msec ) { - gclient_t *client; - - client = ent->client; - client->timeResidual += msec; - - while ( client->timeResidual >= 1000 ) { - client->timeResidual -= 1000; - - // regenerate - /*if ( client->ps.powerups[PW_REGEN] ) - { - if ( ent->health < client->ps.stats[STAT_MAX_HEALTH]) - { - ent->health += 15; - if ( ent->health > client->ps.stats[STAT_MAX_HEALTH] * 1.1 ) - { - ent->health = client->ps.stats[STAT_MAX_HEALTH] * 1.1; - } - G_AddEvent( ent, EV_POWERUP_REGEN, 0 ); - } - else if ( ent->health < client->ps.stats[STAT_MAX_HEALTH] * 2) - { - ent->health += 5; - if ( ent->health > client->ps.stats[STAT_MAX_HEALTH] * 2 ) - { - ent->health = client->ps.stats[STAT_MAX_HEALTH] * 2; - } - G_AddEvent( ent, EV_POWERUP_REGEN, 0 ); - } - } - else - { - // count down health when over max - if ( ent->health > client->ps.stats[STAT_MAX_HEALTH] ) - { - //TA: dont count health and armo(u)r down - //ent->health--; - } - }*/ - - // count down armor when over max - if ( client->ps.stats[STAT_ARMOR] > client->ps.stats[STAT_MAX_HEALTH] ) { - //client->ps.stats[STAT_ARMOR]--; - } - - } -} - -/* -==================== -ClientIntermissionThink -==================== -*/ -void ClientIntermissionThink( gclient_t *client ) { - client->ps.eFlags &= ~EF_TALK; - client->ps.eFlags &= ~EF_FIRING; - - // the level will exit when everyone wants to or after timeouts - - // swap and latch button actions - client->oldbuttons = client->buttons; - client->buttons = client->pers.cmd.buttons; - if ( client->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) & ( client->oldbuttons ^ client->buttons ) ) { - client->readyToExit = 1; - } -} - - -/* -================ -ClientEvents - -Events will be passed on to the clients for presentation, -but any server game effects are handled here -================ -*/ -void ClientEvents( gentity_t *ent, int oldEventSequence ) { - int i, j; - int event; - gclient_t *client; - int damage; - vec3_t dir; - vec3_t origin, angles; -// qboolean fired; - gitem_t *item; - gentity_t *drop; - - client = ent->client; - - if ( oldEventSequence < client->ps.eventSequence - MAX_PS_EVENTS ) { - oldEventSequence = client->ps.eventSequence - MAX_PS_EVENTS; - } - for ( i = oldEventSequence ; i < client->ps.eventSequence ; i++ ) { - event = client->ps.events[ i & (MAX_PS_EVENTS-1) ]; - - switch ( event ) { - case EV_FALL_MEDIUM: - case EV_FALL_FAR: - if ( ent->s.eType != ET_PLAYER ) { - break; // not in the player model - } - if ( g_dmflags.integer & DF_NO_FALLING ) { - break; - } - if ( event == EV_FALL_FAR ) { - damage = 10; - } else { - damage = 5; - } - VectorSet (dir, 0, 0, 1); - ent->pain_debounce_time = level.time + 200; // no normal pain sound - G_Damage (ent, NULL, NULL, NULL, NULL, damage, 0, MOD_FALLING); - break; - - case EV_FIRE_WEAPON: - FireWeapon( ent ); - break; - - case EV_USE_ITEM1: // teleporter - // drop flags in CTF - item = NULL; - j = 0; - - /*if ( ent->client->ps.powerups[ PW_REDFLAG ] ) { - item = BG_FindItemForPowerup( PW_REDFLAG ); - i = PW_REDFLAG; - } else if ( ent->client->ps.powerups[ PW_BLUEFLAG ] ) { - item = BG_FindItemForPowerup( PW_BLUEFLAG ); - i = PW_BLUEFLAG; - }*/ - - if ( item ) { - drop = Drop_Item( ent, item, 0 ); - // decide how many seconds it has left - drop->count = ( ent->client->ps.powerups[ j ] - level.time ) / 1000; - if ( drop->count < 1 ) { - drop->count = 1; - } - - ent->client->ps.powerups[ j ] = 0; - } - - SelectSpawnPoint( ent->client->ps.origin, origin, angles ); - TeleportPlayer( ent, origin, angles ); - break; - - case EV_USE_ITEM2: // medkit - ent->health = ent->client->ps.stats[STAT_MAX_HEALTH]; - break; - - default: - break; - } - } - -} - -/* -============== -StuckInOtherClient -============== -*/ -static int StuckInOtherClient(gentity_t *ent) { - int i; - gentity_t *ent2; - - ent2 = &g_entities[0]; - for ( i = 0; i < MAX_CLIENTS; i++, ent2++ ) { - if ( ent2 == ent ) { - continue; - } - if ( !ent2->inuse ) { - continue; - } - if ( !ent2->client ) { - continue; - } - if ( ent2->health <= 0 ) { - continue; - } - // - if (ent2->r.absmin[0] > ent->r.absmax[0]) - continue; - if (ent2->r.absmin[1] > ent->r.absmax[1]) - continue; - if (ent2->r.absmin[2] > ent->r.absmax[2]) - continue; - if (ent2->r.absmax[0] < ent->r.absmin[0]) - continue; - if (ent2->r.absmax[1] < ent->r.absmin[1]) - continue; - if (ent2->r.absmax[2] < ent->r.absmin[2]) - continue; - return qtrue; - } - return qfalse; -} - -//TA: rip bots -//void BotTestSolid(vec3_t origin); - -/* -============== -ClientThink - -This will be called once for each client frame, which will -usually be a couple times for each server frame on fast clients. - -If "g_synchronousClients 1" is set, this will be called exactly -once for each server frame, which makes for smooth demo recording. -============== -*/ -void ClientThink_real( gentity_t *ent ) { - gclient_t *client; - pmove_t pm; - int oldEventSequence; - int msec; - usercmd_t *ucmd; - float speed; - - //TA: torch - gentity_t *light; - - //TA: creep variables - gentity_t *creepNode; - vec3_t temp_v; - int i; - qboolean cSlowed = qfalse; - - //Com_Printf( "%d\n", G_LuminanceAtPoint( ent->s.origin ) ); - - client = ent->client; - - // don't think if the client is not yet connected (and thus not yet spawned in) - if (client->pers.connected != CON_CONNECTED) { - return; - } - - // mark the time, so the connection sprite can be removed - ucmd = &ent->client->pers.cmd; - - // sanity check the command time to prevent speedup cheating - if ( ucmd->serverTime > level.time + 200 ) { - ucmd->serverTime = level.time + 200; -// G_Printf("serverTime <<<<<\n" ); - } - if ( ucmd->serverTime < level.time - 1000 ) { - ucmd->serverTime = level.time - 1000; -// G_Printf("serverTime >>>>>\n" ); - } - - msec = ucmd->serverTime - client->ps.commandTime; - // following others may result in bad times, but we still want - // to check for follow toggles - if ( msec < 1 && client->sess.spectatorState != SPECTATOR_FOLLOW ) { - return; - } - if ( msec > 200 ) { - msec = 200; - } - - if ( pmove_msec.integer < 8 ) { - trap_Cvar_Set("pmove_msec", "8"); - } - else if (pmove_msec.integer > 33) { - trap_Cvar_Set("pmove_msec", "33"); - } - - if ( pmove_fixed.integer || client->pers.pmoveFixed ) { - ucmd->serverTime = ((ucmd->serverTime + pmove_msec.integer-1) / pmove_msec.integer) * pmove_msec.integer; - //if (ucmd->serverTime - client->ps.commandTime <= 0) - // return; - } - - // - // check for exiting intermission - // - if ( level.intermissiontime ) { - ClientIntermissionThink( client ); - return; - } - - // spectators don't do much - if ( client->sess.sessionTeam == TEAM_SPECTATOR ) { - if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) { - return; - } - SpectatorThink( ent, ucmd ); - return; - } - - // check for inactivity timer, but never drop the local client of a non-dedicated server - if ( !ClientInactivityTimer( client ) ) { - return; - } - - // clear the rewards if time - if ( level.time > client->rewardTime ) { - client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET ); - } - - if ( client->noclip ) { - client->ps.pm_type = PM_NOCLIP; - } else if ( client->ps.stats[STAT_HEALTH] <= 0 ) { - client->ps.pm_type = PM_DEAD; - } else { - client->ps.pm_type = PM_NORMAL; - } - - client->ps.gravity = g_gravity.value; - - // set speed - client->ps.speed = g_speed.value * client->classSpeed; - - //TA: slow player if standing in creep - for ( i = 1, creepNode = g_entities + i; i < level.num_entities; i++, creepNode++ ) - { - if( !Q_stricmp( creepNode->classname, "team_droid_creep" ) ) - { - VectorSubtract( client->ps.origin, creepNode->s.origin, temp_v ); - - if( ( VectorLength( temp_v ) <= creepNode->s.frame ) && - ( temp_v[ 2 ] <= 21 ) && //assumes mins of player is (x, x, -24) - ( client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) - { - client->ps.speed *= 0.5; - client->ps.stats[ STAT_STATE ] |= SS_CREEPSLOWED; - cSlowed = qtrue; - break; - } - } - } - - if( !cSlowed ) - client->ps.stats[ STAT_STATE ] &= ~SS_CREEPSLOWED; - - /*if ( client->ps.powerups[PW_HASTE] ) { - client->ps.speed *= 1.3; - }*/ - - // Let go of the hook if we aren't firing - if ( client->ps.weapon == WP_GRAPPLING_HOOK && - client->hook && !( ucmd->buttons & BUTTON_ATTACK ) ) { - Weapon_HookFree(client->hook); - } - - //TA: torch stuff - if( client->torch == NULL && BG_activated( UP_TORCH, client->ps.stats ) ) - { - light = G_Spawn( ); - light->s.eType = ET_TORCH; - light->r.ownerNum = ent->s.number; - light->parent = ent; - client->torch = light; - } - else if( client->torch != NULL && !BG_activated( UP_TORCH, client->ps.stats ) ) - { - G_FreeEntity( client->torch ); - trap_LinkEntity( client->torch ); - client->torch = NULL; - } - - - if( client->torch != NULL ) - ShineTorch( client->torch ); - - // set up for pmove - oldEventSequence = client->ps.eventSequence; - - memset (&pm, 0, sizeof(pm)); - - //TA: gauntlet is a NULL weapon to be given to builder classes - // check for the hit-scan gauntlet, don't let the action - // go through as an attack unless it actually hits something - /*if ( client->ps.weapon == WP_GAUNTLET && !( ucmd->buttons & BUTTON_TALK ) && - ( ucmd->buttons & BUTTON_ATTACK ) && client->ps.weaponTime <= 0 ) { - pm.gauntletHit = CheckGauntletAttack( ent ); - }*/ - pm.gauntletHit = qfalse; - - if ( ent->flags & FL_FORCE_GESTURE ) { - ent->flags &= ~FL_FORCE_GESTURE; - ent->client->pers.cmd.buttons |= BUTTON_GESTURE; - } - - pm.ps = &client->ps; - pm.cmd = *ucmd; - if ( pm.ps->pm_type == PM_DEAD ) { - pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY; - } - else if ( ent->r.svFlags & SVF_BOT ) { - pm.tracemask = MASK_PLAYERSOLID | CONTENTS_BOTCLIP; - } - else { - pm.tracemask = MASK_PLAYERSOLID; - } - pm.trace = trap_Trace; - pm.pointcontents = trap_PointContents; - pm.debugLevel = g_debugMove.integer; - pm.noFootsteps = ( g_dmflags.integer & DF_NO_FOOTSTEPS ) > 0; - - pm.pmove_fixed = pmove_fixed.integer | client->pers.pmoveFixed; - pm.pmove_msec = pmove_msec.integer; - - VectorCopy( client->ps.origin, client->oldOrigin ); - - Pmove (&pm); - - // save results of pmove - if ( ent->client->ps.eventSequence != oldEventSequence ) { - ent->eventTime = level.time; - } - if (g_smoothClients.integer) { - BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue ); - } - else { - BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue ); - } - if ( !( ent->client->ps.eFlags & EF_FIRING ) ) { - client->fireHeld = qfalse; // for grapple - } - - // use the snapped origin for linking so it matches client predicted versions - VectorCopy( ent->s.pos.trBase, ent->r.currentOrigin ); - - VectorCopy (pm.mins, ent->r.mins); - VectorCopy (pm.maxs, ent->r.maxs); - - ent->waterlevel = pm.waterlevel; - ent->watertype = pm.watertype; - - // execute client events - ClientEvents( ent, oldEventSequence ); - - // link entity now, after any personal teleporters have been used - trap_LinkEntity (ent); - if ( !ent->client->noclip ) { - G_TouchTriggers( ent ); - } - - // NOTE: now copy the exact origin over otherwise clients can be snapped into solid - VectorCopy( ent->client->ps.origin, ent->r.currentOrigin ); - - //test for solid areas in the AAS file - //TA: rip bots - //BotTestSolid(ent->r.currentOrigin); - - // touch other objects - ClientImpacts( ent, &pm ); - - // save results of triggers and client events - if (ent->client->ps.eventSequence != oldEventSequence) { - ent->eventTime = level.time; - } - - // swap and latch button actions - client->oldbuttons = client->buttons; - client->buttons = ucmd->buttons; - client->latched_buttons |= client->buttons & ~client->oldbuttons; - - // check for respawning - if ( client->ps.stats[STAT_HEALTH] <= 0 ) { - // wait for the attack button to be pressed - if ( level.time > client->respawnTime ) { - // forcerespawn is to prevent users from waiting out powerups - if ( g_forcerespawn.integer > 0 && - ( level.time - client->respawnTime ) > g_forcerespawn.integer * 1000 ) { - respawn( ent ); - return; - } - - // pressing attack or use is the normal respawn method - if ( ucmd->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) ) { - respawn( ent ); - } - } - return; - } - - // perform once-a-second actions - ClientTimerActions( ent, msec ); -} - -/* -================== -ClientThink - -A new command has arrived from the client -================== -*/ -void ClientThink( int clientNum ) { - gentity_t *ent; - - ent = g_entities + clientNum; - trap_GetUsercmd( clientNum, &ent->client->pers.cmd ); - - // mark the time we got info, so we can display the - // phone jack if they don't get any for a while - ent->client->lastCmdTime = level.time; - - if ( !(ent->r.svFlags & SVF_BOT) && !g_synchronousClients.integer ) { - ClientThink_real( ent ); - } -} - - -void G_RunClient( gentity_t *ent ) { - if ( !(ent->r.svFlags & SVF_BOT) && !g_synchronousClients.integer ) { - return; - } - ent->client->pers.cmd.serverTime = level.time; - ClientThink_real( ent ); -} - - -/* -================== -SpectatorClientEndFrame - -================== -*/ -void SpectatorClientEndFrame( gentity_t *ent ) { - gclient_t *cl; - - // if we are doing a chase cam or a remote view, grab the latest info - if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) { - int clientNum, flags; - - clientNum = ent->client->sess.spectatorClient; - - // team follow1 and team follow2 go to whatever clients are playing - if ( clientNum == -1 ) { - clientNum = level.follow1; - } else if ( clientNum == -2 ) { - clientNum = level.follow2; - } - if ( clientNum >= 0 ) { - cl = &level.clients[ clientNum ]; - if ( cl->pers.connected == CON_CONNECTED && cl->sess.sessionTeam != TEAM_SPECTATOR ) { - flags = (cl->ps.eFlags & ~(EF_VOTED | EF_TEAMVOTED)) | (ent->client->ps.eFlags & (EF_VOTED | EF_TEAMVOTED)); - ent->client->ps = cl->ps; - ent->client->ps.pm_flags |= PMF_FOLLOW; - ent->client->ps.eFlags = flags; - return; - } else { - // drop them to free spectators unless they are dedicated camera followers - if ( ent->client->sess.spectatorClient >= 0 ) { - ent->client->sess.spectatorState = SPECTATOR_FREE; - ClientBegin( ent->client - level.clients ); - } - } - } - } - - if ( ent->client->sess.spectatorState == SPECTATOR_SCOREBOARD ) { - ent->client->ps.pm_flags |= PMF_SCOREBOARD; - } else { - ent->client->ps.pm_flags &= ~PMF_SCOREBOARD; - } -} - -/* -============== -ClientEndFrame - -Called at the end of each server frame for each connected client -A fast client will have multiple ClientThink for each ClientEdFrame, -while a slow client may have multiple ClientEndFrame between ClientThink. -============== -*/ -void ClientEndFrame( gentity_t *ent ) { - int i; - clientPersistant_t *pers; - - if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) { - SpectatorClientEndFrame( ent ); - return; - } - - pers = &ent->client->pers; - - // turn off any expired powerups - for ( i = 0 ; i < MAX_POWERUPS ; i++ ) { - if ( ent->client->ps.powerups[ i ] < level.time ) { - ent->client->ps.powerups[ i ] = 0; - } - } - - // save network bandwidth -#if 0 - if ( !g_synchronousClients->integer && ent->client->ps.pm_type == PM_NORMAL ) { - // FIXME: this must change eventually for non-sync demo recording - VectorClear( ent->client->ps.viewangles ); - } -#endif - - // - // If the end of unit layout is displayed, don't give - // the player any normal movement attributes - // - if ( level.intermissiontime ) { - return; - } - - // burn from lava, etc - P_WorldEffects (ent); - - // apply all the damage taken this frame - P_DamageFeedback (ent); - - // add the EF_CONNECTION flag if we haven't gotten commands recently - if ( level.time - ent->client->lastCmdTime > 1000 ) { - ent->s.eFlags |= EF_CONNECTION; - } else { - ent->s.eFlags &= ~EF_CONNECTION; - } - - ent->client->ps.stats[STAT_HEALTH] = ent->health; // FIXME: get rid of ent->health... - - G_SetClientSound (ent); - - // set the latest infor - if (g_smoothClients.integer) { - BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue ); - } - else { - BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue ); - } - - // set the bit for the reachability area the client is currently in - // i = trap_AAS_PointReachabilityAreaIndex( ent->client->ps.origin ); - // ent->client->areabits[i >> 3] |= 1 << (i & 7); -} - - diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c deleted file mode 100644 index c8b8ab55..00000000 --- a/src/game/g_buildable.c +++ /dev/null @@ -1,627 +0,0 @@ -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "g_local.h" - - -/* -================ -nullDieFunction - -hack to prevent compilers complaining about function pointer -> NULL conversion -================ -*/ -void nullDieFunction( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) -{ -} - - -/* -================ -DSpawn_Melt - -Called when an droid spawn dies -================ -*/ -void DSpawn_Melt( gentity_t *self ) -{ - G_SelectiveRadiusDamage( self->s.pos.trBase, self->parent, 2, - self->splashRadius, self, self->splashMethodOfDeath, PTE_DROIDS ); - - if( ( self->timestamp + 10000 ) > level.time ) - { - self->nextthink = level.time + 500; - trap_LinkEntity( self ); - } - else - G_FreeEntity( self ); - - //update spawn counts - CalculateRanks( ); -} - -/* -================ -DSpawn_Die - -Called when an droid spawn dies -================ -*/ -void DSpawn_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) -{ - vec3_t dir; - - // we don't have a valid direction, so just point straight up - dir[0] = dir[1] = 0; - dir[2] = 1; - - G_SelectiveRadiusDamage( self->s.pos.trBase, self->parent, self->splashDamage, - self->splashRadius, self, self->splashMethodOfDeath, PTE_DROIDS ); - - self->s.modelindex = 0; //don't draw the model once its destroyed - G_AddEvent( self, EV_GIB_GENERIC, DirToByte( dir ) ); - self->r.contents = CONTENTS_TRIGGER; - self->timestamp = level.time; - self->die = nullDieFunction; - self->think = DSpawn_Melt; - self->nextthink = level.time + 500; //wait .5 seconds before damaging others - - trap_LinkEntity( self ); -} - - -/* -================ -DDef1_Die - -Called when an droid spawn dies -================ -*/ -void DDef1_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) -{ - vec3_t dir; - - // we don't have a valid direction, so just point straight up - dir[0] = dir[1] = 0; - dir[2] = 1; - - G_SelectiveRadiusDamage( self->s.pos.trBase, self->parent, self->splashDamage, - self->splashRadius, self, self->splashMethodOfDeath, PTE_DROIDS ); - - self->s.modelindex = 0; //don't draw the model once its destroyed - G_AddEvent( self, EV_GIB_GENERIC, DirToByte( dir ) ); - self->r.contents = CONTENTS_TRIGGER; - self->timestamp = level.time; - self->freeAfterEvent = qtrue; - self->die = nullDieFunction; -} - - -/* -================ -DSpawn_Think - -think function for Droid Spawn -================ -*/ -void DSpawn_Think( gentity_t *self ) -{ - if( self->parentNode == NULL ) - self->parentNode = createCreepNode( self->s.origin ); - - self->nextthink = level.time + 100; -} - - -/* -================ -DDef1_Think - -think function for Droid Spawn -================ -*/ -void DDef1_Think( gentity_t *self ) -{ - int i; - gentity_t *ent; - gentity_t *closestSpawn; - int distance = 0; - int minDistance = 10000; - vec3_t temp_v; - vec3_t dir = { 0, 0, 1 }; //up - - if( ( self->parentNode == NULL ) || !self->parentNode->inuse ) - { - for ( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ ) - { - if( !Q_stricmp( ent->classname, "team_droid_spawn" ) ) - { - VectorSubtract( self->s.origin, ent->s.origin, temp_v ); - distance = VectorLength( temp_v ); - if( distance < minDistance ) - { - closestSpawn = ent; - minDistance = distance; - } - } - } - - if( minDistance <= CREEP_BASESIZE ) - self->parentNode = closestSpawn; - else - { - G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE ); - return; - } - } - - G_SelectiveRadiusDamage( self->s.pos.trBase, self->parent, self->splashDamage, - self->splashRadius, self, self->splashMethodOfDeath, PTE_DROIDS ); - - self->nextthink = level.time + 100; -} - -//TA: the following defense turret code was written by -// "fuzzysteve" (fuzzysteve@quakefiles.com) and -// Anthony "inolen" Pesch (www.inolen.com) -//with modifications by me of course :) -#define HDEF1_RANGE 500 -#define HDEF1_ANGULARSPEED 15 -#define HDEF1_FIRINGSPEED 200 -#define HDEF1_ACCURACYTOLERANCE 10 -#define HDEF1_VERTICALCAP 20 - -/* -================ -hdef1_trackenemy - -Used by HDef1_Think to track enemy location -================ -*/ -qboolean hdef1_trackenemy( gentity_t *self ) -{ - vec3_t dirToTarget, angleToTarget, angularDiff; - - VectorSubtract( self->enemy->s.pos.trBase, self->s.pos.trBase, dirToTarget ); - VectorNormalize( dirToTarget ); - vectoangles( dirToTarget, angleToTarget ); - - angularDiff[ PITCH ] = AngleSubtract( self->turloc[ PITCH ], angleToTarget[ PITCH ] ); - angularDiff[ YAW ] = AngleSubtract( self->turloc[ YAW ], angleToTarget[ YAW ] ); - - if( angularDiff[ PITCH ] < -HDEF1_ACCURACYTOLERANCE ) - self->turloc[ PITCH ] += HDEF1_ANGULARSPEED; - else if( angularDiff[ PITCH ] > HDEF1_ACCURACYTOLERANCE ) - self->turloc[ PITCH ] -= HDEF1_ANGULARSPEED; - else - self->turloc[ PITCH ] = angleToTarget[ PITCH ]; - - if( self->turloc[ PITCH ] < -HDEF1_VERTICALCAP ) - self->turloc[ PITCH ] = -HDEF1_VERTICALCAP; - - if( self->turloc[ PITCH ] > HDEF1_VERTICALCAP ) - self->turloc[ PITCH ] = HDEF1_VERTICALCAP; - - if( angularDiff[ YAW ] < -HDEF1_ACCURACYTOLERANCE ) - self->turloc[ YAW ] += HDEF1_ANGULARSPEED; - else if( angularDiff[ YAW ] > HDEF1_ACCURACYTOLERANCE ) - self->turloc[ YAW ] -= HDEF1_ANGULARSPEED; - else - self->turloc[ YAW ] = angleToTarget[ YAW ]; - - VectorCopy( self->turloc, self->s.angles2 ); - - trap_LinkEntity( self ); - - if( abs( angleToTarget[ YAW ] - self->turloc[ YAW ] ) <= HDEF1_ACCURACYTOLERANCE && - abs( angleToTarget[ PITCH ] - self->turloc[ PITCH ] ) <= HDEF1_ACCURACYTOLERANCE ) - return qtrue; - - return qfalse; -} - -/* -================ -hdef1_fireonemeny - -Used by HDef1_Think to fire at enemy -================ -*/ -void hdef1_fireonenemy( gentity_t *self ) -{ - vec3_t aimVector; - - AngleVectors( self->turloc, aimVector, NULL, NULL ); - //fire_flamer( self, self->s.pos.trBase, aimVector ); - fire_plasma( self, self->s.pos.trBase, aimVector ); - G_AddEvent( self, EV_FIRE_WEAPON, 0 ); - self->count = level.time + HDEF1_FIRINGSPEED; -} - -/* -================ -hdef1_checktarget - -Used by HDef1_Think to check enemies for validity -================ -*/ -qboolean hdef1_checktarget(gentity_t *self, gentity_t *target) -{ - vec3_t distance; - trace_t trace; - - if( !target ) // Do we have a target? - return qfalse; - if( !target->inuse ) // Does the target still exist? - return qfalse; - if( target == self ) // is the target us? - return qfalse; - if( !target->client ) // is the target a bot or player? - return qfalse; - if( target->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) // is the target one of us? - return qfalse; - if( target->client->sess.sessionTeam == TEAM_SPECTATOR ) // is the target alive? - return qfalse; - if( target->health <= 0 ) // is the target still alive? - return qfalse; - - VectorSubtract( target->r.currentOrigin, self->r.currentOrigin, distance ); - if( VectorLength( distance ) > HDEF1_RANGE ) // is the target within range? - return qfalse; - - trap_Trace( &trace, self->s.pos.trBase, NULL, NULL, target->s.pos.trBase, self->s.number, MASK_SHOT ); - if ( trace.contents & CONTENTS_SOLID ) // can we see the target? - return qfalse; - - return qtrue; -} - - -/* -================ -hdef1_findenemy - -Used by HDef1_Think to locate enemy gentities -================ -*/ -void hdef1_findenemy( gentity_t *ent ) -{ - gentity_t *target; - - target = g_entities; - - for (; target < &g_entities[ level.num_entities ]; target++) - { - if( !hdef1_checktarget( ent, target ) ) - continue; - - ent->enemy = target; - return; - } - - ent->enemy = NULL; -} - - -/* -================ -HDef1_Think - -think function for Human Defense -================ -*/ -void HDef1_Think( gentity_t *self ) -{ - self->nextthink = level.time + 50; - - if( !hdef1_checktarget( self, self->enemy) ) - hdef1_findenemy( self ); - if( !self->enemy ) - return; - - if( hdef1_trackenemy( self ) && ( self->count < level.time ) ) - hdef1_fireonenemy( self ); -} - - -/* -================ -HSpawn_blast - -Called when a human spawn explodes -think function -================ -*/ -void HSpawn_Blast( gentity_t *self ) -{ - G_RadiusDamage( self->s.pos.trBase, self->parent, self->splashDamage, - self->splashRadius, self, self->splashMethodOfDeath ); - - G_FreeEntity( self ); - trap_LinkEntity( self ); - - //update spawn counts - CalculateRanks( ); -} - - -/* -================ -HSpawn_die - -Called when a human spawn dies -================ -*/ -void HSpawn_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) -{ - vec3_t dir; - - // we don't have a valid direction, so just point straight up - dir[0] = dir[1] = 0; - dir[2] = 1; - - self->s.modelindex = 0; //don't draw the model once its destroyed - G_AddEvent( self, EV_ITEM_EXPLOSION, DirToByte( dir ) ); - self->r.contents = CONTENTS_TRIGGER; - self->timestamp = level.time; - self->die = nullDieFunction; - self->think = HSpawn_Blast; - self->nextthink = level.time + 1000; //wait 1.5 seconds before damaging others - - trap_LinkEntity( self ); -} - - -/* -================ -itemFits - -Checks to see if an item fits in a specific area -================ -*/ -qboolean itemFits( gentity_t *ent, gitem_t *item, int distance ) -{ - vec3_t forward; - vec3_t angles; - vec3_t player_origin, entity_origin; - vec3_t mins, maxs; - vec3_t temp_v; - trace_t tr1, tr2; - int i; - gentity_t *creepent; - qboolean creeptest; - qboolean nearcreep = qfalse; - - VectorCopy( ent->s.apos.trBase, angles ); - angles[PITCH] = 0; // always forward - - AngleVectors( angles, forward, NULL, NULL ); - VectorCopy( ent->s.pos.trBase, player_origin ); - VectorMA( player_origin, distance, forward, entity_origin ); - - if( !Q_stricmp( item->classname, "team_droid_spawn" ) ) - { - creeptest = qfalse; - VectorSet( mins, -15, -15, -15 ); - VectorSet( maxs, 15, 15, 15 ); - } - else if( !Q_stricmp( item->classname, "team_droid_def1" ) ) - { - creeptest = qtrue; - VectorSet( mins, -15, -15, -15 ); - VectorSet( maxs, 15, 15, 15 ); - } - else if( !Q_stricmp( item->classname, "team_human_spawn" ) ) - { - creeptest = qfalse; - VectorSet( mins, -40, -40, -4 ); - VectorSet( maxs, 40, 40, 4 ); - } - else if( !Q_stricmp( item->classname, "team_human_def1" ) ) - { - creeptest = qfalse; - VectorSet( mins, -24, -24, -11 ); - VectorSet( maxs, 24, 24, 11 ); - } - else if( !Q_stricmp( item->classname, "team_human_mcu" ) ) - { - creeptest = qfalse; - VectorSet( mins, -15, -15, -15 ); - VectorSet( maxs, 15, 15, 15 ); - } - - trap_Trace( &tr1, entity_origin, mins, maxs, entity_origin, ent->s.number, MASK_PLAYERSOLID ); - trap_Trace( &tr2, player_origin, NULL, NULL, entity_origin, ent->s.number, MASK_PLAYERSOLID ); - - if( creeptest ) - { - for ( i = 1, creepent = g_entities + i; i < level.num_entities; i++, creepent++ ) - { - if( !Q_stricmp( creepent->classname, "team_droid_spawn" ) ) - { - VectorSubtract( entity_origin, creepent->s.origin, temp_v ); - if( VectorLength( temp_v ) <= CREEP_BASESIZE ) - { - nearcreep = qtrue; - break; - } - } - } - } - else - nearcreep = qtrue; - - if( tr1.fraction >= 1.0 && tr2.fraction >= 1.0 && nearcreep ) - return qtrue; - else - return qfalse; -} - - -/* -================ -Build_Item - -Spawns an item and tosses it forward -================ -*/ -gentity_t *Build_Item( gentity_t *ent, gitem_t *item, int distance ) { - vec3_t forward; - vec3_t angles; - vec3_t origin; - gentity_t *built; - - VectorCopy( ent->s.apos.trBase, angles ); - angles[PITCH] = 0; // always forward - - AngleVectors( angles, forward, NULL, NULL ); - VectorCopy( ent->s.pos.trBase, origin ); - VectorMA( origin, distance, forward, origin ); - - built = G_Spawn(); - - built->s.eType = ET_BUILDABLE; - built->s.modelindex = item - bg_itemlist; // store item number in modelindex - - built->classname = item->classname; - built->item = item; - - if( !Q_stricmp( item->classname, "team_droid_spawn" ) ) - { - VectorSet( built->r.mins, -15, -15, -15 ); - VectorSet( built->r.maxs, 15, 15, 15 ); - - built->biteam = BIT_DROIDS; - built->takedamage = qtrue; - built->health = 1000; - built->damage = 50; - built->splashDamage = 50; - built->splashRadius = 200; - built->splashMethodOfDeath = MOD_ASPAWN; - built->s.modelindex2 = BIT_DROIDS; - G_AddEvent( built, EV_ITEM_GROW, 0 ); - //built->touch = ASpawn_Touch; - built->die = DSpawn_Die; - //built->pain = ASpawn_Pain; - built->think = DSpawn_Think; - built->nextthink = level.time + 100; - } - else if( !Q_stricmp( item->classname, "team_droid_def1" ) ) - { - VectorSet( built->r.mins, -15, -15, -15 ); - VectorSet( built->r.maxs, 15, 15, 15 ); - - built->biteam = BIT_DROIDS; - built->takedamage = qtrue; - built->health = 1000; - built->damage = 50; - built->splashDamage = 20; - built->splashRadius = 50; - built->splashMethodOfDeath = MOD_ASPAWN; - built->s.modelindex2 = BIT_DROIDS; - G_AddEvent( built, EV_ITEM_GROW, 0 ); - //built->touch = ASpawn_Touch; - built->die = DDef1_Die; - //built->pain = ASpawn_Pain; - built->think = DDef1_Think; - built->nextthink = level.time + 100; - } - else if( !Q_stricmp( item->classname, "team_human_spawn" ) ) - { - VectorSet( built->r.mins, -40, -40, -4 ); - VectorSet( built->r.maxs, 40, 40, 4 ); - - built->biteam = BIT_HUMANS; - built->takedamage = qtrue; - built->health = 1000; - built->damage = 50; - built->splashDamage = 50; - built->splashRadius = 150; - built->splashMethodOfDeath = MOD_HSPAWN; - built->s.modelindex2 = BIT_HUMANS; - //built->touch = HSpawn_Touch; - //built->think = HSpawn_Think; - //built->nextthink = level.time + 1000; - built->die = HSpawn_Die; - //built->pain = HSpawn_Pain; - } - else if( !Q_stricmp( item->classname, "team_human_def1" ) ) - { - VectorSet( built->r.mins, -24, -24, -11 ); - VectorSet( built->r.maxs, 24, 24, 11 ); - - built->biteam = BIT_HUMANS; - built->takedamage = qtrue; - built->health = 1000; - built->damage = 50; - built->splashDamage = 20; - built->splashRadius = 50; - built->splashMethodOfDeath = MOD_HSPAWN; - built->s.modelindex2 = BIT_HUMANS; - //built->touch = ASpawn_Touch; - built->die = HSpawn_Die; - //built->pain = ASpawn_Pain; - built->think = HDef1_Think; - built->enemy = NULL; - built->nextthink = level.time + 50; - } - else if( !Q_stricmp( item->classname, "team_human_mcu" ) ) - { - VectorSet( built->r.mins, -15, -15, -15 ); - VectorSet( built->r.maxs, 15, 15, 15 ); - - built->biteam = BIT_HUMANS; - built->takedamage = qtrue; - built->health = 1000; - built->damage = 50; - built->splashDamage = 50; - built->splashRadius = 150; - built->splashMethodOfDeath = MOD_HSPAWN; - built->s.modelindex2 = BIT_HUMANS; - //built->touch = HSpawn_Touch; - //built->think = HSpawn_Think; - //built->nextthink = level.time + 1000; - built->die = HSpawn_Die; - //built->pain = HSpawn_Pain; - } - - built->s.number = built - g_entities; - built->r.contents = CONTENTS_BODY; - built->clipmask = MASK_PLAYERSOLID; - - G_SetOrigin( built, origin ); - VectorCopy( angles, built->s.angles ); - built->turloc[ YAW ] = built->s.angles2[ YAW ] = angles[ YAW ]; - VectorCopy( origin, built->s.origin ); - built->s.pos.trType = TR_GRAVITY; - built->s.pos.trTime = level.time; - - //update spawn counts - CalculateRanks( ); - - trap_LinkEntity (built); - - return built; -} - diff --git a/src/game/g_client.c b/src/game/g_client.c deleted file mode 100644 index af9fdee7..00000000 --- a/src/game/g_client.c +++ /dev/null @@ -1,1543 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "g_local.h" - -// g_client.c -- client functions that don't happen every frame - -static vec3_t playerMins = {-15, -15, -24}; -static vec3_t playerMaxs = {15, 15, 32}; - -/*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 32) initial -potential spawning position for deathmatch games. -The first time a player enters the game, they will be at an 'initial' spot. -Targets will be fired when someone spawns in on them. -"nobots" will prevent bots from using this spot. -"nohumans" will prevent non-bots from using this spot. -*/ -void SP_info_player_deathmatch( gentity_t *ent ) { - int i; - - G_SpawnInt( "nobots", "0", &i); - if ( i ) { - ent->flags |= FL_NO_BOTS; - } - G_SpawnInt( "nohumans", "0", &i ); - if ( i ) { - ent->flags |= FL_NO_HUMANS; - } -} - -/*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 32) -equivelant to info_player_deathmatch -*/ -void SP_info_player_start(gentity_t *ent) { - ent->classname = "info_player_deathmatch"; - SP_info_player_deathmatch( ent ); -} - -/*QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32) -The intermission will be viewed from this point. Target an info_notnull for the view direction. -*/ -void SP_info_player_intermission( gentity_t *ent ) { - -} - -/*QUAKED info_droid_intermission (1 0 1) (-16 -16 -24) (16 16 32) -The intermission will be viewed from this point. Target an info_notnull for the view direction. -*/ -void SP_info_droid_intermission( gentity_t *ent ) { - -} - -/*QUAKED info_human_intermission (1 0 1) (-16 -16 -24) (16 16 32) -The intermission will be viewed from this point. Target an info_notnull for the view direction. -*/ -void SP_info_human_intermission( gentity_t *ent ) { - -} - - - -/* -======================================================================= - - SelectSpawnPoint - -======================================================================= -*/ - -/* -================ -SpotWouldTelefrag - -================ -*/ -qboolean SpotWouldTelefrag( gentity_t *spot ) { - int i, num; - int touch[MAX_GENTITIES]; - gentity_t *hit; - vec3_t mins, maxs; - - VectorAdd( spot->s.origin, playerMins, mins ); - VectorAdd( spot->s.origin, playerMaxs, maxs ); - num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES ); - - for (i=0 ; iclient && hit->client->ps.stats[STAT_HEALTH] > 0 ) { - if( hit->client ) { - return qtrue; - } - - } - - return qfalse; -} - -/* -================ -SelectNearestDeathmatchSpawnPoint - -Find the spot that we DON'T want to use -================ -*/ -#define MAX_SPAWN_POINTS 128 -gentity_t *SelectNearestDeathmatchSpawnPoint( vec3_t from ) { - gentity_t *spot; - vec3_t delta; - float dist, nearestDist; - gentity_t *nearestSpot; - - nearestDist = 999999; - nearestSpot = NULL; - spot = NULL; - - while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) { - - VectorSubtract( spot->s.origin, from, delta ); - dist = VectorLength( delta ); - if ( dist < nearestDist ) { - nearestDist = dist; - nearestSpot = spot; - } - } - - return nearestSpot; -} - - -/* -================ -SelectRandomDeathmatchSpawnPoint - -go to a random point that doesn't telefrag -================ -*/ -#define MAX_SPAWN_POINTS 128 -gentity_t *SelectRandomDeathmatchSpawnPoint( void ) { - gentity_t *spot; - int count; - int selection; - gentity_t *spots[MAX_SPAWN_POINTS]; - - count = 0; - spot = NULL; - - while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) { - if ( SpotWouldTelefrag( spot ) ) { - continue; - } - spots[ count ] = spot; - count++; - } - - if ( !count ) { // no spots that won't telefrag - return G_Find( NULL, FOFS(classname), "info_player_deathmatch"); - } - - selection = rand() % count; - return spots[ selection ]; -} - - -/* -=========== -SelectRandomFurthestSpawnPoint - -Chooses a player start, deathmatch start, etc -============ -*/ -gentity_t *SelectRandomFurthestSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles ) { - gentity_t *spot; - vec3_t delta; - float dist; - float list_dist[64]; - gentity_t *list_spot[64]; - int numSpots, rnd, i, j; - - numSpots = 0; - spot = NULL; - - while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) { - if ( SpotWouldTelefrag( spot ) ) { - continue; - } - VectorSubtract( spot->s.origin, avoidPoint, delta ); - dist = VectorLength( delta ); - for (i = 0; i < numSpots; i++) { - if ( dist > list_dist[i] ) { - if ( numSpots >= 64 ) - numSpots = 64-1; - for (j = numSpots; j > i; j--) { - list_dist[j] = list_dist[j-1]; - list_spot[j] = list_spot[j-1]; - } - list_dist[i] = dist; - list_spot[i] = spot; - numSpots++; - if (numSpots > 64) - numSpots = 64; - break; - } - } - if (i >= numSpots && numSpots < 64) { - list_dist[numSpots] = dist; - list_spot[numSpots] = spot; - numSpots++; - } - } - if (!numSpots) { - spot = G_Find( NULL, FOFS(classname), "info_player_deathmatch"); - if (!spot) - G_Error( "Couldn't find a spawn point" ); - VectorCopy (spot->s.origin, origin); - origin[2] += 9; - VectorCopy (spot->s.angles, angles); - return spot; - } - - // select a random spot from the spawn points furthest away - rnd = random() * (numSpots / 2); - - VectorCopy (list_spot[rnd]->s.origin, origin); - origin[2] += 9; - VectorCopy (list_spot[rnd]->s.angles, angles); - - return list_spot[rnd]; -} - - -/* -================ -SelectDroidSpawnPoint - -go to a random point that doesn't telefrag -================ -*/ -gentity_t *SelectDroidSpawnPoint( void ) { - gentity_t *spot; - int count; - int selection; - gentity_t *spots[MAX_SPAWN_POINTS]; - - count = 0; - spot = NULL; - - while ((spot = G_Find (spot, FOFS(classname), "team_droid_spawn")) != NULL) { - if ( SpotWouldTelefrag( spot ) || ( spot->health <= 0 ) ) { - continue; - } - spots[ count ] = spot; - count++; - } - - if ( !count ) { // no spots that won't telefrag - spot = G_Find( NULL, FOFS(classname), "team_droid_spawn"); - if( spot->health > 0 ) - return spot; - else - return NULL; - - } - - selection = rand() % count; - return spots[ selection ]; -} - - -/* -================ -SelectHumanSpawnPoint - -go to a random point that doesn't telefrag -================ -*/ -gentity_t *SelectHumanSpawnPoint( void ) { - gentity_t *spot; - int count; - int selection; - gentity_t *spots[MAX_SPAWN_POINTS]; - - count = 0; - spot = NULL; - - while ((spot = G_Find (spot, FOFS(classname), "team_human_spawn")) != NULL) { - if ( SpotWouldTelefrag( spot ) || ( spot->health <= 0 ) ) { - continue; - } - spots[ count ] = spot; - count++; - } - - if ( !count ) { // no spots that won't telefrag - spot = G_Find( NULL, FOFS(classname), "team_human_spawn"); - if( spot->health > 0 ) - return spot; - else - return NULL; - } - - selection = rand() % count; - return spots[ selection ]; -} - - -/* -=========== -SelectSpawnPoint - -Chooses a player start, deathmatch start, etc -============ -*/ -gentity_t *SelectSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles ) { - return SelectRandomFurthestSpawnPoint( avoidPoint, origin, angles ); - - /* - gentity_t *spot; - gentity_t *nearestSpot; - - nearestSpot = SelectNearestDeathmatchSpawnPoint( avoidPoint ); - - spot = SelectRandomDeathmatchSpawnPoint ( ); - if ( spot == nearestSpot ) { - // roll again if it would be real close to point of death - spot = SelectRandomDeathmatchSpawnPoint ( ); - if ( spot == nearestSpot ) { - // last try - spot = SelectRandomDeathmatchSpawnPoint ( ); - } - } - - // find a single player start spot - if (!spot) { - G_Error( "Couldn't find a spawn point" ); - } - - VectorCopy (spot->s.origin, origin); - origin[2] += 9; - VectorCopy (spot->s.angles, angles); - - return spot; - */ -} - - -/* -=========== -SelectTremulousSpawnPoint - -Chooses a player start, deathmatch start, etc -============ -*/ -gentity_t *SelectTremulousSpawnPoint( int team, vec3_t origin, vec3_t angles ) -{ - gentity_t *spot; - - if( team == PTE_DROIDS ) - spot = SelectDroidSpawnPoint( ); - else if( team == PTE_HUMANS ) - spot = SelectHumanSpawnPoint( ); - - //no available spots - if( !spot ) - { - return NULL; - } - - // find a single player start spot - if (!spot) { - //G_Error( "Couldn't find a spawn point" ); - } - - //TA: why isn't spot->s.origin being set? - VectorCopy (spot->s.pos.trBase, origin); - VectorCopy (spot->s.angles, angles); - - if( team == PTE_DROIDS ) - origin[2] += 40; - else if( team == PTE_HUMANS ) - origin[2] += 29; - - return spot; - -} - - -/* -=========== -SelectInitialSpawnPoint - -Try to find a spawn point marked 'initial', otherwise -use normal spawn selection. -============ -*/ -gentity_t *SelectInitialSpawnPoint( vec3_t origin, vec3_t angles ) { - gentity_t *spot; - - spot = NULL; - while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) { - if ( spot->spawnflags & 1 ) { - break; - } - } - - if ( !spot || SpotWouldTelefrag( spot ) ) { - return SelectSpawnPoint( vec3_origin, origin, angles ); - } - - VectorCopy (spot->s.origin, origin); - origin[2] += 9; - VectorCopy (spot->s.angles, angles); - - return spot; -} - -/* -=========== -SelectSpectatorSpawnPoint - -============ -*/ -gentity_t *SelectSpectatorSpawnPoint( vec3_t origin, vec3_t angles ) { - FindIntermissionPoint(); - - VectorCopy( level.intermission_origin, origin ); - VectorCopy( level.intermission_angle, angles ); - - return NULL; -} - - -/* -=========== -SelectDroidLockSpawnPoint - -Try to find a spawn point for droid intermission otherwise -use normal intermission spawn. -============ -*/ -gentity_t *SelectDroidLockSpawnPoint( vec3_t origin, vec3_t angles ) { - gentity_t *spot; - - spot = NULL; - spot = G_Find (spot, FOFS(classname), "info_droid_intermission"); - - if ( !spot ) { - return SelectSpectatorSpawnPoint( origin, angles ); - } - - VectorCopy (spot->s.origin, origin); - VectorCopy (spot->s.angles, angles); - - return spot; -} - - -/* -=========== -SelectHumanLockSpawnPoint - -Try to find a spawn point for human intermission otherwise -use normal intermission spawn. -============ -*/ -gentity_t *SelectHumanLockSpawnPoint( vec3_t origin, vec3_t angles ) { - gentity_t *spot; - - spot = NULL; - spot = G_Find (spot, FOFS(classname), "info_human_intermission"); - - if ( !spot ) { - return SelectSpectatorSpawnPoint( origin, angles ); - } - - VectorCopy (spot->s.origin, origin); - VectorCopy (spot->s.angles, angles); - - return spot; -} - - -/* -======================================================================= - -BODYQUE - -======================================================================= -*/ - -#if BODY_QUEUE_SIZE -/* -=============== -InitBodyQue -=============== -*/ -void InitBodyQue (void) { - int i; - gentity_t *ent; - - level.bodyQueIndex = 0; - for (i=0; iclassname = "bodyque"; - ent->neverFree = qtrue; - level.bodyQue[i] = ent; - } -} -#endif - -/* -============= -BodySink - -After sitting around for five seconds, fall into the ground and dissapear -============= -*/ -void BodySink( gentity_t *ent ) { - if ( level.time - ent->timestamp > 6500 ) { - // the body ques are never actually freed, they are just unlinked - trap_UnlinkEntity( ent ); - ent->physicsObject = qfalse; - return; - } - ent->nextthink = level.time + 100; - ent->s.pos.trBase[2] -= 1; -} - -/* -============= -CopyToBodyQue - -A player is respawning, so make an entity that looks -just like the existing corpse to leave behind. -============= -*/ -void CopyToBodyQue( gentity_t *ent ) { - gentity_t *body; - int contents; - - //TA: not really the place for this.. but hey.. - if( ent->client->torch != NULL && BG_activated( UP_TORCH, ent->client->ps.stats ) ) - { - G_FreeEntity( ent->client->torch ); - trap_UnlinkEntity( ent->client->torch ); - ent->client->torch = NULL; - } - - trap_UnlinkEntity (ent); - - // if client is in a nodrop area, don't leave the body - contents = trap_PointContents( ent->s.origin, -1 ); - if ( contents & CONTENTS_NODROP ) { - return; - } - - body = G_Spawn( ); - body->classname = "corpse"; - body->s = ent->s; - body->r.s = body->s; - body->s.eFlags = EF_DEAD; - body->s.eType = ET_CORPSE; - body->s.number = body - g_entities; - body->timestamp = level.time; - body->physicsObject = qtrue; - body->s.event = 0; - body->r.contents = CONTENTS_BODY; - body->clipmask = MASK_PLAYERSOLID; - - switch ( body->s.legsAnim & ~ANIM_TOGGLEBIT ) { - case BOTH_DEATH1: - case BOTH_DEAD1: - body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD1; - break; - case BOTH_DEATH2: - case BOTH_DEAD2: - body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD2; - break; - case BOTH_DEATH3: - case BOTH_DEAD3: - default: - body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD3; - break; - } - - //body->die = body_die; - - // don't take more damage if already gibbed - if ( ent->health <= GIB_HEALTH ) { - body->takedamage = qfalse; - } else { - body->takedamage = qtrue; - } - - //make the make player entity disappear - ent->takedamage = qfalse; - ent->s.eType = ET_INVISIBLE; - ent->r.contents = 0; - ent->s.solid = 0; - ent->r.s.solid = 0; - body->health = ent->health = ent->client->ps.stats[STAT_HEALTH]; - ent->health = ent->client->ps.stats[STAT_HEALTH] = GIB_HEALTH - 1; - - //FIXME: change body dimensions - VectorSet( body->r.mins, -15, -15, -15 ); - VectorSet( body->r.maxs, 15, 15, 15 ); - VectorSet( body->r.absmin, -15, -15, -15 ); - VectorSet( body->r.absmax, 15, 15, 15 ); - - if ( body->s.groundEntityNum == ENTITYNUM_NONE ) - { - body->s.pos.trType = TR_GRAVITY; - body->s.pos.trTime = level.time; - VectorCopy( ent->client->ps.velocity, body->s.pos.trDelta ); - } - else - { - body->s.pos.trType = TR_STATIONARY; - } - - body->s.pos.trTime = level.time; - - VectorCopy ( body->s.pos.trBase, body->r.currentOrigin ); - trap_LinkEntity( body ); - -} - -//====================================================================== - - -/* -================== -SetClientViewAngle - -================== -*/ -void SetClientViewAngle( gentity_t *ent, vec3_t angle ) { - int i; - - // set the delta angle - for (i=0 ; i<3 ; i++) { - int cmdAngle; - - cmdAngle = ANGLE2SHORT(angle[i]); - ent->client->ps.delta_angles[i] = cmdAngle - ent->client->pers.cmd.angles[i]; - } - VectorCopy( angle, ent->s.angles ); - VectorCopy (ent->s.angles, ent->client->ps.viewangles); -} - -/* -================ -respawn -================ -*/ -void respawn( gentity_t *ent ) { - gentity_t *tent; - - CopyToBodyQue (ent); - - //TA: Clients can't respawn - they must go thru the class cmd - ClientSpawn(ent); - - //FIXME: need different spawn/respawn functions for different teams - - // add a teleportation effect - //tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_IN ); - //tent->s.clientNum = ent->s.clientNum; -} - -/* -================ -TeamCount - -Returns number of players on a team -================ -*/ -team_t TeamCount( int ignoreClientNum, int team ) { - int i; - int count = 0; - - for ( i = 0 ; i < level.maxclients ; i++ ) { - if ( i == ignoreClientNum ) { - continue; - } - if ( level.clients[i].pers.connected == CON_DISCONNECTED ) { - continue; - } - if ( level.clients[i].sess.sessionTeam == team ) { - count++; - } - } - - return count; -} - - -/* -================ -TeamLeader - -Returns the client number of the team leader -================ -*/ -int TeamLeader( int team ) { - int i; - - for ( i = 0 ; i < level.maxclients ; i++ ) { - if ( level.clients[i].pers.connected == CON_DISCONNECTED ) { - continue; - } - if ( level.clients[i].sess.sessionTeam == team ) { - if ( level.clients[i].sess.teamLeader ) - return i; - } - } - - return -1; -} - - -/* -================ -PickTeam - -================ -*/ -team_t PickTeam( int ignoreClientNum ) { - int counts[TEAM_NUM_TEAMS]; - - counts[TEAM_DROIDS] = TeamCount( ignoreClientNum, TEAM_DROIDS ); - counts[TEAM_HUMANS] = TeamCount( ignoreClientNum, TEAM_HUMANS ); - - if ( counts[TEAM_DROIDS] > counts[TEAM_HUMANS] ) { - return TEAM_HUMANS; - } - if ( counts[TEAM_HUMANS] > counts[TEAM_DROIDS] ) { - return TEAM_DROIDS; - } - // equal team count, so join the team with the lowest score - if ( level.teamScores[TEAM_DROIDS] > level.teamScores[TEAM_HUMANS] ) { - return TEAM_HUMANS; - } - return TEAM_DROIDS; -} - -/* -=========== -ForceClientSkin - -Forces a client's skin (for teamplay) -=========== -*/ -static void ForceClientSkin( gclient_t *client, char *model, const char *skin ) { - char *p; - - if ((p = Q_strrchr(model, '/')) != 0) { - *p = 0; - } - - Q_strcat(model, MAX_QPATH, "/"); - Q_strcat(model, MAX_QPATH, skin); -} - - -/* -=========== -ClientCheckName -============ -*/ -static void ClientCleanName( const char *in, char *out, int outSize ) { - int len, colorlessLen; - char ch; - char *p; - int spaces; - - //save room for trailing null byte - outSize--; - - len = 0; - colorlessLen = 0; - p = out; - *p = 0; - spaces = 0; - - while( 1 ) { - ch = *in++; - if( !ch ) { - break; - } - - // don't allow leading spaces - if( !*p && ch == ' ' ) { - continue; - } - - // check colors - if( ch == Q_COLOR_ESCAPE ) { - // solo trailing carat is not a color prefix - if( !*in ) { - break; - } - - // don't allow black in a name, period - if( ColorIndex(*in) == 0 ) { - in++; - continue; - } - - // make sure room in dest for both chars - if( len > outSize - 2 ) { - break; - } - - *out++ = ch; - *out++ = *in++; - len += 2; - continue; - } - - // don't allow too many consecutive spaces - if( ch == ' ' ) { - spaces++; - if( spaces > 3 ) { - continue; - } - } - else { - spaces = 0; - } - - if( len > outSize - 1 ) { - break; - } - - *out++ = ch; - colorlessLen++; - len++; - } - *out = 0; - - // don't allow empty names - if( *p == 0 || colorlessLen == 0 ) { - Q_strncpyz( p, "UnnamedPlayer", outSize ); - } -} - - -/* -=========== -ClientUserInfoChanged - -Called from ClientConnect when the player first connects and -directly by the server system when the player updates a userinfo variable. - -The game can override any of the settings and call trap_SetUserinfo -if desired. -============ -*/ -void ClientUserinfoChanged( int clientNum ) { - gentity_t *ent; - int teamTask, teamLeader, team, health; - char *s; - char model[MAX_QPATH]; - char oldname[MAX_STRING_CHARS]; - gclient_t *client; - char c1[MAX_INFO_STRING]; - char redTeam[MAX_INFO_STRING]; - char blueTeam[MAX_INFO_STRING]; - char userinfo[MAX_INFO_STRING]; - - ent = g_entities + clientNum; - client = ent->client; - - trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) ); - - // check for malformed or illegal info strings - if ( !Info_Validate(userinfo) ) { - strcpy (userinfo, "\\name\\badinfo"); - } - - // check for local client - s = Info_ValueForKey( userinfo, "ip" ); - if ( !strcmp( s, "localhost" ) ) { - client->pers.localClient = qtrue; - } - - // check the item prediction - s = Info_ValueForKey( userinfo, "cg_predictItems" ); - if ( !atoi( s ) ) { - client->pers.predictItemPickup = qfalse; - } else { - client->pers.predictItemPickup = qtrue; - } - - // set name - Q_strncpyz ( oldname, client->pers.netname, sizeof( oldname ) ); - s = Info_ValueForKey (userinfo, "name"); - ClientCleanName( s, client->pers.netname, sizeof(client->pers.netname) ); - - if ( client->sess.sessionTeam == TEAM_SPECTATOR ) { - if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) { - Q_strncpyz( client->pers.netname, "scoreboard", sizeof(client->pers.netname) ); - } - } - - if ( client->pers.connected == CON_CONNECTED ) { - if ( strcmp( oldname, client->pers.netname ) ) { - trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " renamed to %s\n\"", oldname, - client->pers.netname) ); - } - } - - // set max health - health = atoi( Info_ValueForKey( userinfo, "handicap" ) ); - client->pers.maxHealth = health; - if ( client->pers.maxHealth < 1 || client->pers.maxHealth > 100 ) { - client->pers.maxHealth = 100; - } - //client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth; - - // set model - //Q_strncpyz( model, Info_ValueForKey (userinfo, "model"), sizeof( model ) ); - switch( client->pers.pclass ) - { - case PCL_D_BASE: - Q_strncpyz( model, "klesk", sizeof( model ) ); - break; - case PCL_D_BUILDER: - Q_strncpyz( model, "lucy", sizeof( model ) ); - break; - case PCL_H_BASE: - Q_strncpyz( model, "sarge", sizeof( model ) ); - break; - default: - Q_strncpyz( model, "grunt", sizeof( model ) ); - } - - // team - switch( client->sess.sessionTeam ) { - case TEAM_HUMANS: - ForceClientSkin(client, model, "red"); - break; - case TEAM_DROIDS: - ForceClientSkin(client, model, "blue"); - break; - } - if ( g_gametype.integer >= GT_TEAM && client->sess.sessionTeam == TEAM_SPECTATOR ) { - // don't ever use a default skin in teamplay, it would just waste memory - ForceClientSkin(client, model, "red"); - } - - - - // teamInfo - s = Info_ValueForKey( userinfo, "teamoverlay" ); - if ( ! *s || atoi( s ) != 0 ) { - client->pers.teamInfo = qtrue; - } else { - client->pers.teamInfo = qfalse; - } - - // team task (0 = none, 1 = offence, 2 = defence) - teamTask = atoi(Info_ValueForKey(userinfo, "teamtask")); - // team Leader (1 = leader, 0 is normal player) - teamLeader = client->sess.teamLeader; - - // colors - strcpy(c1, Info_ValueForKey( userinfo, "color" )); - strcpy(redTeam, "humans"); - strcpy(blueTeam, "droids"); - - // send over a subset of the userinfo keys so other clients can - // print scoreboards, display models, and play custom sounds - if ( ent->r.svFlags & SVF_BOT ) { - s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\c1\\%s\\hc\\%i\\w\\%i\\l\\%i\\skill\\%s\\tt\\%d\\tl\\%d", - client->pers.netname, client->sess.sessionTeam, model, model, c1, - client->pers.maxHealth, client->sess.wins, client->sess.losses, - Info_ValueForKey( userinfo, "skill" ), teamTask, teamLeader ); - } else { - s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\g_redteam\\%s\\g_blueteam\\%s\\c1\\%s\\hc\\%i\\w\\%i\\l\\%i\\tt\\%d\\tl\\%d", - client->pers.netname, client->sess.sessionTeam, model, model, redTeam, blueTeam, c1, - client->pers.maxHealth, client->sess.wins, client->sess.losses, teamTask, teamLeader); - } - - trap_SetConfigstring( CS_PLAYERS+clientNum, s ); - - G_LogPrintf( "ClientUserinfoChanged: %i %s\n", clientNum, s ); -} - - -/* -=========== -ClientConnect - -Called when a player begins connecting to the server. -Called again for every map change or tournement restart. - -The session information will be valid after exit. - -Return NULL if the client should be allowed, otherwise return -a string with the reason for denial. - -Otherwise, the client will be sent the current gamestate -and will eventually get to ClientBegin. - -firstTime will be qtrue the very first time a client connects -to the server machine, but qfalse on map changes and tournement -restarts. -============ -*/ -char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot ) { - char *value; - gclient_t *client; - char userinfo[MAX_INFO_STRING]; - gentity_t *ent; - - ent = &g_entities[ clientNum ]; - - trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) ); - - // check to see if they are on the banned IP list - value = Info_ValueForKey (userinfo, "ip"); - if ( G_FilterPacket( value ) ) { - return "Banned."; - } - - // check for a password - value = Info_ValueForKey (userinfo, "password"); - if ( g_password.string[0] && Q_stricmp( g_password.string, "none" ) && - strcmp( g_password.string, value) != 0) { - return "Invalid password"; - } - - // they can connect - ent->client = level.clients + clientNum; - client = ent->client; - - memset( client, 0, sizeof(*client) ); - - client->pers.connected = CON_CONNECTING; - - // read or initialize the session data - if ( firstTime || level.newSession ) { - G_InitSessionData( client, userinfo ); - } - G_ReadSessionData( client ); - - //TA: rip bots - /*if( isBot ) { - ent->r.svFlags |= SVF_BOT; - ent->inuse = qtrue; - if( !G_BotConnect( clientNum, !firstTime ) ) { - return "BotConnectfailed"; - } - }*/ - - // get and distribute relevent paramters - G_LogPrintf( "ClientConnect: %i\n", clientNum ); - ClientUserinfoChanged( clientNum ); - - // don't do the "xxx connected" messages if they were caried over from previous level - if ( firstTime ) { - trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " connected\n\"", client->pers.netname) ); - } - - if ( g_gametype.integer >= GT_TEAM && - client->sess.sessionTeam != TEAM_SPECTATOR ) { - BroadcastTeamChange( client, -1 ); - } - - // count current clients and rank for scoreboard - CalculateRanks(); - - return NULL; -} - -/* -=========== -ClientBegin - -called when a client has finished connecting, and is ready -to be placed into the level. This will happen every level load, -and on transition between teams, but doesn't happen on respawns -============ -*/ -void ClientBegin( int clientNum ) { - gentity_t *ent; - gclient_t *client; - gentity_t *tent; - int flags; - - ent = g_entities + clientNum; - - //TA: rip bots - /*if( ent->botDelayBegin ) { - G_QueueBotBegin( clientNum ); - ent->botDelayBegin = qfalse; - return; - }*/ - - client = level.clients + clientNum; - - if ( ent->r.linked ) { - trap_UnlinkEntity( ent ); - } - G_InitGentity( ent ); - ent->touch = 0; - ent->pain = 0; - ent->client = client; - - client->pers.connected = CON_CONNECTED; - client->pers.enterTime = level.time; - client->pers.teamState.state = TEAM_BEGIN; - - // save eflags around this, because changing teams will - // cause this to happen with a valid entity, and we - // want to make sure the teleport bit is set right - // so the viewpoint doesn't interpolate through the - // world to the new position - flags = client->ps.eFlags; - memset( &client->ps, 0, sizeof( client->ps ) ); - client->ps.eFlags = flags; - - // locate ent at a spawn point - - ClientSpawn( ent ); - - if ( client->sess.sessionTeam != TEAM_SPECTATOR ) { - // send event - tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_IN ); - tent->s.clientNum = ent->s.clientNum; - - if ( g_gametype.integer != GT_TOURNAMENT ) { - trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " entered the game\n\"", client->pers.netname) ); - } - } - G_LogPrintf( "ClientBegin: %i\n", clientNum ); - - // count current clients and rank for scoreboard - CalculateRanks(); -} - -/* -=========== -ClientSpawn - -Called every time a client is placed fresh in the world: -after the first ClientBegin, and after each respawn -Initializes all non-persistant parts of playerState -============ -*/ -void ClientSpawn(gentity_t *ent) { - int index; - vec3_t spawn_origin, spawn_angles; - gclient_t *client; - int i; - clientPersistant_t saved; - clientSession_t savedSess; - int persistant[MAX_PERSISTANT]; - gentity_t *spawnPoint; - int flags; - int savedPing; - int ammoIndex, ammoSubIndex; - int teamLocal; - int accuracy_hits, accuracy_shots; - int savedEvents[MAX_PS_EVENTS]; - int eventSequence; - char userinfo[MAX_INFO_STRING]; - - index = ent - g_entities; - client = ent->client; - - teamLocal = client->pers.pteam; - - //TA: only start client if chosen a class and joined a team - if( client->pers.pclass == 0 && teamLocal == 0 ) - { - client->sess.sessionTeam = TEAM_SPECTATOR; - client->sess.spectatorState = SPECTATOR_FREE; - } - else if( client->pers.pclass == 0 ) - { - client->sess.sessionTeam = TEAM_SPECTATOR; - client->sess.spectatorState = SPECTATOR_LOCKED; - } - - // find a spawn point - // do it before setting health back up, so farthest - // ranging doesn't count this client - if ( client->sess.sessionTeam == TEAM_SPECTATOR ) - { - if( teamLocal == PTE_NONE ) - spawnPoint = SelectSpectatorSpawnPoint ( spawn_origin, spawn_angles); - else if( teamLocal == PTE_DROIDS ) - spawnPoint = SelectDroidLockSpawnPoint ( spawn_origin, spawn_angles); - else if( teamLocal == PTE_HUMANS ) - spawnPoint = SelectHumanLockSpawnPoint ( spawn_origin, spawn_angles); - } - else - { - // don't spawn near existing origin if possible - spawnPoint = SelectTremulousSpawnPoint( teamLocal, spawn_origin, spawn_angles ); - - if( spawnPoint == NULL ) - { - trap_SendServerCommand( ent-g_entities, va("print \"No suitable spawns available\n\"" ) ); - return; - } - } - client->pers.teamState.state = TEAM_ACTIVE; - - // toggle the teleport bit so the client knows to not lerp - flags = ent->client->ps.eFlags & ( EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED ); - flags ^= EF_TELEPORT_BIT; - - // clear everything but the persistant data - - saved = client->pers; - savedSess = client->sess; - savedPing = client->ps.ping; - accuracy_hits = client->accuracy_hits; - accuracy_shots = client->accuracy_shots; - for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) { - persistant[i] = client->ps.persistant[i]; - } - // also save the predictable events otherwise we might get double or dropped events - for (i = 0; i < MAX_PS_EVENTS; i++) { - savedEvents[i] = client->ps.events[i]; - } - eventSequence = client->ps.eventSequence; - memset (client, 0, sizeof(*client)); - - client->pers = saved; - client->sess = savedSess; - client->ps.ping = savedPing; - client->accuracy_hits = accuracy_hits; - client->accuracy_shots = accuracy_shots; - client->lastkilled_client = -1; - for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) { - client->ps.persistant[i] = persistant[i]; - } - for (i = 0; i < MAX_PS_EVENTS; i++) { - client->ps.events[i] = savedEvents[i]; - } - client->ps.eventSequence = eventSequence; - - if( client->sess.sessionTeam == TEAM_SPECTATOR ) - { - if( teamLocal == PTE_DROIDS ) - G_AddEvent( ent, EV_MENU, MN_DROID ); - else if( teamLocal == PTE_HUMANS ) - G_AddEvent( ent, EV_MENU, MN_HUMAN ); - } - - // increment the spawncount so the client will detect the respawn - client->ps.persistant[PERS_SPAWN_COUNT]++; - client->ps.persistant[PERS_TEAM] = client->sess.sessionTeam; - - client->airOutTime = level.time + 12000; - - trap_GetUserinfo( index, userinfo, sizeof(userinfo) ); - client->ps.eFlags = flags; - - //Com_Printf( "ent->client->pers->pclass = %i\n", ent->client->pers.pclass ); - - ent->s.groundEntityNum = ENTITYNUM_NONE; - ent->client = &level.clients[index]; - ent->takedamage = qtrue; - ent->inuse = qtrue; - ent->classname = "player"; - ent->r.contents = CONTENTS_BODY; - ent->clipmask = MASK_PLAYERSOLID; - ent->die = player_die; - ent->waterlevel = 0; - ent->watertype = 0; - ent->flags = 0; - - client->ps.stats[ STAT_WEAPONS ] = 0; - client->ps.stats[ STAT_WEAPONS2 ] = 0; - - // clear entity values - switch( ent->client->pers.pclass ) - { - case PCL_D_BUILDER: - client->pers.maxHealth = 50; - client->ps.stats[STAT_MAX_HEALTH] = 50; - client->ps.stats[STAT_ARMOR] = 50; - - client->ps.eFlags = flags; - - VectorCopy (playerMins, ent->r.mins); - VectorCopy (playerMaxs, ent->r.maxs); - - client->ps.clientNum = index; - - BG_packWeapon( WP_ABUILD, client->ps.stats ); - BG_packAmmoArray( WP_ABUILD, client->ps.ammo, client->ps.powerups, 0, 0, 0 ); - - client->ps.stats[ STAT_ABILITIES ] |= SCA_TAKESFALLDAMAGE; - BG_packAttributes( 80, 15, 350, client->ps.stats ); - client->classSpeed = 0.5; - break; - - case PCL_D_BASE: - client->pers.maxHealth = 25; - client->ps.stats[STAT_MAX_HEALTH] = 25; - client->ps.eFlags = flags; - - VectorCopy (playerMins, ent->r.mins); - VectorCopy (playerMaxs, ent->r.maxs); - - client->ps.clientNum = index; - - BG_packWeapon( WP_VENOM, client->ps.stats ); - BG_packAmmoArray( WP_VENOM, client->ps.ammo, client->ps.powerups, 0, 0, 0 ); - - client->ps.stats[ STAT_ABILITIES ] |= SCA_WALLCLIMBER; - client->ps.stats[ STAT_ABILITIES ] |= SCA_CANJUMP; - client->ps.stats[ STAT_ABILITIES ] |= SCA_NOWEAPONDRIFT; - BG_packAttributes( 140, 0, 25, client->ps.stats ); - client->classSpeed = 2.0; - break; - - case PCL_H_BASE: - client->pers.maxHealth = 100; - client->ps.stats[STAT_MAX_HEALTH] = 100; - client->ps.stats[STAT_ARMOR] = 50; - - client->ps.eFlags = flags; - - VectorCopy (playerMins, ent->r.mins); - VectorCopy (playerMaxs, ent->r.maxs); - - client->ps.clientNum = index; - - /*BG_packWeapon( WP_MACHINEGUN, client->ps.stats ); - BG_packAmmoArray( WP_MACHINEGUN, client->ps.ammo, client->ps.powerups, CS_MG, 4, 4 );*/ - - client->ps.stats[ STAT_ABILITIES ] |= SCA_TAKESFALLDAMAGE; - client->ps.stats[ STAT_ABILITIES ] |= SCA_CANJUMP; - BG_packAttributes( 90, 2, 200, client->ps.stats ); - client->classSpeed = 1.0; - break; - - //eventually remove this case (or report an error) when all classes implemented - default: - client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth; - client->ps.eFlags = flags; - - VectorCopy (playerMins, ent->r.mins); - VectorCopy (playerMaxs, ent->r.maxs); - - client->ps.clientNum = index; - - BG_packWeapon( WP_MACHINEGUN, client->ps.stats ); - BG_packAmmoArray( WP_MACHINEGUN, client->ps.ammo, client->ps.powerups, 100, 0, 0 ); - - BG_packWeapon( WP_GAUNTLET, client->ps.stats ); - BG_packAmmoArray( WP_GAUNTLET, client->ps.ammo, client->ps.powerups, 0, 0, 0 ); - - BG_packAmmoArray( WP_GRAPPLING_HOOK, client->ps.ammo, client->ps.powerups, 0, 0, 0 ); - - client->ps.stats[ STAT_ABILITIES ] |= SCA_TAKESFALLDAMAGE; - client->ps.stats[ STAT_ABILITIES ] |= SCA_CANZOOM; - client->ps.stats[ STAT_ABILITIES ] |= SCA_CANJUMP; - BG_packAttributes( 90, 2, 200, client->ps.stats ); - client->classSpeed = 1.0; - - } - - ent->client->ps.stats[ STAT_PCLASS ] = ent->client->pers.pclass; - ent->client->ps.stats[ STAT_PTEAM ] = ent->client->pers.pteam; - - - // health will count down towards max_health - ent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH]; //* 1.25; - - G_SetOrigin( ent, spawn_origin ); - VectorCopy( spawn_origin, client->ps.origin ); - - // the respawned flag will be cleared after the attack and jump keys come up - client->ps.pm_flags |= PMF_RESPAWNED; - - trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd ); - SetClientViewAngle( ent, spawn_angles ); - - if ( client->sess.sessionTeam == TEAM_SPECTATOR ) { - - } else { - G_KillBox( ent ); - trap_LinkEntity (ent); - - // force the base weapon up - client->ps.weapon = WP_NONE; - client->ps.weaponstate = WEAPON_READY; - - } - - // don't allow full run speed for a bit - client->ps.pm_flags |= PMF_TIME_KNOCKBACK; - client->ps.pm_time = 100; - - client->respawnTime = level.time; - client->inactivityTime = level.time + g_inactivity.integer * 1000; - client->latched_buttons = 0; - - // set default animations - client->ps.torsoAnim = TORSO_STAND; - client->ps.legsAnim = LEGS_IDLE; - - if ( level.intermissiontime ) { - MoveClientToIntermission( ent ); - } else { - // fire the targets of the spawn point - G_UseTargets( spawnPoint, ent ); - - // select the highest weapon number available, after any - // spawn given items have fired - client->ps.weapon = 1; - for ( i = WP_NUM_WEAPONS - 1 ; i > 0 ; i-- ) { - if ( BG_gotWeapon( i, client->ps.stats ) ) { - client->ps.weapon = i; - break; - } - } - } - - // run a client frame to drop exactly to the floor, - // initialize animations and other things - client->ps.commandTime = level.time - 100; - ent->client->pers.cmd.serverTime = level.time; - ClientThink( ent-g_entities ); - - // positively link the client, even if the command times are weird - if ( client->sess.sessionTeam != TEAM_SPECTATOR ) { - BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue ); - VectorCopy( ent->client->ps.origin, ent->r.currentOrigin ); - trap_LinkEntity( ent ); - } - - //TA: must do this here so the number of active clients is calculated - CalculateRanks(); - - // run the presend to set anything else - ClientEndFrame( ent ); - - // clear entity state values - BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue ); -} - - -/* -=========== -ClientDisconnect - -Called when a player drops from the server. -Will not be called between levels. - -This should NOT be called directly by any game logic, -call trap_DropClient(), which will call this and do -server system housekeeping. -============ -*/ -void ClientDisconnect( int clientNum ) { - gentity_t *ent; - gentity_t *tent; - int i; - - ent = g_entities + clientNum; - if ( !ent->client ) { - return; - } - - // stop any following clients - for ( i = 0 ; i < level.maxclients ; i++ ) { - if ( level.clients[i].sess.sessionTeam == TEAM_SPECTATOR - && level.clients[i].sess.spectatorState == SPECTATOR_FOLLOW - && level.clients[i].sess.spectatorClient == clientNum ) { - StopFollowing( &g_entities[i] ); - } - } - - // send effect if they were completely connected - if ( ent->client->pers.connected == CON_CONNECTED - && ent->client->sess.sessionTeam != TEAM_SPECTATOR ) { - tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_OUT ); - tent->s.clientNum = ent->s.clientNum; - - // They don't get to take powerups with them! - // Especially important for stuff like CTF flags - TossClientItems ( ent ); - } - - G_LogPrintf( "ClientDisconnect: %i\n", clientNum ); - - // if we are playing in tourney mode and losing, give a win to the other player - if ( ( g_gametype.integer == GT_TOURNAMENT ) - && !level.intermissiontime - && !level.warmupTime && level.sortedClients[1] == clientNum ) { - level.clients[ level.sortedClients[0] ].sess.wins++; - ClientUserinfoChanged( level.sortedClients[0] ); - } - - trap_UnlinkEntity (ent); - ent->s.modelindex = 0; - ent->inuse = qfalse; - ent->classname = "disconnected"; - ent->client->pers.connected = CON_DISCONNECTED; - ent->client->ps.persistant[PERS_TEAM] = TEAM_FREE; - ent->client->sess.sessionTeam = TEAM_FREE; - - trap_SetConfigstring( CS_PLAYERS + clientNum, ""); - - CalculateRanks(); - - //TA: rip bots - /*if ( ent->r.svFlags & SVF_BOT ) { - BotAIShutdownClient( clientNum ); - }*/ -} diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c deleted file mode 100644 index 3fcc088b..00000000 --- a/src/game/g_cmds.c +++ /dev/null @@ -1,2050 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* To assertain which portions are licensed under the GPL and which are - * licensed by Id Software, Inc. please run a diff between the equivalent - * versions of the "Tremulous" modification and the unmodified "Quake3" - * game source code. - */ - -#include "g_local.h" - -#include "../ta_ui/menudef.h" // for the voice chats - -/* -================== -DeathmatchScoreboardMessage - -================== -*/ -void DeathmatchScoreboardMessage( gentity_t *ent ) { - char entry[1024]; - char string[1400]; - int stringlength; - int i, j; - gclient_t *cl; - int numSorted; - int scoreFlags; - - // send the latest information on all clients - string[0] = 0; - stringlength = 0; - scoreFlags = 0; - - numSorted = level.numConnectedClients; - - for (i=0 ; i < numSorted ; i++) { - int ping; - - cl = &level.clients[level.sortedClients[i]]; - - if ( cl->pers.connected == CON_CONNECTING ) { - ping = -1; - } else { - ping = cl->ps.ping < 999 ? cl->ps.ping : 999; - } - Com_sprintf (entry, sizeof(entry), - " %i %i %i %i %i %i", level.sortedClients[i], - cl->ps.persistant[PERS_SCORE], ping, (level.time - cl->pers.enterTime)/60000, - scoreFlags, g_entities[level.sortedClients[i]].s.powerups); - j = strlen(entry); - if (stringlength + j > 1024) - break; - strcpy (string + stringlength, entry); - stringlength += j; - } - - trap_SendServerCommand( ent-g_entities, va("scores %i %i %i%s", i, - level.teamScores[TEAM_HUMANS], level.teamScores[TEAM_DROIDS], - string ) ); -} - - -/* -================== -Cmd_Score_f - -Request current scoreboard information -================== -*/ -void Cmd_Score_f( gentity_t *ent ) { - DeathmatchScoreboardMessage( ent ); -} - - - -/* -================== -CheatsOk -================== -*/ -qboolean CheatsOk( gentity_t *ent ) { - if ( !g_cheats.integer ) { - trap_SendServerCommand( ent-g_entities, va("print \"Cheats are not enabled on this server.\n\"")); - return qfalse; - } - if ( ent->health <= 0 ) { - trap_SendServerCommand( ent-g_entities, va("print \"You must be alive to use this command.\n\"")); - return qfalse; - } - return qtrue; -} - - -/* -================== -ConcatArgs -================== -*/ -char *ConcatArgs( int start ) { - int i, c, tlen; - static char line[MAX_STRING_CHARS]; - int len; - char arg[MAX_STRING_CHARS]; - - len = 0; - c = trap_Argc(); - for ( i = start ; i < c ; i++ ) { - trap_Argv( i, arg, sizeof( arg ) ); - tlen = strlen( arg ); - if ( len + tlen >= MAX_STRING_CHARS - 1 ) { - break; - } - memcpy( line + len, arg, tlen ); - len += tlen; - if ( i != c - 1 ) { - line[len] = ' '; - len++; - } - } - - line[len] = 0; - - return line; -} - -/* -================== -SanitizeString - -Remove case and control characters -================== -*/ -void SanitizeString( char *in, char *out ) { - while ( *in ) { - if ( *in == 27 ) { - in += 2; // skip color code - continue; - } - if ( *in < 32 ) { - in++; - continue; - } - *out++ = tolower( *in++ ); - } - - *out = 0; -} - -/* -================== -ClientNumberFromString - -Returns a player number for either a number or name string -Returns -1 if invalid -================== -*/ -int ClientNumberFromString( gentity_t *to, char *s ) { - gclient_t *cl; - int idnum; - char s2[MAX_STRING_CHARS]; - char n2[MAX_STRING_CHARS]; - - // numeric values are just slot numbers - if (s[0] >= '0' && s[0] <= '9') { - idnum = atoi( s ); - if ( idnum < 0 || idnum >= level.maxclients ) { - trap_SendServerCommand( to-g_entities, va("print \"Bad client slot: %i\n\"", idnum)); - return -1; - } - - cl = &level.clients[idnum]; - if ( cl->pers.connected != CON_CONNECTED ) { - trap_SendServerCommand( to-g_entities, va("print \"Client %i is not active\n\"", idnum)); - return -1; - } - return idnum; - } - - // check for a name match - SanitizeString( s, s2 ); - for ( idnum=0,cl=level.clients ; idnum < level.maxclients ; idnum++,cl++ ) { - if ( cl->pers.connected != CON_CONNECTED ) { - continue; - } - SanitizeString( cl->pers.netname, n2 ); - if ( !strcmp( n2, s2 ) ) { - return idnum; - } - } - - trap_SendServerCommand( to-g_entities, va("print \"User %s is not on the server\n\"", s)); - return -1; -} - -/* -================== -Cmd_Give_f - -Give items to a client -================== -*/ -void Cmd_Give_f (gentity_t *ent) -{ - char *name; - gitem_t *it; - int i; - qboolean give_all; - gentity_t *it_ent; - trace_t trace; - - if ( !CheatsOk( ent ) ) { - return; - } - - name = ConcatArgs( 1 ); - - if (Q_stricmp(name, "all") == 0) - give_all = qtrue; - else - give_all = qfalse; - - if (give_all || Q_stricmp( name, "health") == 0) - { - ent->health = ent->client->ps.stats[STAT_MAX_HEALTH]; - if (!give_all) - return; - } - - if (give_all || Q_stricmp(name, "weapons") == 0) - { - BG_packWeapon( (1 << WP_NUM_WEAPONS) - 1 - ( 1 << WP_GRAPPLING_HOOK ) - ( 1 << WP_NONE ), ent->client->ps.stats ); - if (!give_all) - return; - } - - if (give_all || Q_stricmp(name, "ammo") == 0) - { - for ( i = 0 ; i < MAX_WEAPONS ; i++ ) { - BG_packAmmoArray( i, ent->client->ps.ammo, ent->client->ps.powerups, 999, 0, 0 ); - } - if (!give_all) - return; - } - - if (give_all || Q_stricmp(name, "armor") == 0) - { - ent->client->ps.stats[STAT_ARMOR] = 200; - - if (!give_all) - return; - } - - // spawn a specific item right on the player - if ( !give_all ) { - it = BG_FindItem (name); - if (!it) { - return; - } - - it_ent = G_Spawn(); - VectorCopy( ent->r.currentOrigin, it_ent->s.origin ); - it_ent->classname = it->classname; - G_SpawnItem (it_ent, it); - FinishSpawningItem(it_ent ); - memset( &trace, 0, sizeof( trace ) ); - Touch_Item (it_ent, ent, &trace); - if (it_ent->inuse) { - G_FreeEntity( it_ent ); - } - } -} - - -/* -================== -Cmd_God_f - -Sets client to godmode - -argv(0) god -================== -*/ -void Cmd_God_f (gentity_t *ent) -{ - char *msg; - - if ( !CheatsOk( ent ) ) { - return; - } - - ent->flags ^= FL_GODMODE; - if (!(ent->flags & FL_GODMODE) ) - msg = "godmode OFF\n"; - else - msg = "godmode ON\n"; - - trap_SendServerCommand( ent-g_entities, va("print \"%s\"", msg)); -} - - -/* -================== -Cmd_Notarget_f - -Sets client to notarget - -argv(0) notarget -================== -*/ -void Cmd_Notarget_f( gentity_t *ent ) { - char *msg; - - if ( !CheatsOk( ent ) ) { - return; - } - - ent->flags ^= FL_NOTARGET; - if (!(ent->flags & FL_NOTARGET) ) - msg = "notarget OFF\n"; - else - msg = "notarget ON\n"; - - trap_SendServerCommand( ent-g_entities, va("print \"%s\"", msg)); -} - - -/* -================== -Cmd_Noclip_f - -argv(0) noclip -================== -*/ -void Cmd_Noclip_f( gentity_t *ent ) { - char *msg; - - if ( !CheatsOk( ent ) ) { - return; - } - - if ( ent->client->noclip ) { - msg = "noclip OFF\n"; - } else { - msg = "noclip ON\n"; - } - ent->client->noclip = !ent->client->noclip; - - trap_SendServerCommand( ent-g_entities, va("print \"%s\"", msg)); -} - - -/* -================== -Cmd_LevelShot_f - -This is just to help generate the level pictures -for the menus. It goes to the intermission immediately -and sends over a command to the client to resize the view, -hide the scoreboard, and take a special screenshot -================== -*/ -void Cmd_LevelShot_f( gentity_t *ent ) { - if ( !CheatsOk( ent ) ) { - return; - } - - // doesn't work in single player - if ( g_gametype.integer != 0 ) { - trap_SendServerCommand( ent-g_entities, - "print \"Must be in g_gametype 0 for levelshot\n\"" ); - return; - } - - BeginIntermission(); - trap_SendServerCommand( ent-g_entities, "clientLevelShot" ); -} - - -void Cmd_TeamTask_f( gentity_t *ent ) { - char userinfo[MAX_INFO_STRING]; - char arg[MAX_TOKEN_CHARS]; - int task; - int client = ent->client - level.clients; - - if ( trap_Argc() != 2 ) { - return; - } - trap_Argv( 1, arg, sizeof( arg ) ); - task = atoi( arg ); - - trap_GetUserinfo(client, userinfo, sizeof(userinfo)); - Info_SetValueForKey(userinfo, "teamtask", va("%d", task)); - trap_SetUserinfo(client, userinfo); - ClientUserinfoChanged(client); -} - - -/* -================= -Cmd_Kill_f -================= -*/ -void Cmd_Kill_f( gentity_t *ent ) { - if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) { - return; - } - if (ent->health <= 0) { - return; - } - ent->flags &= ~FL_GODMODE; - ent->client->ps.stats[STAT_HEALTH] = ent->health = 0; - player_die (ent, ent, ent, 100000, MOD_SUICIDE); -} - -/* -================= -BroadCastTeamChange - -Let everyone know about a team change -================= -*/ -void BroadcastTeamChange( gclient_t *client, int oldTeam ) -{ - if ( client->sess.sessionTeam == TEAM_HUMANS ) { - trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the humans.\n\"", - client->pers.netname) ); - } else if ( client->sess.sessionTeam == TEAM_DROIDS ) { - trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the droids.\n\"", - client->pers.netname)); - } else if ( client->sess.sessionTeam == TEAM_SPECTATOR && oldTeam != TEAM_SPECTATOR ) { - trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the spectators.\n\"", - client->pers.netname)); - } else if ( client->sess.sessionTeam == TEAM_FREE ) { - trap_SendServerCommand( -1, va("cp \"%s" S_COLOR_WHITE " joined the battle.\n\"", - client->pers.netname)); - } -} - -/* -================= -SetTeam -================= -*/ -void SetTeam( gentity_t *ent, char *s ) { - int team, oldTeam; - gclient_t *client; - int clientNum; - spectatorState_t specState; - int specClient; - - // - // see what change is requested - // - client = ent->client; - - clientNum = client - level.clients; - specClient = 0; - - specState = SPECTATOR_NOT; - if ( !Q_stricmp( s, "scoreboard" ) || !Q_stricmp( s, "score" ) ) { - team = TEAM_SPECTATOR; - specState = SPECTATOR_SCOREBOARD; - } else if ( !Q_stricmp( s, "follow1" ) ) { - team = TEAM_SPECTATOR; - specState = SPECTATOR_FOLLOW; - specClient = -1; - } else if ( !Q_stricmp( s, "follow2" ) ) { - team = TEAM_SPECTATOR; - specState = SPECTATOR_FOLLOW; - specClient = -2; - } else if ( !Q_stricmp( s, "spectator" ) || !Q_stricmp( s, "s" ) ) { - team = TEAM_SPECTATOR; - specState = SPECTATOR_FREE; - } else if ( g_gametype.integer >= GT_TEAM ) { - // if running a team game, assign player to one of the teams - specState = SPECTATOR_NOT; - if ( !Q_stricmp( s, "humans" ) || !Q_stricmp( s, "h" ) ) { - team = TEAM_HUMANS; - } else if ( !Q_stricmp( s, "droids" ) || !Q_stricmp( s, "d" ) ) { - team = TEAM_DROIDS; - } else { - // pick the team with the least number of players - team = PickTeam( clientNum ); - } - - if ( g_teamForceBalance.integer ) { - int counts[TEAM_NUM_TEAMS]; - - counts[TEAM_DROIDS] = TeamCount( ent->client->ps.clientNum, TEAM_DROIDS ); - counts[TEAM_HUMANS] = TeamCount( ent->client->ps.clientNum, TEAM_HUMANS ); - - // We allow a spread of two - if ( team == TEAM_HUMANS && counts[TEAM_HUMANS] - counts[TEAM_DROIDS] > 1 ) { - trap_SendServerCommand( ent->client->ps.clientNum, - "cp \"Humans team has too many players.\n\"" ); - return; // ignore the request - } - if ( team == TEAM_DROIDS && counts[TEAM_DROIDS] - counts[TEAM_HUMANS] > 1 ) { - trap_SendServerCommand( ent->client->ps.clientNum, - "cp \"Droids team has too many players.\n\"" ); - return; // ignore the request - } - - // It's ok, the team we are switching to has less or same number of players - } - - } else { - // force them to spectators if there aren't any spots free - team = TEAM_FREE; - } - - // override decision if limiting the players - if ( (g_gametype.integer == GT_TOURNAMENT) - && level.numNonSpectatorClients >= 2 ) { - team = TEAM_SPECTATOR; - } else if ( g_maxGameClients.integer > 0 && - level.numNonSpectatorClients >= g_maxGameClients.integer ) { - team = TEAM_SPECTATOR; - } - - // - // decide if we will allow the change - // - oldTeam = client->sess.sessionTeam; - if ( team == oldTeam && team != TEAM_SPECTATOR ) { - return; - } - - // - // execute the team change - // - - // he starts at 'base' - client->pers.teamState.state = TEAM_BEGIN; - if ( oldTeam != TEAM_SPECTATOR ) { - // Kill him (makes sure he loses flags, etc) - ent->flags &= ~FL_GODMODE; - ent->client->ps.stats[STAT_HEALTH] = ent->health = 0; - player_die (ent, ent, ent, 100000, MOD_SUICIDE); - - } - // they go to the end of the line for tournements - if ( team == TEAM_SPECTATOR ) { - client->sess.spectatorTime = level.time; - } - - client->sess.sessionTeam = team; - client->sess.spectatorState = specState; - client->sess.spectatorClient = specClient; - - BroadcastTeamChange( client, oldTeam ); - - // get and distribute relevent paramters - ClientUserinfoChanged( clientNum ); - - ClientBegin( clientNum ); -} - -/* -================= -StopFollowing - -If the client being followed leaves the game, or you just want to drop -to free floating spectator mode -================= -*/ -void StopFollowing( gentity_t *ent ) { - ent->client->ps.persistant[ PERS_TEAM ] = TEAM_SPECTATOR; - ent->client->sess.sessionTeam = TEAM_SPECTATOR; - ent->client->sess.spectatorState = SPECTATOR_FREE; - ent->client->ps.pm_flags &= ~PMF_FOLLOW; - ent->r.svFlags &= ~SVF_BOT; - ent->client->ps.clientNum = ent - g_entities; -} - -/* -================= -Cmd_Team_f -================= -*/ -void Cmd_Team_f( gentity_t *ent ) { - int oldTeam; - char s[MAX_TOKEN_CHARS]; - - //TA: rip out the q3a team system :) - - oldTeam = ent->client->pers.pteam; - - trap_Argv( 1, s, sizeof( s ) ); - - if( !strlen( s ) ) - { - trap_SendServerCommand( ent-g_entities, va("print \"team: %i\n\"", ent->client->pers.pteam ) ); - return; - } - - if(!Q_stricmp(s, "0")) - ent->client->pers.pteam = PTE_NONE; - else if(!Q_stricmp(s, "1")) - ent->client->pers.pteam = PTE_DROIDS; - else if(!Q_stricmp(s, "2")) - ent->client->pers.pteam = PTE_HUMANS; - - if( oldTeam != ent->client->pers.pteam ) - { - ent->client->pers.pclass = 0; - ClientSpawn( ent ); - } - - //FIXME: put some team change broadcast code here. -} - - -/* -================= -Cmd_Follow_f -================= -*/ -void Cmd_Follow_f( gentity_t *ent ) { - int i; - char arg[MAX_TOKEN_CHARS]; - - if ( trap_Argc() != 2 ) { - if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) { - StopFollowing( ent ); - } - return; - } - - trap_Argv( 1, arg, sizeof( arg ) ); - i = ClientNumberFromString( ent, arg ); - if ( i == -1 ) { - return; - } - - // can't follow self - if ( &level.clients[ i ] == ent->client ) { - return; - } - - // can't follow another spectator - if ( level.clients[ i ].sess.sessionTeam == TEAM_SPECTATOR ) { - return; - } - - // if they are playing a tournement game, count as a loss - if ( ( g_gametype.integer == GT_TOURNAMENT ) - && ent->client->sess.sessionTeam == TEAM_FREE ) { - ent->client->sess.losses++; - } - - // first set them to spectator - if ( ent->client->sess.sessionTeam != TEAM_SPECTATOR ) { - SetTeam( ent, "spectator" ); - } - - ent->client->sess.spectatorState = SPECTATOR_FOLLOW; - ent->client->sess.spectatorClient = i; -} - -/* -================= -Cmd_FollowCycle_f -================= -*/ -void Cmd_FollowCycle_f( gentity_t *ent, int dir ) { - int clientnum; - int original; - - // if they are playing a tournement game, count as a loss - if ( ( g_gametype.integer == GT_TOURNAMENT ) - && ent->client->sess.sessionTeam == TEAM_FREE ) { - ent->client->sess.losses++; - } - // first set them to spectator - if ( ent->client->sess.spectatorState == SPECTATOR_NOT ) { - SetTeam( ent, "spectator" ); - } - - if ( dir != 1 && dir != -1 ) { - G_Error( "Cmd_FollowCycle_f: bad dir %i", dir ); - } - - clientnum = ent->client->sess.spectatorClient; - original = clientnum; - do { - clientnum += dir; - if ( clientnum >= level.maxclients ) { - clientnum = 0; - } - if ( clientnum < 0 ) { - clientnum = level.maxclients - 1; - } - - // can only follow connected clients - if ( level.clients[ clientnum ].pers.connected != CON_CONNECTED ) { - continue; - } - - // can't follow another spectator - if ( level.clients[ clientnum ].sess.sessionTeam == TEAM_SPECTATOR ) { - continue; - } - - // this is good, we can use it - ent->client->sess.spectatorClient = clientnum; - ent->client->sess.spectatorState = SPECTATOR_FOLLOW; - return; - } while ( clientnum != original ); - - // leave it where it was -} - - -/* -================== -G_Say -================== -*/ -static void G_SayTo( gentity_t *ent, gentity_t *other, int mode, int color, const char *name, const char *message ) { - if (!other) { - return; - } - if (!other->inuse) { - return; - } - if (!other->client) { - return; - } - if ( mode == SAY_TEAM && !OnSameTeam(ent, other) ) { - return; - } - // no chatting to players in tournements - if ( ( g_gametype.integer == GT_TOURNAMENT ) - && other->client->sess.sessionTeam == TEAM_FREE - && ent->client->sess.sessionTeam != TEAM_FREE ) { - return; - } - - trap_SendServerCommand( other-g_entities, va("%s \"%s%c%c%s\"", - mode == SAY_TEAM ? "tchat" : "chat", - name, Q_COLOR_ESCAPE, color, message)); -} - -#define EC "\x19" - -void G_Say( gentity_t *ent, gentity_t *target, int mode, const char *chatText ) { - int j; - gentity_t *other; - int color; - char name[64]; - // don't let text be too long for malicious reasons - char text[MAX_SAY_TEXT]; - char location[64]; - - if ( g_gametype.integer < GT_TEAM && mode == SAY_TEAM ) { - mode = SAY_ALL; - } - - switch ( mode ) { - default: - case SAY_ALL: - G_LogPrintf( "say: %s: %s\n", ent->client->pers.netname, chatText ); - Com_sprintf (name, sizeof(name), "%s%c%c"EC": ", ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE ); - color = COLOR_GREEN; - break; - case SAY_TEAM: - G_LogPrintf( "sayteam: %s: %s\n", ent->client->pers.netname, chatText ); - if (Team_GetLocationMsg(ent, location, sizeof(location))) - Com_sprintf (name, sizeof(name), EC"(%s%c%c"EC") (%s)"EC": ", - ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE, location); - else - Com_sprintf (name, sizeof(name), EC"(%s%c%c"EC")"EC": ", - ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE ); - color = COLOR_CYAN; - break; - case SAY_TELL: - if (target && g_gametype.integer >= GT_TEAM && - target->client->sess.sessionTeam == ent->client->sess.sessionTeam && - Team_GetLocationMsg(ent, location, sizeof(location))) - Com_sprintf (name, sizeof(name), EC"[%s%c%c"EC"] (%s)"EC": ", ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE, location ); - else - Com_sprintf (name, sizeof(name), EC"[%s%c%c"EC"]"EC": ", ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE ); - color = COLOR_MAGENTA; - break; - } - - Q_strncpyz( text, chatText, sizeof(text) ); - - if ( target ) { - G_SayTo( ent, target, mode, color, name, text ); - return; - } - - // echo the text to the console - if ( g_dedicated.integer ) { - G_Printf( "%s%s\n", name, text); - } - - // send it to all the apropriate clients - for (j = 0; j < level.maxclients; j++) { - other = &g_entities[j]; - G_SayTo( ent, other, mode, color, name, text ); - } -} - - -/* -================== -Cmd_Say_f -================== -*/ -static void Cmd_Say_f( gentity_t *ent, int mode, qboolean arg0 ) { - char *p; - - if ( trap_Argc () < 2 && !arg0 ) { - return; - } - - if (arg0) - { - p = ConcatArgs( 0 ); - } - else - { - p = ConcatArgs( 1 ); - } - - G_Say( ent, NULL, mode, p ); -} - -/* -================== -Cmd_Tell_f -================== -*/ -static void Cmd_Tell_f( gentity_t *ent ) { - int targetNum; - gentity_t *target; - char *p; - char arg[MAX_TOKEN_CHARS]; - - if ( trap_Argc () < 2 ) { - return; - } - - trap_Argv( 1, arg, sizeof( arg ) ); - targetNum = atoi( arg ); - if ( targetNum < 0 || targetNum >= level.maxclients ) { - return; - } - - target = &g_entities[targetNum]; - if ( !target || !target->inuse || !target->client ) { - return; - } - - p = ConcatArgs( 2 ); - - G_LogPrintf( "tell: %s to %s: %s\n", ent->client->pers.netname, target->client->pers.netname, p ); - G_Say( ent, target, SAY_TELL, p ); - // don't tell to the player self if it was already directed to this player - // also don't send the chat back to a bot - if ( ent != target && !(ent->r.svFlags & SVF_BOT)) { - G_Say( ent, ent, SAY_TELL, p ); - } -} - - -static void G_VoiceTo( gentity_t *ent, gentity_t *other, int mode, const char *id, qboolean voiceonly ) { - int color; - char *cmd; - - if (!other) { - return; - } - if (!other->inuse) { - return; - } - if (!other->client) { - return; - } - if ( mode == SAY_TEAM && !OnSameTeam(ent, other) ) { - return; - } - // no chatting to players in tournements - if ( (g_gametype.integer == GT_TOURNAMENT )) { - return; - } - - if (mode == SAY_TEAM) { - color = COLOR_CYAN; - cmd = "vtchat"; - } - else if (mode == SAY_TELL) { - color = COLOR_MAGENTA; - cmd = "vtell"; - } - else { - color = COLOR_GREEN; - cmd = "vchat"; - } - - trap_SendServerCommand( other-g_entities, va("%s %d %d %d %s", cmd, voiceonly, ent->s.number, color, id)); -} - - -void G_Voice( gentity_t *ent, gentity_t *target, int mode, const char *id, qboolean voiceonly ) { - int j; - gentity_t *other; - - if ( g_gametype.integer < GT_TEAM && mode == SAY_TEAM ) { - mode = SAY_ALL; - } - - if ( target ) { - G_VoiceTo( ent, target, mode, id, voiceonly ); - return; - } - - // echo the text to the console - if ( g_dedicated.integer ) { - G_Printf( "voice: %s %s\n", ent->client->pers.netname, id); - } - - // send it to all the apropriate clients - for (j = 0; j < level.maxclients; j++) { - other = &g_entities[j]; - G_VoiceTo( ent, other, mode, id, voiceonly ); - } -} - - -/* -================== -Cmd_Voice_f -================== -*/ -static void Cmd_Voice_f( gentity_t *ent, int mode, qboolean arg0, qboolean voiceonly ) { - char *p; - - if ( trap_Argc () < 2 && !arg0 ) { - return; - } - - if (arg0) - { - p = ConcatArgs( 0 ); - } - else - { - p = ConcatArgs( 1 ); - } - - G_Voice( ent, NULL, mode, p, voiceonly ); -} - - -/* -================== -Cmd_VoiceTell_f -================== -*/ -static void Cmd_VoiceTell_f( gentity_t *ent, qboolean voiceonly ) { - int targetNum; - gentity_t *target; - char *id; - char arg[MAX_TOKEN_CHARS]; - - if ( trap_Argc () < 2 ) { - return; - } - - trap_Argv( 1, arg, sizeof( arg ) ); - targetNum = atoi( arg ); - if ( targetNum < 0 || targetNum >= level.maxclients ) { - return; - } - - target = &g_entities[targetNum]; - if ( !target || !target->inuse || !target->client ) { - return; - } - - id = ConcatArgs( 2 ); - - G_LogPrintf( "vtell: %s to %s: %s\n", ent->client->pers.netname, target->client->pers.netname, id ); - G_Voice( ent, target, SAY_TELL, id, voiceonly ); - // don't tell to the player self if it was already directed to this player - // also don't send the chat back to a bot - if ( ent != target && !(ent->r.svFlags & SVF_BOT)) { - G_Voice( ent, ent, SAY_TELL, id, voiceonly ); - } -} - - -/* -================== -Cmd_VoiceTaunt_f -================== -*/ -static void Cmd_VoiceTaunt_f( gentity_t *ent ) { - gentity_t *who; - int i; - - if (!ent->client) { - return; - } - - // insult someone who just killed you - if (ent->enemy && ent->enemy->client && ent->enemy->client->lastkilled_client == ent->s.number) { - // i am a dead corpse - if (!(ent->enemy->r.svFlags & SVF_BOT)) { - //G_Voice( ent, ent->enemy, SAY_TELL, VOICECHAT_DEATHINSULT, qfalse ); - } - if (!(ent->r.svFlags & SVF_BOT)) { - //G_Voice( ent, ent, SAY_TELL, VOICECHAT_DEATHINSULT, qfalse ); - } - ent->enemy = NULL; - return; - } - // insult someone you just killed - if (ent->client->lastkilled_client >= 0 && ent->client->lastkilled_client != ent->s.number) { - who = g_entities + ent->client->lastkilled_client; - if (who->client) { - // who is the person I just killed - if (who->client->lasthurt_mod == MOD_GAUNTLET) { - if (!(who->r.svFlags & SVF_BOT)) { - //G_Voice( ent, who, SAY_TELL, VOICECHAT_KILLGAUNTLET, qfalse ); // and I killed them with a gauntlet - } - if (!(ent->r.svFlags & SVF_BOT)) { - //G_Voice( ent, ent, SAY_TELL, VOICECHAT_KILLGAUNTLET, qfalse ); - } - } else { - if (!(who->r.svFlags & SVF_BOT)) { - //G_Voice( ent, who, SAY_TELL, VOICECHAT_KILLINSULT, qfalse ); // and I killed them with something else - } - if (!(ent->r.svFlags & SVF_BOT)) { - //G_Voice( ent, ent, SAY_TELL, VOICECHAT_KILLINSULT, qfalse ); - } - } - ent->client->lastkilled_client = -1; - return; - } - } - - if (g_gametype.integer >= GT_TEAM) { - // praise a team mate who just got a reward - for(i = 0; i < MAX_CLIENTS; i++) { - who = g_entities + i; - if (who->client && who != ent && who->client->sess.sessionTeam == ent->client->sess.sessionTeam) { - if (who->client->rewardTime > level.time) { - if (!(who->r.svFlags & SVF_BOT)) { - //G_Voice( ent, who, SAY_TELL, VOICECHAT_PRAISE, qfalse ); - } - if (!(ent->r.svFlags & SVF_BOT)) { - //G_Voice( ent, ent, SAY_TELL, VOICECHAT_PRAISE, qfalse ); - } - return; - } - } - } - } - - // just say something - //G_Voice( ent, NULL, SAY_ALL, VOICECHAT_TAUNT, qfalse ); -} - - -static char *gc_orders[] = { - "hold your position", - "hold this position", - "come here", - "cover me", - "guard location", - "search and destroy", - "report" -}; - -void Cmd_GameCommand_f( gentity_t *ent ) { - int player; - int order; - char str[MAX_TOKEN_CHARS]; - - trap_Argv( 1, str, sizeof( str ) ); - player = atoi( str ); - trap_Argv( 2, str, sizeof( str ) ); - order = atoi( str ); - - if ( player < 0 || player >= MAX_CLIENTS ) { - return; - } - if ( order < 0 || order > sizeof(gc_orders)/sizeof(char *) ) { - return; - } - G_Say( ent, &g_entities[player], SAY_TELL, gc_orders[order] ); - G_Say( ent, ent, SAY_TELL, gc_orders[order] ); -} - -/* -================== -Cmd_Where_f -================== -*/ -void Cmd_Where_f( gentity_t *ent ) { - trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", vtos( ent->s.origin ) ) ); -} - -static const char *gameNames[] = { - "Free For All", - "Tournament", - "Single Player", - "Team Deathmatch", - "Capture the Flag", - "One Flag CTF", - "Overload", - "Harvester" -}; - -/* -================== -Cmd_CallVote_f -================== -*/ -void Cmd_CallVote_f( gentity_t *ent ) { - int i; - char arg1[MAX_STRING_TOKENS]; - char arg2[MAX_STRING_TOKENS]; - - if ( !g_allowVote.integer ) { - trap_SendServerCommand( ent-g_entities, "print \"Voting not allowed here.\n\"" ); - return; - } - - if ( level.voteTime ) { - trap_SendServerCommand( ent-g_entities, "print \"A vote is already in progress.\n\"" ); - return; - } - if ( ent->client->pers.voteCount >= MAX_VOTE_COUNT ) { - trap_SendServerCommand( ent-g_entities, "print \"You have called the maximum number of votes.\n\"" ); - return; - } - if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) { - trap_SendServerCommand( ent-g_entities, "print \"Not allowed to call a vote as spectator.\n\"" ); - return; - } - - // make sure it is a valid command to vote on - trap_Argv( 1, arg1, sizeof( arg1 ) ); - trap_Argv( 2, arg2, sizeof( arg2 ) ); - - if( strchr( arg1, ';' ) || strchr( arg2, ';' ) ) { - trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" ); - return; - } - - if ( !Q_stricmp( arg1, "map_restart" ) ) { - } else if ( !Q_stricmp( arg1, "nextmap" ) ) { - } else if ( !Q_stricmp( arg1, "map" ) ) { - } else if ( !Q_stricmp( arg1, "g_gametype" ) ) { - } else if ( !Q_stricmp( arg1, "kick" ) ) { - } else if ( !Q_stricmp( arg1, "clientkick" ) ) { - } else if ( !Q_stricmp( arg1, "g_doWarmup" ) ) { - } else if ( !Q_stricmp( arg1, "timelimit" ) ) { - } else if ( !Q_stricmp( arg1, "fraglimit" ) ) { - } else { - trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" ); - trap_SendServerCommand( ent-g_entities, "print \"Vote commands are: map_restart, nextmap, map , g_gametype , kick , clientkick , g_doWarmup, timelimit