Created
September 12, 2025 20:40
-
-
Save kkestell/4b39df32eafdd610304d8770dd83aa41 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <ctype.h> | |
| #include <errno.h> | |
| #include <fcntl.h> | |
| #include <math.h> | |
| #include <setjmp.h> | |
| #include <stdarg.h> | |
| #include <stdbool.h> | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <sys/stat.h> | |
| #include <raylib.h> | |
| #define QUAKE_GAME // as opposed to utilities | |
| #define VERSION 1.09 | |
| #define GLQUAKE_VERSION 1.00 | |
| #define D3DQUAKE_VERSION 0.01 | |
| #define WINQUAKE_VERSION 0.996 | |
| #define LINUX_VERSION 1.30 | |
| #define X11_VERSION 1.10 | |
| #define GAMENAME "id1" | |
| #define ALIGN_PTR(p, a) (void *)(((uintptr_t)(p) + ((a) - 1)) & ~((uintptr_t)((a) - 1))) | |
| #define ALIGN_PAD_ELEMS(T,A) (((A) + sizeof(T) - 2) / sizeof(T)) | |
| #define UNALIGNED_OK 0 | |
| #define CACHE_SIZE 32 // used to align key data structures | |
| #define UNUSED(x) (x = x) // for pesky compiler / lint warnings | |
| #define MINIMUM_MEMORY 0x550000 | |
| #define MINIMUM_MEMORY_LEVELPAK (MINIMUM_MEMORY + 0x100000) | |
| #define MAX_NUM_ARGVS 50 | |
| #define PITCH 0 | |
| #define YAW 1 | |
| #define ROLL 2 | |
| #define MAX_QPATH 64 // max length of a quake game pathname | |
| #define MAX_OSPATH 128 // max length of a filesystem pathname | |
| #define ON_EPSILON 0.1 // point on plane side epsilon | |
| #define MAX_MSGLEN 8000 // max length of a reliable message | |
| #define MAX_DATAGRAM 1024 // max length of unreliable message | |
| #define MAX_EDICTS 600 // FIXME: ouch! ouch! ouch! | |
| #define MAX_LIGHTSTYLES 64 | |
| #define MAX_MODELS 256 // these are sent over the net as bytes | |
| #define MAX_SOUNDS 256 // so they cannot be blindly increased | |
| #define SAVEGAME_COMMENT_LENGTH 39 | |
| #define MAX_STYLESTRING 64 | |
| #define MAX_CL_STATS 32 | |
| #define STAT_HEALTH 0 | |
| #define STAT_FRAGS 1 | |
| #define STAT_WEAPON 2 | |
| #define STAT_AMMO 3 | |
| #define STAT_ARMOR 4 | |
| #define STAT_WEAPONFRAME 5 | |
| #define STAT_SHELLS 6 | |
| #define STAT_NAILS 7 | |
| #define STAT_ROCKETS 8 | |
| #define STAT_CELLS 9 | |
| #define STAT_ACTIVEWEAPON 10 | |
| #define STAT_TOTALSECRETS 11 | |
| #define STAT_TOTALMONSTERS 12 | |
| #define STAT_SECRETS 13 // bumped on client side by svc_foundsecret | |
| #define STAT_MONSTERS 14 // bumped by svc_killedmonster | |
| #define IT_SHOTGUN 1 | |
| #define IT_SUPER_SHOTGUN 2 | |
| #define IT_NAILGUN 4 | |
| #define IT_SUPER_NAILGUN 8 | |
| #define IT_GRENADE_LAUNCHER 16 | |
| #define IT_ROCKET_LAUNCHER 32 | |
| #define IT_LIGHTNING 64 | |
| #define IT_SUPER_LIGHTNING 128 | |
| #define IT_SHELLS 256 | |
| #define IT_NAILS 512 | |
| #define IT_ROCKETS 1024 | |
| #define IT_CELLS 2048 | |
| #define IT_AXE 4096 | |
| #define IT_ARMOR1 8192 | |
| #define IT_ARMOR2 16384 | |
| #define IT_ARMOR3 32768 | |
| #define IT_SUPERHEALTH 65536 | |
| #define IT_KEY1 131072 | |
| #define IT_KEY2 262144 | |
| #define IT_INVISIBILITY 524288 | |
| #define IT_INVULNERABILITY 1048576 | |
| #define IT_SUIT 2097152 | |
| #define IT_QUAD 4194304 | |
| #define IT_SIGIL1 (1 << 28) | |
| #define IT_SIGIL2 (1 << 29) | |
| #define IT_SIGIL3 (1 << 30) | |
| #define IT_SIGIL4 (1 << 31) | |
| #define RIT_SHELLS 128 | |
| #define RIT_NAILS 256 | |
| #define RIT_ROCKETS 512 | |
| #define RIT_CELLS 1024 | |
| #define RIT_AXE 2048 | |
| #define RIT_LAVA_NAILGUN 4096 | |
| #define RIT_LAVA_SUPER_NAILGUN 8192 | |
| #define RIT_MULTI_GRENADE 16384 | |
| #define RIT_MULTI_ROCKET 32768 | |
| #define RIT_PLASMA_GUN 65536 | |
| #define RIT_ARMOR1 8388608 | |
| #define RIT_ARMOR2 16777216 | |
| #define RIT_ARMOR3 33554432 | |
| #define RIT_LAVA_NAILS 67108864 | |
| #define RIT_PLASMA_AMMO 134217728 | |
| #define RIT_MULTI_ROCKETS 268435456 | |
| #define RIT_SHIELD 536870912 | |
| #define RIT_ANTIGRAV 1073741824 | |
| #define RIT_SUPERHEALTH 2147483648 | |
| #define HIT_PROXIMITY_GUN_BIT 16 | |
| #define HIT_MJOLNIR_BIT 7 | |
| #define HIT_LASER_CANNON_BIT 23 | |
| #define HIT_PROXIMITY_GUN (1 << HIT_PROXIMITY_GUN_BIT) | |
| #define HIT_MJOLNIR (1 << HIT_MJOLNIR_BIT) | |
| #define HIT_LASER_CANNON (1 << HIT_LASER_CANNON_BIT) | |
| #define HIT_WETSUIT (1 << (23 + 2)) | |
| #define HIT_EMPATHY_SHIELDS (1 << (23 + 3)) | |
| #define MAX_SCOREBOARD 16 | |
| #define MAX_SCOREBOARDNAME 32 | |
| #define SOUND_CHANNELS 8 | |
| #define STRUCT_FROM_LINK(l, t, m) ((t *)((uint8_t *)l - (int32_t) & (((t *)0)->m))) | |
| #define Q_MAXCHAR ((char)0x7f) | |
| #define Q_MAXSHORT ((int16_t)0x7fff) | |
| #define Q_MAXINT ((int32_t)0x7fffffff) | |
| #define Q_MAXLONG ((int32_t)0x7fffffff) | |
| #define Q_MAXFLOAT ((int32_t)0x7fffffff) | |
| #define Q_MINCHAR ((char)0x80) | |
| #define Q_MINSHORT ((int16_t)0x8000) | |
| #define Q_MININT ((int32_t)0x80000000) | |
| #define Q_MINLONG ((int32_t)0x80000000) | |
| #define Q_MINFLOAT ((int32_t)0x7fffffff) | |
| #define MAX_MAP_HULLS 4 | |
| #define MAX_MAP_MODELS 256 | |
| #define MAX_MAP_BRUSHES 4096 | |
| #define MAX_MAP_ENTITIES 1024 | |
| #define MAX_MAP_ENTSTRING 65536 | |
| #define MAX_MAP_PLANES 32767 | |
| #define MAX_MAP_NODES 32767 // because negative shorts are contents | |
| #define MAX_MAP_CLIPNODES 32767 // | |
| #define MAX_MAP_LEAFS 8192 | |
| #define MAX_MAP_VERTS 65535 | |
| #define MAX_MAP_FACES 65535 | |
| #define MAX_MAP_MARKSURFACES 65535 | |
| #define MAX_MAP_TEXINFO 4096 | |
| #define MAX_MAP_EDGES 256000 | |
| #define MAX_MAP_SURFEDGES 512000 | |
| #define MAX_MAP_TEXTURES 512 | |
| #define MAX_MAP_MIPTEX 0x200000 | |
| #define MAX_MAP_LIGHTING 0x100000 | |
| #define MAX_MAP_VISIBILITY 0x100000 | |
| #define MAX_MAP_PORTALS 65536 | |
| #define MAX_KEY 32 | |
| #define MAX_VALUE 1024 | |
| #define BSPVERSION 29 | |
| #define TOOLVERSION 2 | |
| #define LUMP_ENTITIES 0 | |
| #define LUMP_PLANES 1 | |
| #define LUMP_TEXTURES 2 | |
| #define LUMP_VERTEXES 3 | |
| #define LUMP_VISIBILITY 4 | |
| #define LUMP_NODES 5 | |
| #define LUMP_TEXINFO 6 | |
| #define LUMP_FACES 7 | |
| #define LUMP_LIGHTING 8 | |
| #define LUMP_CLIPNODES 9 | |
| #define LUMP_LEAFS 10 | |
| #define LUMP_MARKSURFACES 11 | |
| #define LUMP_EDGES 12 | |
| #define LUMP_SURFEDGES 13 | |
| #define LUMP_MODELS 14 | |
| #define HEADER_LUMPS 15 | |
| #define MIPLEVELS 4 | |
| #define PLANE_X 0 | |
| #define PLANE_Y 1 | |
| #define PLANE_Z 2 | |
| #define PLANE_ANYX 3 | |
| #define PLANE_ANYY 4 | |
| #define PLANE_ANYZ 5 | |
| #define CONTENTS_EMPTY -1 | |
| #define CONTENTS_SOLID -2 | |
| #define CONTENTS_WATER -3 | |
| #define CONTENTS_SLIME -4 | |
| #define CONTENTS_LAVA -5 | |
| #define CONTENTS_SKY -6 | |
| #define CONTENTS_ORIGIN -7 // removed at csg time | |
| #define CONTENTS_CLIP -8 // changed to contents_solid | |
| #define CONTENTS_CURRENT_0 -9 | |
| #define CONTENTS_CURRENT_90 -10 | |
| #define CONTENTS_CURRENT_180 -11 | |
| #define CONTENTS_CURRENT_270 -12 | |
| #define CONTENTS_CURRENT_UP -13 | |
| #define CONTENTS_CURRENT_DOWN -14 | |
| #define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision | |
| #define MAXLIGHTMAPS 4 | |
| #define AMBIENT_WATER 0 | |
| #define AMBIENT_SKY 1 | |
| #define AMBIENT_SLIME 2 | |
| #define AMBIENT_LAVA 3 | |
| #define NUM_AMBIENTS 4 // automatic ambient sounds | |
| #define VID_CBITS 6 | |
| #define VID_GRADES (1 << VID_CBITS) | |
| #define IS_NAN(x) (((*(int32_t *)&x) & nanmask) == nanmask) | |
| #define DotProduct(x, y) (x[0] * y[0] + x[1] * y[1] + x[2] * y[2]) | |
| #define VectorSubtract(a, b, c) \ | |
| { \ | |
| c[0] = a[0] - b[0]; \ | |
| c[1] = a[1] - b[1]; \ | |
| c[2] = a[2] - b[2]; \ | |
| } | |
| #define VectorAdd(a, b, c) \ | |
| { \ | |
| c[0] = a[0] + b[0]; \ | |
| c[1] = a[1] + b[1]; \ | |
| c[2] = a[2] + b[2]; \ | |
| } | |
| #define VectorCopy(a, b) \ | |
| { \ | |
| b[0] = a[0]; \ | |
| b[1] = a[1]; \ | |
| b[2] = a[2]; \ | |
| } | |
| #define BOX_ON_PLANE_SIDE(emins, emaxs, p) \ | |
| (((p)->type < 3) ? (((p)->dist <= (emins)[(p)->type]) ? 1 : (((p)->dist >= (emaxs)[(p)->type]) ? 2 : 3)) \ | |
| : BoxOnPlaneSide((emins), (emaxs), (p))) | |
| #define CMP_NONE 0 | |
| #define CMP_LZSS 1 | |
| #define TYP_NONE 0 | |
| #define TYP_LABEL 1 | |
| #define TYP_LUMPY 64 // 64 + grab command number | |
| #define TYP_PALETTE 64 | |
| #define TYP_QTEX 65 | |
| #define TYP_QPIC 66 | |
| #define TYP_SOUND 67 | |
| #define TYP_MIPTEX 68 | |
| #define NET_NAMELEN 64 | |
| #define NET_MAXMESSAGE 8192 | |
| #define NET_HEADERSIZE (2 * sizeof(uint32_t)) | |
| #define NET_DATAGRAMSIZE (MAX_DATAGRAM + NET_HEADERSIZE) | |
| #define NETFLAG_LENGTH_MASK 0x0000ffff | |
| #define NETFLAG_DATA 0x00010000 | |
| #define NETFLAG_ACK 0x00020000 | |
| #define NETFLAG_NAK 0x00040000 | |
| #define NETFLAG_EOM 0x00080000 | |
| #define NETFLAG_UNRELIABLE 0x00100000 | |
| #define NETFLAG_CTL 0x80000000 | |
| #define NET_PROTOCOL_VERSION 3 | |
| #define CCREQ_CONNECT 0x01 | |
| #define CCREQ_SERVER_INFO 0x02 | |
| #define CCREQ_PLAYER_INFO 0x03 | |
| #define CCREQ_RULE_INFO 0x04 | |
| #define CCREP_ACCEPT 0x81 | |
| #define CCREP_REJECT 0x82 | |
| #define CCREP_SERVER_INFO 0x83 | |
| #define CCREP_PLAYER_INFO 0x84 | |
| #define CCREP_RULE_INFO 0x85 | |
| #define MAX_NET_DRIVERS 8 | |
| #define HOSTCACHESIZE 8 | |
| #define PROTOCOL_VERSION 15 | |
| #define U_MOREBITS (1 << 0) | |
| #define U_ORIGIN1 (1 << 1) | |
| #define U_ORIGIN2 (1 << 2) | |
| #define U_ORIGIN3 (1 << 3) | |
| #define U_ANGLE2 (1 << 4) | |
| #define U_NOLERP (1 << 5) // don't interpolate movement | |
| #define U_FRAME (1 << 6) | |
| #define U_SIGNAL (1 << 7) // just differentiates from other updates | |
| #define U_ANGLE1 (1 << 8) | |
| #define U_ANGLE3 (1 << 9) | |
| #define U_MODEL (1 << 10) | |
| #define U_COLORMAP (1 << 11) | |
| #define U_SKIN (1 << 12) | |
| #define U_EFFECTS (1 << 13) | |
| #define U_LONGENTITY (1 << 14) | |
| #define SU_VIEWHEIGHT (1 << 0) | |
| #define SU_IDEALPITCH (1 << 1) | |
| #define SU_PUNCH1 (1 << 2) | |
| #define SU_PUNCH2 (1 << 3) | |
| #define SU_PUNCH3 (1 << 4) | |
| #define SU_VELOCITY1 (1 << 5) | |
| #define SU_VELOCITY2 (1 << 6) | |
| #define SU_VELOCITY3 (1 << 7) | |
| #define SU_ITEMS (1 << 9) | |
| #define SU_ONGROUND (1 << 10) // no data follows, the bit is it | |
| #define SU_INWATER (1 << 11) // no data follows, the bit is it | |
| #define SU_WEAPONFRAME (1 << 12) | |
| #define SU_ARMOR (1 << 13) | |
| #define SU_WEAPON (1 << 14) | |
| #define SND_VOLUME (1 << 0) // a byte | |
| #define SND_ATTENUATION (1 << 1) // a byte | |
| #define SND_LOOPING (1 << 2) // a long | |
| #define DEFAULT_VIEWHEIGHT 22 | |
| #define GAME_COOP 0 | |
| #define GAME_DEATHMATCH 1 | |
| #define svc_bad 0 | |
| #define svc_nop 1 | |
| #define svc_disconnect 2 | |
| #define svc_updatestat 3 // [byte] [long] | |
| #define svc_version 4 // [long] server version | |
| #define svc_setview 5 // [short] entity number | |
| #define svc_sound 6 // <see code> | |
| #define svc_time 7 // [float] server time | |
| #define svc_print 8 // [string] null terminated string | |
| #define svc_stufftext \ | |
| 9 // [string] stuffed into client's console buffer | |
| #define svc_setangle 10 // [angle3] set the view angle to this absolute value | |
| #define svc_serverinfo \ | |
| 11 // [long] version | |
| #define svc_lightstyle 12 // [byte] [string] | |
| #define svc_updatename 13 // [byte] [string] | |
| #define svc_updatefrags 14 // [byte] [short] | |
| #define svc_clientdata 15 // <shortbits + data> | |
| #define svc_stopsound 16 // <see code> | |
| #define svc_updatecolors 17 // [byte] [byte] | |
| #define svc_particle 18 // [vec3] <variable> | |
| #define svc_damage 19 | |
| #define svc_spawnstatic 20 | |
| #define svc_spawnbaseline 22 | |
| #define svc_temp_entity 23 | |
| #define svc_setpause 24 // [byte] on / off | |
| #define svc_signonnum 25 // [byte] used for the signon sequence | |
| #define svc_centerprint 26 // [string] to put in center of the screen | |
| #define svc_killedmonster 27 | |
| #define svc_foundsecret 28 | |
| #define svc_spawnstaticsound 29 // [coord3] [byte] samp [byte] vol [byte] aten | |
| #define svc_intermission 30 // [string] music | |
| #define svc_finale 31 // [string] music [string] text | |
| #define svc_cdtrack 32 // [byte] track [byte] looptrack | |
| #define svc_sellscreen 33 | |
| #define svc_cutscene 34 | |
| #define clc_bad 0 | |
| #define clc_nop 1 | |
| #define clc_disconnect 2 | |
| #define clc_move 3 // [usercmd_t] | |
| #define clc_stringcmd 4 // [string] message | |
| #define TE_SPIKE 0 | |
| #define TE_SUPERSPIKE 1 | |
| #define TE_GUNSHOT 2 | |
| #define TE_EXPLOSION 3 | |
| #define TE_TAREXPLOSION 4 | |
| #define TE_LIGHTNING1 5 | |
| #define TE_LIGHTNING2 6 | |
| #define TE_WIZSPIKE 7 | |
| #define TE_KNIGHTSPIKE 8 | |
| #define TE_LIGHTNING3 9 | |
| #define TE_LAVASPLASH 10 | |
| #define TE_TELEPORT 11 | |
| #define TE_EXPLOSION2 12 | |
| #define TE_BEAM 13 | |
| #define SBAR_HEIGHT 24 | |
| #define __SOUND__ | |
| #define DEFAULT_SOUND_PACKET_VOLUME 255 | |
| #define DEFAULT_SOUND_PACKET_ATTENUATION 1.0 | |
| #define MAX_CHANNELS 128 | |
| #define MAX_DYNAMIC_CHANNELS 8 | |
| #define MAXCLIPPLANES 11 | |
| #define TOP_RANGE 16 // soldier uniform colors | |
| #define BOTTOM_RANGE 96 | |
| #define CSHIFT_CONTENTS 0 | |
| #define CSHIFT_DAMAGE 1 | |
| #define CSHIFT_BONUS 2 | |
| #define CSHIFT_POWERUP 3 | |
| #define NUM_CSHIFTS 4 | |
| #define NAME_LENGTH 64 | |
| #define SIGNONS 4 // signon messages to receive before connected | |
| #define MAX_DLIGHTS 32 | |
| #define MAX_BEAMS 24 | |
| #define MAX_EFRAGS 640 | |
| #define MAX_MAPSTRING 2048 | |
| #define MAX_DEMOS 8 | |
| #define MAX_DEMONAME 16 | |
| #define MAX_TEMP_ENTITIES 64 // lightning bolts, etc | |
| #define MAX_STATIC_ENTITIES 128 // torches, etc | |
| #define MAX_VISEDICTS 256 | |
| #define OFS_NULL 0 | |
| #define OFS_RETURN 1 | |
| #define OFS_PARM0 4 // leave 3 ofs for each parm to hold vectors | |
| #define OFS_PARM1 7 | |
| #define OFS_PARM2 10 | |
| #define OFS_PARM3 13 | |
| #define OFS_PARM4 16 | |
| #define OFS_PARM5 19 | |
| #define OFS_PARM6 22 | |
| #define OFS_PARM7 25 | |
| #define RESERVED_OFS 28 | |
| #define DEF_SAVEGLOBAL (1 << 15) | |
| #define MAX_PARMS 8 | |
| #define PROG_VERSION 6 | |
| #define PROGHEADER_CRC 5927 | |
| #define MAX_ENT_LEAFS 16 | |
| #define EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l, edict_t, area) | |
| #define NEXT_EDICT(e) ((edict_t *)((uint8_t *)e + pr_edict_size)) | |
| #define EDICT_TO_PROG(e) ((uint8_t *)e - (uint8_t *)sv.edicts) | |
| #define PROG_TO_EDICT(e) ((edict_t *)((uint8_t *)sv.edicts + e)) | |
| #define G_FLOAT(o) (pr_globals[o]) | |
| #define G_INT(o) (*(int32_t *)&pr_globals[o]) | |
| #define G_EDICT(o) ((edict_t *)((uint8_t *)sv.edicts + *(int32_t *)&pr_globals[o])) | |
| #define G_EDICTNUM(o) NUM_FOR_EDICT(G_EDICT(o)) | |
| #define G_VECTOR(o) (&pr_globals[o]) | |
| #define G_STRING(o) (pr_strings + *(string_t *)&pr_globals[o]) | |
| #define G_FUNCTION(o) (*(func_t *)&pr_globals[o]) | |
| #define E_FLOAT(e, o) (((float *)&e->v)[o]) | |
| #define E_INT(e, o) (*(int32_t *)&((float *)&e->v)[o]) | |
| #define E_VECTOR(e, o) (&((float *)&e->v)[o]) | |
| #define E_STRING(e, o) (pr_strings + *(string_t *)&((float *)&e->v)[o]) | |
| #define NUM_PING_TIMES 16 | |
| #define NUM_SPAWN_PARMS 16 | |
| #define MOVETYPE_NONE 0 // never moves | |
| #define MOVETYPE_ANGLENOCLIP 1 | |
| #define MOVETYPE_ANGLECLIP 2 | |
| #define MOVETYPE_WALK 3 // gravity | |
| #define MOVETYPE_STEP 4 // gravity, special edge handling | |
| #define MOVETYPE_FLY 5 | |
| #define MOVETYPE_TOSS 6 // gravity | |
| #define MOVETYPE_PUSH 7 // no clip to world, push and crush | |
| #define MOVETYPE_NOCLIP 8 | |
| #define MOVETYPE_FLYMISSILE 9 // extra size to monsters | |
| #define MOVETYPE_BOUNCE 10 | |
| #define MOVETYPE_BOUNCEMISSILE 11 // bounce w/o gravity | |
| #define MOVETYPE_FOLLOW 12 // track movement of aiment | |
| #define SOLID_NOT 0 // no interaction with other objects | |
| #define SOLID_TRIGGER 1 // touch on edge, but not blocking | |
| #define SOLID_BBOX 2 // touch on edge, block | |
| #define SOLID_SLIDEBOX 3 // touch on edge, but not an onground | |
| #define SOLID_BSP 4 // bsp clip, touch on edge, block | |
| #define DEAD_NO 0 | |
| #define DEAD_DYING 1 | |
| #define DEAD_DEAD 2 | |
| #define DAMAGE_NO 0 | |
| #define DAMAGE_YES 1 | |
| #define DAMAGE_AIM 2 | |
| #define FL_FLY 1 | |
| #define FL_SWIM 2 | |
| #define FL_CONVEYOR 4 | |
| #define FL_CLIENT 8 | |
| #define FL_INWATER 16 | |
| #define FL_MONSTER 32 | |
| #define FL_GODMODE 64 | |
| #define FL_NOTARGET 128 | |
| #define FL_ITEM 256 | |
| #define FL_ONGROUND 512 | |
| #define FL_PARTIALGROUND 1024 // not all corners are valid | |
| #define FL_WATERJUMP 2048 // player jumping out of water | |
| #define FL_JUMPRELEASED 4096 // for jump debouncing | |
| #define EF_BRIGHTFIELD 1 | |
| #define EF_MUZZLEFLASH 2 | |
| #define EF_BRIGHTLIGHT 4 | |
| #define EF_DIMLIGHT 8 | |
| #define SPAWNFLAG_NOT_EASY 256 | |
| #define SPAWNFLAG_NOT_MEDIUM 512 | |
| #define SPAWNFLAG_NOT_HARD 1024 | |
| #define SPAWNFLAG_NOT_DEATHMATCH 2048 | |
| #define __MODEL__ | |
| #define ALIAS_VERSION 6 | |
| #define ALIAS_ONSEAM 0x0020 | |
| #define SYNCTYPE_T | |
| #define DT_FACES_FRONT 0x0010 | |
| #define IDPOLYHEADER (('O' << 24) + ('P' << 16) + ('D' << 8) + 'I') | |
| #define SPRITE_VERSION 1 | |
| #define SPR_VP_PARALLEL_UPRIGHT 0 | |
| #define SPR_FACING_UPRIGHT 1 | |
| #define SPR_VP_PARALLEL 2 | |
| #define SPR_ORIENTED 3 | |
| #define SPR_VP_PARALLEL_ORIENTED 4 | |
| #define IDSPRITEHEADER (('P' << 24) + ('S' << 16) + ('D' << 8) + 'I') | |
| #define SIDE_FRONT 0 | |
| #define SIDE_BACK 1 | |
| #define SIDE_ON 2 | |
| #define SURF_PLANEBACK 2 | |
| #define SURF_DRAWSKY 4 | |
| #define SURF_DRAWSPRITE 8 | |
| #define SURF_DRAWTURB 0x10 | |
| #define SURF_DRAWTILED 0x20 | |
| #define SURF_DRAWBACKGROUND 0x40 | |
| #define EF_ROCKET 1 // leave a trail | |
| #define EF_GRENADE 2 // leave a trail | |
| #define EF_GIB 4 // leave a trail | |
| #define EF_ROTATE 8 // rotate (bonus items) | |
| #define EF_TRACER 16 // green split trail | |
| #define EF_ZOMGIB 32 // small blood trail | |
| #define EF_TRACER2 64 // orange split trail + rotate | |
| #define EF_TRACER3 128 // purple trail | |
| #define WARP_WIDTH 320 | |
| #define WARP_HEIGHT 200 | |
| #define MAX_LBM_HEIGHT 480 | |
| #define PARTICLE_Z_CLIP 8.0 | |
| #define DR_SOLID 0 | |
| #define DR_TRANSPARENT 1 | |
| #define TRANSPARENT_COLOR 0xFF | |
| #define TURB_TEX_SIZE 64 // base turbulent texture size | |
| #define CYCLE 128 // turbulent cycle size | |
| #define TILE_SIZE 128 // size of textures generated by R_GenTiledSurf | |
| #define SKYSHIFT 7 | |
| #define SKYSIZE (1 << SKYSHIFT) | |
| #define SKYMASK (SKYSIZE - 1) | |
| #define MOVE_NORMAL 0 | |
| #define MOVE_NOMONSTERS 1 | |
| #define MOVE_MISSILE 2 | |
| #define K_TAB 9 | |
| #define K_ENTER 13 | |
| #define K_ESCAPE 27 | |
| #define K_SPACE 32 | |
| #define K_BACKSPACE 127 | |
| #define K_UPARROW 128 | |
| #define K_DOWNARROW 129 | |
| #define K_LEFTARROW 130 | |
| #define K_RIGHTARROW 131 | |
| #define K_ALT 132 | |
| #define K_CTRL 133 | |
| #define K_SHIFT 134 | |
| #define K_F1 135 | |
| #define K_F2 136 | |
| #define K_F3 137 | |
| #define K_F4 138 | |
| #define K_F5 139 | |
| #define K_F6 140 | |
| #define K_F7 141 | |
| #define K_F8 142 | |
| #define K_F9 143 | |
| #define K_F10 144 | |
| #define K_F11 145 | |
| #define K_F12 146 | |
| #define K_INS 147 | |
| #define K_DEL 148 | |
| #define K_PGDN 149 | |
| #define K_PGUP 150 | |
| #define K_HOME 151 | |
| #define K_END 152 | |
| #define K_PAUSE 255 | |
| #define K_MOUSE1 200 | |
| #define K_MOUSE2 201 | |
| #define K_MOUSE3 202 | |
| #define K_JOY1 203 | |
| #define K_JOY2 204 | |
| #define K_JOY3 205 | |
| #define K_JOY4 206 | |
| #define K_AUX1 207 | |
| #define K_AUX2 208 | |
| #define K_AUX3 209 | |
| #define K_AUX4 210 | |
| #define K_AUX5 211 | |
| #define K_AUX6 212 | |
| #define K_AUX7 213 | |
| #define K_AUX8 214 | |
| #define K_AUX9 215 | |
| #define K_AUX10 216 | |
| #define K_AUX11 217 | |
| #define K_AUX12 218 | |
| #define K_AUX13 219 | |
| #define K_AUX14 220 | |
| #define K_AUX15 221 | |
| #define K_AUX16 222 | |
| #define K_AUX17 223 | |
| #define K_AUX18 224 | |
| #define K_AUX19 225 | |
| #define K_AUX20 226 | |
| #define K_AUX21 227 | |
| #define K_AUX22 228 | |
| #define K_AUX23 229 | |
| #define K_AUX24 230 | |
| #define K_AUX25 231 | |
| #define K_AUX26 232 | |
| #define K_AUX27 233 | |
| #define K_AUX28 234 | |
| #define K_AUX29 235 | |
| #define K_AUX30 236 | |
| #define K_AUX31 237 | |
| #define K_AUX32 238 | |
| #define K_MWHEELUP 239 | |
| #define K_MWHEELDOWN 240 | |
| #define MNET_IPX 1 | |
| #define MNET_TCP 2 | |
| #define SHOWNET(x) \ | |
| if (cl_shownet.value == 2) \ | |
| Con_Printf("%3i:%s\n", msg_readcount - 1, x); | |
| #define MAX_ALIAS_NAME 32 | |
| #define MAX_ARGS 80 | |
| #define NUM_SAFE_ARGVS 7 | |
| #define PAK0_COUNT 339 | |
| #define PAK0_CRC 32981 | |
| #define CMDLINE_LENGTH 256 | |
| #define MAX_FILES_IN_PACK 2048 | |
| #define CON_TEXTSIZE 16384 | |
| #define NUM_CON_TIMES 4 | |
| #define MAXCMDLINE 256 | |
| #define MAXGAMEDIRLEN 1000 | |
| #define MAXPRINTMSG 4096 | |
| #define CRC_INIT_VALUE 0xffff | |
| #define CRC_XOR_VALUE 0x0000 | |
| #define _R_SHARED_H_ | |
| #define MAXVERTS 16 // max points in a surface polygon | |
| #define MAXWORKINGVERTS \ | |
| (MAXVERTS + 4) // max points in an intermediate | |
| #define MAXHEIGHT 1024 | |
| #define MAXWIDTH 1280 | |
| #define MAXDIMENSION ((MAXHEIGHT > MAXWIDTH) ? MAXHEIGHT : MAXWIDTH) | |
| #define SIN_BUFFER_SIZE (MAXDIMENSION + CYCLE) | |
| #define INFINITE_DISTANCE \ | |
| 0x10000 // distance that's always guaranteed to | |
| #define NUMSTACKEDGES 2400 | |
| #define MINEDGES NUMSTACKEDGES | |
| #define NUMSTACKSURFACES 800 | |
| #define MINSURFACES NUMSTACKSURFACES | |
| #define MAXSPANS 3000 | |
| #define ALIAS_LEFT_CLIP 0x0001 | |
| #define ALIAS_TOP_CLIP 0x0002 | |
| #define ALIAS_RIGHT_CLIP 0x0004 | |
| #define ALIAS_BOTTOM_CLIP 0x0008 | |
| #define ALIAS_Z_CLIP 0x0010 | |
| #define ALIAS_XY_CLIP_MASK 0x000F | |
| #define SCANBUFFERPAD 0x1000 | |
| #define R_SKY_SMASK 0x007F0000 | |
| #define R_SKY_TMASK 0x007F0000 | |
| #define DS_SPAN_LIST_END -128 | |
| #define SURFCACHE_SIZE_AT_320X200 600 * 1024 | |
| #define NUM_MIPS 4 | |
| #define ALIAS_BASE_SIZE_RATIO (1.0 / 11.0) | |
| #define BMODEL_FULLY_CLIPPED \ | |
| 0x10 // value returned by R_BmodelCheckBBox () | |
| #define XCENTERING (1.0 / 2.0) | |
| #define YCENTERING (1.0 / 2.0) | |
| #define CLIP_EPSILON 0.001 | |
| #define BACKFACE_EPSILON 0.01 | |
| #define DIST_NOT_SET 98765 | |
| #define NEAR_CLIP 0.01 | |
| #define MAXBVERTINDEXES \ | |
| 1000 // new clipped vertices when clipping bmodels | |
| #define MAX_BTOFPOLYS 5000 // FIXME: tune this | |
| #define MAXALIASVERTS 2000 // TODO: tune this | |
| #define ALIAS_Z_CLIP_PLANE 5 | |
| #define AMP 8 * 0x10000 | |
| #define AMP2 3 | |
| #define SPEED 20 | |
| #define DPS_MAXSPANS MAXHEIGHT + 1 | |
| #define SKY_SPAN_SHIFT 5 | |
| #define SKY_SPAN_MAX (1 << SKY_SPAN_SHIFT) | |
| #define GUARDSIZE 4 | |
| #define MAX_CACHED_PICS 128 | |
| #define VCR_SIGNATURE 0x56435231 | |
| #define SAVEGAME_VERSION 5 | |
| #define DEG2RAD(a) (a * M_PI) / 180.0F | |
| #define StartingGame (m_multiplayer_cursor == 1) | |
| #define JoiningGame (m_multiplayer_cursor == 0) | |
| #define SerialConfig (m_net_cursor == 0) | |
| #define DirectConfig (m_net_cursor == 1) | |
| #define IPXConfig (m_net_cursor == 2) | |
| #define TCPIPConfig (m_net_cursor == 3) | |
| #define MAIN_ITEMS 5 | |
| #define SINGLEPLAYER_ITEMS 3 | |
| #define MAX_SAVEGAMES 12 | |
| #define MULTIPLAYER_ITEMS 3 | |
| #define NUM_SETUP_CMDS 5 | |
| #define OPTIONS_ITEMS 13 | |
| #define SLIDER_RANGE 10 | |
| #define NUMCOMMANDS (sizeof(bindnames) / sizeof(bindnames[0])) | |
| #define NUM_HELP_PAGES 6 | |
| #define NUM_SERIALCONFIG_CMDS 6 | |
| #define NUM_MODEMCONFIG_CMDS 5 | |
| #define NUM_LANCONFIG_CMDS 3 | |
| #define NUM_GAMEOPTIONS 9 | |
| #define MAX_MOD_KNOWN 256 | |
| #define NL_PRESENT 0 | |
| #define NL_NEEDS_LOADED 1 | |
| #define NL_UNREFERENCED 2 | |
| #define ANIM_CYCLE 2 | |
| #define sfunc net_landrivers[sock->landriver] | |
| #define dfunc net_landrivers[net_landriverlevel] | |
| #define VCR_OP_CONNECT 1 | |
| #define VCR_OP_GETMESSAGE 2 | |
| #define VCR_OP_SENDMESSAGE 3 | |
| #define VCR_OP_CANSENDMESSAGE 4 | |
| #define VCR_MAX_MESSAGE 4 | |
| #define RETURN_EDICT(e) (((int32_t *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e)) | |
| #define MAX_CHECK 16 | |
| #define MSG_BROADCAST 0 // unreliable to all | |
| #define MSG_ONE 1 // reliable to one (msg_entity) | |
| #define MSG_ALL 2 // reliable to all | |
| #define MSG_INIT 3 // write to the init string | |
| #define MAX_FIELD_LEN 64 | |
| #define GEFV_CACHESIZE 2 | |
| #define MAX_STACK_DEPTH 32 | |
| #define LOCALSTACK_SIZE 2048 | |
| #define LIGHT_MIN \ | |
| 5 // lowest light value we'll allow, to avoid the | |
| #define NUMVERTEXNORMALS 162 | |
| #define MAX_BMODEL_VERTS 500 // 6K | |
| #define MAX_BMODEL_EDGES 1000 // 12K | |
| #define MAXLEFTCLIPEDGES 100 | |
| #define FULLY_CLIPPED_CACHED 0x80000000 | |
| #define FRAMECOUNT_MASK 0x7FFFFFFF | |
| #define MAX_TIMINGS 100 | |
| #define MAX_PARTICLES \ | |
| 2048 // default max # of particles at one | |
| #define ABSOLUTE_MIN_PARTICLES \ | |
| 512 // no fewer than this no matter what's | |
| #define STAT_MINUS 10 // num frame for '-' stats digit | |
| #define MAX_SFX 512 | |
| #define PAINTBUFFER_SIZE 512 | |
| #define STEPSIZE 18 | |
| #define DI_NODIR -1 | |
| #define MOVE_EPSILON 0.01 | |
| #define STOP_EPSILON 0.1 | |
| #define MAX_CLIP_PLANES 5 | |
| #define MAX_FORWARD 6 | |
| #define MAX_HANDLES 10 | |
| #define BASEWIDTH (640) | |
| #define BASEHEIGHT (400) | |
| #define AREA_DEPTH 4 | |
| #define AREA_NODES 32 | |
| #define DIST_EPSILON (0.03125) | |
| #define DYNAMIC_SIZE 0xc000 | |
| #define ZONEID 0x1d4a11 | |
| #define MINFRAGMENT 64 | |
| #define HUNK_SENTINAL 0x1df001ed | |
| typedef struct sizebuf_s | |
| { | |
| bool allowoverflow; | |
| bool overflowed; | |
| uint8_t *data; | |
| int32_t maxsize; | |
| int32_t cursize; | |
| } sizebuf_t; | |
| typedef struct link_s | |
| { | |
| struct link_s *prev; | |
| struct link_s *next; | |
| } link_t; | |
| struct cache_user_s; | |
| extern struct cvar_s registered; | |
| typedef struct | |
| { | |
| int32_t fileofs; | |
| int32_t filelen; | |
| } lump_t; | |
| typedef struct | |
| { | |
| float mins[3]; | |
| float maxs[3]; | |
| float origin[3]; | |
| int32_t headnode[MAX_MAP_HULLS]; | |
| int32_t visleafs; | |
| int32_t firstface; | |
| int32_t numfaces; | |
| } dmodel_t; | |
| typedef struct | |
| { | |
| int32_t version; | |
| lump_t lumps[HEADER_LUMPS]; | |
| } dheader_t; | |
| typedef struct | |
| { | |
| int32_t nummiptex; | |
| int32_t dataofs[4]; | |
| } dmiptexlump_t; | |
| typedef struct miptex_s | |
| { | |
| int8_t name[16]; | |
| uint32_t width; | |
| uint32_t height; | |
| uint32_t offsets[MIPLEVELS]; | |
| } miptex_t; | |
| typedef struct | |
| { | |
| float point[3]; | |
| } dvertex_t; | |
| typedef struct | |
| { | |
| float normal[3]; | |
| float dist; | |
| int32_t type; | |
| } dplane_t; | |
| typedef struct | |
| { | |
| int32_t planenum; | |
| int16_t children[2]; | |
| int16_t mins[3]; | |
| int16_t maxs[3]; | |
| uint16_t firstface; | |
| uint16_t numfaces; | |
| } dnode_t; | |
| typedef struct | |
| { | |
| int32_t planenum; | |
| int16_t children[2]; | |
| } dclipnode_t; | |
| typedef struct texinfo_s | |
| { | |
| float vecs[2][4]; | |
| int32_t miptex; | |
| int32_t flags; | |
| } texinfo_t; | |
| typedef struct | |
| { | |
| uint16_t v[2]; | |
| } dedge_t; | |
| typedef struct | |
| { | |
| int16_t planenum; | |
| int16_t side; | |
| int32_t firstedge; | |
| int16_t numedges; | |
| int16_t texinfo; | |
| uint8_t styles[MAXLIGHTMAPS]; | |
| int32_t lightofs; | |
| } dface_t; | |
| typedef struct | |
| { | |
| int32_t contents; | |
| int32_t visofs; | |
| int16_t mins[3]; | |
| int16_t maxs[3]; | |
| uint16_t firstmarksurface; | |
| uint16_t nummarksurfaces; | |
| uint8_t ambient_level[NUM_AMBIENTS]; | |
| } dleaf_t; | |
| typedef uint8_t pixel_t; | |
| typedef struct vrect_s | |
| { | |
| int32_t x; | |
| int32_t y; | |
| int32_t width; | |
| int32_t height; | |
| struct vrect_s *pnext; | |
| } vrect_t; | |
| typedef struct | |
| { | |
| pixel_t *buffer; | |
| pixel_t *colormap; | |
| uint16_t *colormap16; | |
| int32_t fullbright; | |
| uint32_t rowbytes; | |
| uint32_t width; | |
| uint32_t height; | |
| float aspect; | |
| int32_t numpages; | |
| int32_t recalc_refdef; | |
| pixel_t *conbuffer; | |
| int32_t conrowbytes; | |
| uint32_t conwidth; | |
| uint32_t conheight; | |
| int32_t maxwarpwidth; | |
| int32_t maxwarpheight; | |
| pixel_t *direct; | |
| } viddef_t; | |
| typedef struct cache_user_s | |
| { | |
| void *data; | |
| } cache_user_t; | |
| typedef float vec_t; | |
| typedef vec_t vec3_t[3]; | |
| typedef vec_t vec5_t[5]; | |
| typedef int32_t fixed4_t; | |
| typedef int32_t fixed8_t; | |
| typedef int32_t fixed16_t; | |
| struct mplane_s; | |
| typedef struct | |
| { | |
| vec3_t origin; | |
| vec3_t angles; | |
| int32_t modelindex; | |
| int32_t frame; | |
| int32_t colormap; | |
| int32_t skin; | |
| int32_t effects; | |
| } entity_state_t; | |
| typedef struct | |
| { | |
| int32_t width; | |
| int32_t height; | |
| uint8_t data[4]; | |
| } qpic_t; | |
| typedef struct | |
| { | |
| char identification[4]; | |
| int32_t numlumps; | |
| int32_t infotableofs; | |
| } wadinfo_t; | |
| typedef struct | |
| { | |
| int32_t filepos; | |
| int32_t disksize; | |
| int32_t size; | |
| char type; | |
| char compression; | |
| char pad1; | |
| char pad2; | |
| char name[16]; | |
| } lumpinfo_t; | |
| typedef struct cvar_s | |
| { | |
| char *name; | |
| char *string; | |
| bool archive; | |
| bool server; | |
| float value; | |
| struct cvar_s *next; | |
| } cvar_t; | |
| struct qsockaddr | |
| { | |
| int16_t sa_family; | |
| unsigned char sa_data[14]; | |
| }; | |
| typedef struct qsocket_s | |
| { | |
| struct qsocket_s *next; | |
| double connecttime; | |
| double lastMessageTime; | |
| double lastSendTime; | |
| bool disconnected; | |
| bool canSend; | |
| bool sendNext; | |
| int32_t driver; | |
| int32_t landriver; | |
| int32_t socket; | |
| void *driverdata; | |
| uint32_t ackSequence; | |
| uint32_t sendSequence; | |
| uint32_t unreliableSendSequence; | |
| int32_t sendMessageLength; | |
| uint8_t sendMessage[NET_MAXMESSAGE]; | |
| uint32_t receiveSequence; | |
| uint32_t unreliableReceiveSequence; | |
| int32_t receiveMessageLength; | |
| uint8_t receiveMessage[NET_MAXMESSAGE]; | |
| struct qsockaddr addr; | |
| char address[NET_NAMELEN]; | |
| } qsocket_t; | |
| typedef struct | |
| { | |
| char *name; | |
| bool initialized; | |
| int32_t controlSock; | |
| int32_t (*Init)(void); | |
| void (*Shutdown)(void); | |
| void (*Listen)(bool state); | |
| int32_t (*OpenSocket)(int32_t port); | |
| int32_t (*CloseSocket)(int32_t socket); | |
| int32_t (*Connect)(int32_t socket, struct qsockaddr *addr); | |
| int32_t (*CheckNewConnections)(void); | |
| int32_t (*Read)(int32_t socket, uint8_t *buf, int32_t len, struct qsockaddr *addr); | |
| int32_t (*Write)(int32_t socket, uint8_t *buf, int32_t len, struct qsockaddr *addr); | |
| int32_t (*Broadcast)(int32_t socket, uint8_t *buf, int32_t len); | |
| char *(*AddrToString)(struct qsockaddr *addr); | |
| int32_t (*StringToAddr)(char *string, struct qsockaddr *addr); | |
| int32_t (*GetSocketAddr)(int32_t socket, struct qsockaddr *addr); | |
| int32_t (*GetNameFromAddr)(struct qsockaddr *addr, char *name); | |
| int32_t (*GetAddrFromName)(char *name, struct qsockaddr *addr); | |
| int32_t (*AddrCompare)(struct qsockaddr *addr1, struct qsockaddr *addr2); | |
| int32_t (*GetSocketPort)(struct qsockaddr *addr); | |
| int32_t (*SetSocketPort)(struct qsockaddr *addr, int32_t port); | |
| } net_landriver_t; | |
| typedef struct | |
| { | |
| char *name; | |
| bool initialized; | |
| int32_t (*Init)(void); | |
| void (*Listen)(bool state); | |
| void (*SearchForHosts)(bool xmit); | |
| qsocket_t *(*Connect)(char *host); | |
| qsocket_t *(*CheckNewConnections)(void); | |
| int32_t (*QGetMessage)(qsocket_t *sock); | |
| int32_t (*QSendMessage)(qsocket_t *sock, sizebuf_t *data); | |
| int32_t (*SendUnreliableMessage)(qsocket_t *sock, sizebuf_t *data); | |
| bool (*CanSendMessage)(qsocket_t *sock); | |
| bool (*CanSendUnreliableMessage)(qsocket_t *sock); | |
| void (*Close)(qsocket_t *sock); | |
| void (*Shutdown)(void); | |
| int32_t controlSock; | |
| } net_driver_t; | |
| typedef struct | |
| { | |
| char name[16]; | |
| char map[16]; | |
| char cname[32]; | |
| int32_t users; | |
| int32_t maxusers; | |
| int32_t driver; | |
| int32_t ldriver; | |
| struct qsockaddr addr; | |
| } hostcache_t; | |
| typedef struct _PollProcedure | |
| { | |
| struct _PollProcedure *next; | |
| double nextTime; | |
| void (*procedure)(); | |
| void *arg; | |
| } PollProcedure; | |
| typedef void (*xcommand_t)(void); | |
| typedef enum | |
| { | |
| src_client, | |
| src_command | |
| } cmd_source_t; | |
| typedef struct | |
| { | |
| int32_t left; | |
| int32_t right; | |
| } portable_samplepair_t; | |
| typedef struct sfx_s | |
| { | |
| char name[MAX_QPATH]; | |
| cache_user_t cache; | |
| } sfx_t; | |
| typedef struct | |
| { | |
| int32_t length; | |
| int32_t loopstart; | |
| int32_t speed; | |
| int32_t width; | |
| int32_t stereo; | |
| uint8_t data[1]; | |
| } sfxcache_t; | |
| typedef struct | |
| { | |
| bool gamealive; | |
| bool soundalive; | |
| bool splitbuffer; | |
| int32_t channels; | |
| int32_t samples; | |
| int32_t submission_chunk; | |
| int32_t samplepos; | |
| int32_t samplebits; | |
| int32_t speed; | |
| unsigned char *buffer; | |
| } dma_t; | |
| typedef struct | |
| { | |
| sfx_t *sfx; | |
| int32_t leftvol; | |
| int32_t rightvol; | |
| int32_t end; | |
| int32_t pos; | |
| int32_t looping; | |
| int32_t entnum; | |
| int32_t entchannel; | |
| vec3_t origin; | |
| vec_t dist_mult; | |
| int32_t master_vol; | |
| } channel_t; | |
| typedef struct | |
| { | |
| int32_t rate; | |
| int32_t width; | |
| int32_t channels; | |
| int32_t loopstart; | |
| int32_t samples; | |
| int32_t dataofs; | |
| } wavinfo_t; | |
| typedef struct efrag_s | |
| { | |
| struct mleaf_s *leaf; | |
| struct efrag_s *leafnext; | |
| struct entity_s *entity; | |
| struct efrag_s *entnext; | |
| } efrag_t; | |
| typedef struct entity_s | |
| { | |
| bool forcelink; | |
| int32_t update_type; | |
| entity_state_t baseline; | |
| double msgtime; | |
| vec3_t msg_origins[2]; | |
| vec3_t origin; | |
| vec3_t msg_angles[2]; | |
| vec3_t angles; | |
| struct model_s *model; | |
| struct efrag_s *efrag; | |
| int32_t frame; | |
| float syncbase; | |
| uint8_t *colormap; | |
| int32_t effects; | |
| int32_t skinnum; | |
| int32_t visframe; | |
| int32_t dlightframe; | |
| int32_t dlightbits; | |
| int32_t trivial_accept; | |
| struct mnode_s *topnode; | |
| } entity_t; | |
| typedef struct | |
| { | |
| vrect_t vrect; | |
| vrect_t aliasvrect; | |
| int32_t vrectright; | |
| int32_t vrectbottom; | |
| int32_t aliasvrectright; | |
| int32_t aliasvrectbottom; | |
| float vrectrightedge; | |
| float fvrectx; | |
| float fvrecty; | |
| float fvrectx_adj; | |
| float fvrecty_adj; | |
| int32_t vrect_x_adj_shift20; | |
| int32_t vrectright_adj_shift20; | |
| float fvrectright_adj; | |
| float fvrectbottom_adj; | |
| float fvrectright; | |
| float fvrectbottom; | |
| float horizontalFieldOfView; | |
| float xOrigin; | |
| float yOrigin; | |
| vec3_t vieworg; | |
| vec3_t viewangles; | |
| float fov_x; | |
| float fov_y; | |
| int32_t ambientlight; | |
| } refdef_t; | |
| extern struct texture_s *r_notexture_mip; | |
| typedef struct | |
| { | |
| vec3_t viewangles; | |
| float forwardmove; | |
| float sidemove; | |
| float upmove; | |
| } usercmd_t; | |
| typedef struct | |
| { | |
| int32_t length; | |
| char map[MAX_STYLESTRING]; | |
| } lightstyle_t; | |
| typedef struct | |
| { | |
| char name[MAX_SCOREBOARDNAME]; | |
| float entertime; | |
| int32_t frags; | |
| int32_t colors; | |
| uint8_t translations[VID_GRADES * 256]; | |
| } scoreboard_t; | |
| typedef struct | |
| { | |
| int32_t destcolor[3]; | |
| int32_t percent; | |
| } cshift_t; | |
| typedef struct | |
| { | |
| vec3_t origin; | |
| float radius; | |
| float die; | |
| float decay; | |
| float minlight; | |
| int32_t key; | |
| } dlight_t; | |
| typedef struct | |
| { | |
| int32_t entity; | |
| struct model_s *model; | |
| float endtime; | |
| vec3_t start; | |
| vec3_t end; | |
| } beam_t; | |
| typedef enum | |
| { | |
| ca_dedicated, | |
| ca_disconnected, | |
| ca_connected | |
| } cactive_t; | |
| typedef struct | |
| { | |
| cactive_t state; | |
| char mapstring[MAX_QPATH]; | |
| char spawnparms[MAX_MAPSTRING]; | |
| int32_t demonum; | |
| char demos[MAX_DEMOS][MAX_DEMONAME]; | |
| bool demorecording; | |
| bool demoplayback; | |
| bool timedemo; | |
| int32_t forcetrack; | |
| FILE *demofile; | |
| int32_t td_lastframe; | |
| int32_t td_startframe; | |
| float td_starttime; | |
| int32_t signon; | |
| struct qsocket_s *netcon; | |
| sizebuf_t message; | |
| } client_static_t; | |
| typedef struct | |
| { | |
| int32_t movemessages; | |
| usercmd_t cmd; | |
| int32_t stats[MAX_CL_STATS]; | |
| int32_t items; | |
| float item_gettime[32]; | |
| float faceanimtime; | |
| cshift_t cshifts[NUM_CSHIFTS]; | |
| cshift_t prev_cshifts[NUM_CSHIFTS]; | |
| vec3_t mviewangles[2]; | |
| vec3_t viewangles; | |
| vec3_t mvelocity[2]; | |
| vec3_t velocity; | |
| vec3_t punchangle; | |
| float idealpitch; | |
| float pitchvel; | |
| bool nodrift; | |
| float driftmove; | |
| double laststop; | |
| float viewheight; | |
| float crouch; | |
| bool paused; | |
| bool onground; | |
| bool inwater; | |
| int32_t intermission; | |
| int32_t completed_time; | |
| double mtime[2]; | |
| double time; | |
| double oldtime; | |
| float last_received_message; | |
| struct model_s *model_precache[MAX_MODELS]; | |
| struct sfx_s *sound_precache[MAX_SOUNDS]; | |
| char levelname[40]; | |
| int32_t viewentity; | |
| int32_t maxclients; | |
| int32_t gametype; | |
| struct model_s *worldmodel; | |
| struct efrag_s *free_efrags; | |
| int32_t num_entities; | |
| int32_t num_statics; | |
| entity_t viewent; | |
| int32_t cdtrack; | |
| int32_t looptrack; | |
| scoreboard_t *scores; | |
| } client_state_t; | |
| typedef struct | |
| { | |
| int32_t down[2]; | |
| int32_t state; | |
| } kbutton_t; | |
| typedef int32_t func_t; | |
| typedef int32_t string_t; | |
| typedef enum | |
| { | |
| ev_void, | |
| ev_string, | |
| ev_float, | |
| ev_vector, | |
| ev_entity, | |
| ev_field, | |
| ev_function, | |
| ev_pointer | |
| } etype_t; | |
| enum | |
| { | |
| OP_DONE, | |
| OP_MUL_F, | |
| OP_MUL_V, | |
| OP_MUL_FV, | |
| OP_MUL_VF, | |
| OP_DIV_F, | |
| OP_ADD_F, | |
| OP_ADD_V, | |
| OP_SUB_F, | |
| OP_SUB_V, | |
| OP_EQ_F, | |
| OP_EQ_V, | |
| OP_EQ_S, | |
| OP_EQ_E, | |
| OP_EQ_FNC, | |
| OP_NE_F, | |
| OP_NE_V, | |
| OP_NE_S, | |
| OP_NE_E, | |
| OP_NE_FNC, | |
| OP_LE, | |
| OP_GE, | |
| OP_LT, | |
| OP_GT, | |
| OP_LOAD_F, | |
| OP_LOAD_V, | |
| OP_LOAD_S, | |
| OP_LOAD_ENT, | |
| OP_LOAD_FLD, | |
| OP_LOAD_FNC, | |
| OP_ADDRESS, | |
| OP_STORE_F, | |
| OP_STORE_V, | |
| OP_STORE_S, | |
| OP_STORE_ENT, | |
| OP_STORE_FLD, | |
| OP_STORE_FNC, | |
| OP_STOREP_F, | |
| OP_STOREP_V, | |
| OP_STOREP_S, | |
| OP_STOREP_ENT, | |
| OP_STOREP_FLD, | |
| OP_STOREP_FNC, | |
| OP_RETURN, | |
| OP_NOT_F, | |
| OP_NOT_V, | |
| OP_NOT_S, | |
| OP_NOT_ENT, | |
| OP_NOT_FNC, | |
| OP_IF, | |
| OP_IFNOT, | |
| OP_CALL0, | |
| OP_CALL1, | |
| OP_CALL2, | |
| OP_CALL3, | |
| OP_CALL4, | |
| OP_CALL5, | |
| OP_CALL6, | |
| OP_CALL7, | |
| OP_CALL8, | |
| OP_STATE, | |
| OP_GOTO, | |
| OP_AND, | |
| OP_OR, | |
| OP_BITAND, | |
| OP_BITOR | |
| }; | |
| typedef struct statement_s | |
| { | |
| uint16_t op; | |
| int16_t a; | |
| int16_t b; | |
| int16_t c; | |
| } dstatement_t; | |
| typedef struct | |
| { | |
| uint16_t type; | |
| uint16_t ofs; | |
| int32_t s_name; | |
| } ddef_t; | |
| typedef struct | |
| { | |
| int32_t first_statement; | |
| int32_t parm_start; | |
| int32_t locals; | |
| int32_t profile; | |
| int32_t s_name; | |
| int32_t s_file; | |
| int32_t numparms; | |
| uint8_t parm_size[MAX_PARMS]; | |
| } dfunction_t; | |
| typedef struct | |
| { | |
| int32_t version; | |
| int32_t crc; | |
| int32_t ofs_statements; | |
| int32_t numstatements; | |
| int32_t ofs_globaldefs; | |
| int32_t numglobaldefs; | |
| int32_t ofs_fielddefs; | |
| int32_t numfielddefs; | |
| int32_t ofs_functions; | |
| int32_t numfunctions; | |
| int32_t ofs_strings; | |
| int32_t numstrings; | |
| int32_t ofs_globals; | |
| int32_t numglobals; | |
| int32_t entityfields; | |
| } dprograms_t; | |
| typedef struct | |
| { | |
| int pad[28]; | |
| int self; | |
| int other; | |
| int world; | |
| float time; | |
| float frametime; | |
| float force_retouch; | |
| string_t mapname; | |
| float deathmatch; | |
| float coop; | |
| float teamplay; | |
| float serverflags; | |
| float total_secrets; | |
| float total_monsters; | |
| float found_secrets; | |
| float killed_monsters; | |
| float parm1; | |
| float parm2; | |
| float parm3; | |
| float parm4; | |
| float parm5; | |
| float parm6; | |
| float parm7; | |
| float parm8; | |
| float parm9; | |
| float parm10; | |
| float parm11; | |
| float parm12; | |
| float parm13; | |
| float parm14; | |
| float parm15; | |
| float parm16; | |
| vec3_t v_forward; | |
| vec3_t v_up; | |
| vec3_t v_right; | |
| float trace_allsolid; | |
| float trace_startsolid; | |
| float trace_fraction; | |
| vec3_t trace_endpos; | |
| vec3_t trace_plane_normal; | |
| float trace_plane_dist; | |
| int trace_ent; | |
| float trace_inopen; | |
| float trace_inwater; | |
| int msg_entity; | |
| func_t main; | |
| func_t StartFrame; | |
| func_t PlayerPreThink; | |
| func_t PlayerPostThink; | |
| func_t ClientKill; | |
| func_t ClientConnect; | |
| func_t PutClientInServer; | |
| func_t ClientDisconnect; | |
| func_t SetNewParms; | |
| func_t SetChangeParms; | |
| } globalvars_t; | |
| typedef struct | |
| { | |
| float modelindex; | |
| vec3_t absmin; | |
| vec3_t absmax; | |
| float ltime; | |
| float movetype; | |
| float solid; | |
| vec3_t origin; | |
| vec3_t oldorigin; | |
| vec3_t velocity; | |
| vec3_t angles; | |
| vec3_t avelocity; | |
| vec3_t punchangle; | |
| string_t classname; | |
| string_t model; | |
| float frame; | |
| float skin; | |
| float effects; | |
| vec3_t mins; | |
| vec3_t maxs; | |
| vec3_t size; | |
| func_t touch; | |
| func_t use; | |
| func_t think; | |
| func_t blocked; | |
| float nextthink; | |
| int groundentity; | |
| float health; | |
| float frags; | |
| float weapon; | |
| string_t weaponmodel; | |
| float weaponframe; | |
| float currentammo; | |
| float ammo_shells; | |
| float ammo_nails; | |
| float ammo_rockets; | |
| float ammo_cells; | |
| float items; | |
| float takedamage; | |
| int chain; | |
| float deadflag; | |
| vec3_t view_ofs; | |
| float button0; | |
| float button1; | |
| float button2; | |
| float impulse; | |
| float fixangle; | |
| vec3_t v_angle; | |
| float idealpitch; | |
| string_t netname; | |
| int enemy; | |
| float flags; | |
| float colormap; | |
| float team; | |
| float max_health; | |
| float teleport_time; | |
| float armortype; | |
| float armorvalue; | |
| float waterlevel; | |
| float watertype; | |
| float ideal_yaw; | |
| float yaw_speed; | |
| int aiment; | |
| int goalentity; | |
| float spawnflags; | |
| string_t target; | |
| string_t targetname; | |
| float dmg_take; | |
| float dmg_save; | |
| int dmg_inflictor; | |
| int owner; | |
| vec3_t movedir; | |
| string_t message; | |
| float sounds; | |
| string_t noise; | |
| string_t noise1; | |
| string_t noise2; | |
| string_t noise3; | |
| } entvars_t; | |
| typedef union eval_s | |
| { | |
| string_t string; | |
| float _float; | |
| float vector[3]; | |
| func_t function; | |
| int32_t _int; | |
| int32_t edict; | |
| } eval_t; | |
| typedef struct edict_s | |
| { | |
| bool free; | |
| link_t area; | |
| int32_t num_leafs; | |
| int16_t leafnums[MAX_ENT_LEAFS]; | |
| entity_state_t baseline; | |
| float freetime; | |
| entvars_t v; | |
| } edict_t; | |
| typedef void (*builtin_t)(void); | |
| typedef struct | |
| { | |
| int32_t maxclients; | |
| int32_t maxclientslimit; | |
| struct client_s *clients; | |
| int32_t serverflags; | |
| bool changelevel_issued; | |
| } server_static_t; | |
| typedef enum | |
| { | |
| ss_loading, | |
| ss_active | |
| } server_state_t; | |
| typedef struct | |
| { | |
| bool active; | |
| bool paused; | |
| bool loadgame; | |
| double time; | |
| int32_t lastcheck; | |
| double lastchecktime; | |
| char name[64]; | |
| char startspot[64]; | |
| char modelname[64]; | |
| struct model_s *worldmodel; | |
| char *model_precache[MAX_MODELS]; | |
| struct model_s *models[MAX_MODELS]; | |
| char *sound_precache[MAX_SOUNDS]; | |
| char *lightstyles[MAX_LIGHTSTYLES]; | |
| int32_t num_edicts; | |
| int32_t max_edicts; | |
| edict_t *edicts; | |
| server_state_t state; | |
| sizebuf_t datagram; | |
| uint8_t datagram_buf[MAX_DATAGRAM]; | |
| sizebuf_t reliable_datagram; | |
| uint8_t reliable_datagram_buf[MAX_DATAGRAM]; | |
| sizebuf_t signon; | |
| uint8_t signon_buf[8192]; | |
| } server_t; | |
| typedef struct client_s | |
| { | |
| bool active; | |
| bool spawned; | |
| bool dropasap; | |
| bool privileged; | |
| bool sendsignon; | |
| double last_message; | |
| struct qsocket_s *netconnection; | |
| usercmd_t cmd; | |
| vec3_t wishdir; | |
| sizebuf_t message; | |
| uint8_t msgbuf[MAX_MSGLEN]; | |
| edict_t *edict; | |
| char name[32]; | |
| int32_t colors; | |
| float ping_times[NUM_PING_TIMES]; | |
| int32_t num_pings; | |
| float spawn_parms[NUM_SPAWN_PARMS]; | |
| int32_t old_frags; | |
| } client_t; | |
| typedef enum | |
| { | |
| ST_SYNC = 0, | |
| ST_RAND | |
| } synctype_t; | |
| typedef enum | |
| { | |
| ALIAS_SINGLE = 0, | |
| ALIAS_GROUP | |
| } aliasframetype_t; | |
| typedef enum | |
| { | |
| ALIAS_SKIN_SINGLE = 0, | |
| ALIAS_SKIN_GROUP | |
| } aliasskintype_t; | |
| typedef struct | |
| { | |
| int32_t ident; | |
| int32_t version; | |
| vec3_t scale; | |
| vec3_t scale_origin; | |
| float boundingradius; | |
| vec3_t eyeposition; | |
| int32_t numskins; | |
| int32_t skinwidth; | |
| int32_t skinheight; | |
| int32_t numverts; | |
| int32_t numtris; | |
| int32_t numframes; | |
| synctype_t synctype; | |
| int32_t flags; | |
| float size; | |
| } mdl_t; | |
| typedef struct | |
| { | |
| int32_t onseam; | |
| int32_t s; | |
| int32_t t; | |
| } stvert_t; | |
| typedef struct dtriangle_s | |
| { | |
| int32_t facesfront; | |
| int32_t vertindex[3]; | |
| } dtriangle_t; | |
| typedef struct | |
| { | |
| uint8_t v[3]; | |
| uint8_t lightnormalindex; | |
| } trivertx_t; | |
| typedef struct | |
| { | |
| trivertx_t bboxmin; | |
| trivertx_t bboxmax; | |
| char name[16]; | |
| } daliasframe_t; | |
| typedef struct | |
| { | |
| int32_t numframes; | |
| trivertx_t bboxmin; | |
| trivertx_t bboxmax; | |
| } daliasgroup_t; | |
| typedef struct | |
| { | |
| int32_t numskins; | |
| } daliasskingroup_t; | |
| typedef struct | |
| { | |
| float interval; | |
| } daliasinterval_t; | |
| typedef struct | |
| { | |
| float interval; | |
| } daliasskininterval_t; | |
| typedef struct | |
| { | |
| aliasframetype_t type; | |
| } daliasframetype_t; | |
| typedef struct | |
| { | |
| aliasskintype_t type; | |
| } daliasskintype_t; | |
| typedef struct | |
| { | |
| int32_t ident; | |
| int32_t version; | |
| int32_t type; | |
| float boundingradius; | |
| int32_t width; | |
| int32_t height; | |
| int32_t numframes; | |
| float beamlength; | |
| synctype_t synctype; | |
| } dsprite_t; | |
| typedef struct | |
| { | |
| int32_t origin[2]; | |
| int32_t width; | |
| int32_t height; | |
| } dspriteframe_t; | |
| typedef struct | |
| { | |
| int32_t numframes; | |
| } dspritegroup_t; | |
| typedef struct | |
| { | |
| float interval; | |
| } dspriteinterval_t; | |
| typedef enum | |
| { | |
| SPR_SINGLE = 0, | |
| SPR_GROUP | |
| } spriteframetype_t; | |
| typedef struct | |
| { | |
| spriteframetype_t type; | |
| } dspriteframetype_t; | |
| typedef struct | |
| { | |
| vec3_t position; | |
| } mvertex_t; | |
| typedef struct mplane_s | |
| { | |
| vec3_t normal; | |
| float dist; | |
| uint8_t type; | |
| uint8_t signbits; | |
| uint8_t pad[2]; | |
| } mplane_t; | |
| typedef struct texture_s | |
| { | |
| char name[16]; | |
| uint32_t width; | |
| uint32_t height; | |
| int32_t anim_total; | |
| int32_t anim_min; | |
| int32_t anim_max; | |
| struct texture_s *anim_next; | |
| struct texture_s *alternate_anims; | |
| uint32_t offsets[MIPLEVELS]; | |
| } texture_t; | |
| typedef struct | |
| { | |
| uint16_t v[2]; | |
| uint32_t cachededgeoffset; | |
| } medge_t; | |
| typedef struct | |
| { | |
| float vecs[2][4]; | |
| float mipadjust; | |
| texture_t *texture; | |
| int32_t flags; | |
| } mtexinfo_t; | |
| typedef struct msurface_s | |
| { | |
| int32_t visframe; | |
| int32_t dlightframe; | |
| int32_t dlightbits; | |
| mplane_t *plane; | |
| int32_t flags; | |
| int32_t firstedge; | |
| int32_t numedges; | |
| struct surfcache_s *cachespots[MIPLEVELS]; | |
| int16_t texturemins[2]; | |
| int16_t extents[2]; | |
| mtexinfo_t *texinfo; | |
| uint8_t styles[MAXLIGHTMAPS]; | |
| uint8_t *samples; | |
| } msurface_t; | |
| typedef struct mnode_s | |
| { | |
| int32_t contents; | |
| int32_t visframe; | |
| int16_t minmaxs[6]; | |
| struct mnode_s *parent; | |
| mplane_t *plane; | |
| struct mnode_s *children[2]; | |
| uint16_t firstsurface; | |
| uint16_t numsurfaces; | |
| } mnode_t; | |
| typedef struct mleaf_s | |
| { | |
| int32_t contents; | |
| int32_t visframe; | |
| int16_t minmaxs[6]; | |
| struct mnode_s *parent; | |
| uint8_t *compressed_vis; | |
| efrag_t *efrags; | |
| msurface_t **firstmarksurface; | |
| int32_t nummarksurfaces; | |
| int32_t key; | |
| uint8_t ambient_sound_level[NUM_AMBIENTS]; | |
| } mleaf_t; | |
| typedef struct | |
| { | |
| dclipnode_t *clipnodes; | |
| mplane_t *planes; | |
| int32_t firstclipnode; | |
| int32_t lastclipnode; | |
| vec3_t clip_mins; | |
| vec3_t clip_maxs; | |
| } hull_t; | |
| typedef struct mspriteframe_s | |
| { | |
| int32_t width; | |
| int32_t height; | |
| void *pcachespot; | |
| float up; | |
| float down; | |
| float left; | |
| float right; | |
| uint8_t pixels[4]; | |
| } mspriteframe_t; | |
| typedef struct | |
| { | |
| int32_t numframes; | |
| float *intervals; | |
| mspriteframe_t *frames[1]; | |
| } mspritegroup_t; | |
| typedef struct | |
| { | |
| spriteframetype_t type; | |
| mspriteframe_t *frameptr; | |
| } mspriteframedesc_t; | |
| typedef struct | |
| { | |
| int32_t type; | |
| int32_t maxwidth; | |
| int32_t maxheight; | |
| int32_t numframes; | |
| float beamlength; | |
| void *cachespot; | |
| mspriteframedesc_t frames[1]; | |
| } msprite_t; | |
| typedef struct | |
| { | |
| aliasframetype_t type; | |
| trivertx_t bboxmin; | |
| trivertx_t bboxmax; | |
| int32_t frame; | |
| char name[16]; | |
| } maliasframedesc_t; | |
| typedef struct | |
| { | |
| aliasskintype_t type; | |
| void *pcachespot; | |
| int32_t skin; | |
| } maliasskindesc_t; | |
| typedef struct | |
| { | |
| trivertx_t bboxmin; | |
| trivertx_t bboxmax; | |
| int32_t frame; | |
| } maliasgroupframedesc_t; | |
| typedef struct | |
| { | |
| int32_t numframes; | |
| int32_t intervals; | |
| maliasgroupframedesc_t frames[1]; | |
| } maliasgroup_t; | |
| typedef struct | |
| { | |
| int32_t numskins; | |
| int32_t intervals; | |
| maliasskindesc_t skindescs[1]; | |
| } maliasskingroup_t; | |
| typedef struct mtriangle_s | |
| { | |
| int32_t facesfront; | |
| int32_t vertindex[3]; | |
| } mtriangle_t; | |
| typedef struct | |
| { | |
| int32_t model; | |
| int32_t stverts; | |
| int32_t skindesc; | |
| int32_t triangles; | |
| maliasframedesc_t frames[1]; | |
| } aliashdr_t; | |
| typedef enum | |
| { | |
| mod_brush, | |
| mod_sprite, | |
| mod_alias | |
| } modtype_t; | |
| typedef struct model_s | |
| { | |
| char name[MAX_QPATH]; | |
| bool needload; | |
| modtype_t type; | |
| int32_t numframes; | |
| synctype_t synctype; | |
| int32_t flags; | |
| vec3_t mins; | |
| vec3_t maxs; | |
| float radius; | |
| int32_t firstmodelsurface; | |
| int32_t nummodelsurfaces; | |
| int32_t numsubmodels; | |
| dmodel_t *submodels; | |
| int32_t numplanes; | |
| mplane_t *planes; | |
| int32_t numleafs; | |
| mleaf_t *leafs; | |
| int32_t numvertexes; | |
| mvertex_t *vertexes; | |
| int32_t numedges; | |
| medge_t *edges; | |
| int32_t numnodes; | |
| mnode_t *nodes; | |
| int32_t numtexinfo; | |
| mtexinfo_t *texinfo; | |
| int32_t numsurfaces; | |
| msurface_t *surfaces; | |
| int32_t numsurfedges; | |
| int32_t *surfedges; | |
| int32_t numclipnodes; | |
| dclipnode_t *clipnodes; | |
| int32_t nummarksurfaces; | |
| msurface_t **marksurfaces; | |
| hull_t hulls[MAX_MAP_HULLS]; | |
| int32_t numtextures; | |
| texture_t **textures; | |
| uint8_t *visdata; | |
| uint8_t *lightdata; | |
| char *entities; | |
| cache_user_t cache; | |
| } model_t; | |
| typedef struct | |
| { | |
| float u; | |
| float v; | |
| float s; | |
| float t; | |
| float zi; | |
| } emitpoint_t; | |
| typedef enum | |
| { | |
| pt_static, | |
| pt_grav, | |
| pt_slowgrav, | |
| pt_fire, | |
| pt_explode, | |
| pt_explode2, | |
| pt_blob, | |
| pt_blob2 | |
| } ptype_t; | |
| typedef struct particle_s | |
| { | |
| vec3_t org; | |
| float color; | |
| struct particle_s *next; | |
| vec3_t vel; | |
| float ramp; | |
| float die; | |
| ptype_t type; | |
| } particle_t; | |
| typedef struct polyvert_s | |
| { | |
| float u; | |
| float v; | |
| float zi; | |
| float s; | |
| float t; | |
| } polyvert_t; | |
| typedef struct polydesc_s | |
| { | |
| int32_t numverts; | |
| float nearzi; | |
| msurface_t *pcurrentface; | |
| polyvert_t *pverts; | |
| } polydesc_t; | |
| typedef struct finalvert_s | |
| { | |
| int32_t v[6]; | |
| int32_t flags; | |
| float reserved; | |
| } finalvert_t; | |
| typedef struct | |
| { | |
| void *pskin; | |
| maliasskindesc_t *pskindesc; | |
| int32_t skinwidth; | |
| int32_t skinheight; | |
| mtriangle_t *ptriangles; | |
| finalvert_t *pfinalverts; | |
| int32_t numtriangles; | |
| int32_t drawtype; | |
| int32_t seamfixupX16; | |
| } affinetridesc_t; | |
| typedef struct | |
| { | |
| float u; | |
| float v; | |
| float zi; | |
| float color; | |
| } screenpart_t; | |
| typedef struct | |
| { | |
| int32_t nump; | |
| emitpoint_t *pverts; | |
| mspriteframe_t *pspriteframe; | |
| vec3_t vup; | |
| vec3_t vright; | |
| vec3_t vpn; | |
| float nearzi; | |
| } spritedesc_t; | |
| typedef struct | |
| { | |
| int32_t u; | |
| int32_t v; | |
| float zi; | |
| int32_t color; | |
| } zpointdesc_t; | |
| typedef struct | |
| { | |
| pixel_t *surfdat; | |
| int32_t rowbytes; | |
| msurface_t *surf; | |
| fixed8_t lightadj[MAXLIGHTMAPS]; | |
| texture_t *texture; | |
| int32_t surfmip; | |
| int32_t surfwidth; | |
| int32_t surfheight; | |
| } drawsurf_t; | |
| typedef struct | |
| { | |
| vec3_t normal; | |
| float dist; | |
| } plane_t; | |
| typedef struct | |
| { | |
| bool allsolid; | |
| bool startsolid; | |
| bool inopen; | |
| bool inwater; | |
| float fraction; | |
| vec3_t endpos; | |
| plane_t plane; | |
| edict_t *ent; | |
| } trace_t; | |
| typedef enum | |
| { | |
| key_game, | |
| key_console, | |
| key_message, | |
| key_menu | |
| } keydest_t; | |
| typedef struct | |
| { | |
| int8_t *basedir; | |
| int8_t *cachedir; | |
| int32_t argc; | |
| int8_t **argv; | |
| void *membase; | |
| int32_t memsize; | |
| } quakeparms_t; | |
| typedef struct cmdalias_s | |
| { | |
| struct cmdalias_s *next; | |
| char name[MAX_ALIAS_NAME]; | |
| char *value; | |
| } cmdalias_t; | |
| typedef struct cmd_function_s | |
| { | |
| struct cmd_function_s *next; | |
| char *name; | |
| xcommand_t function; | |
| } cmd_function_t; | |
| typedef struct | |
| { | |
| char name[MAX_QPATH]; | |
| int32_t filepos; | |
| int32_t filelen; | |
| } packfile_t; | |
| typedef struct pack_s | |
| { | |
| char filename[MAX_OSPATH]; | |
| int32_t handle; | |
| int32_t numfiles; | |
| packfile_t *files; | |
| } pack_t; | |
| typedef struct | |
| { | |
| char name[56]; | |
| int32_t filepos; | |
| int32_t filelen; | |
| } dpackfile_t; | |
| typedef struct | |
| { | |
| char id[4]; | |
| int32_t dirofs; | |
| int32_t dirlen; | |
| } dpackheader_t; | |
| typedef struct searchpath_s | |
| { | |
| char filename[MAX_OSPATH]; | |
| pack_t *pack; | |
| struct searchpath_s *next; | |
| } searchpath_t; | |
| typedef struct espan_s | |
| { | |
| int32_t u; | |
| int32_t v; | |
| int32_t count; | |
| struct espan_s *pnext; | |
| } espan_t; | |
| typedef struct surf_s | |
| { | |
| struct surf_s *next; | |
| struct surf_s *prev; | |
| struct espan_s *spans; | |
| int32_t key; | |
| int32_t last_u; | |
| int32_t spanstate; | |
| int32_t flags; | |
| void *data; | |
| entity_t *entity; | |
| float nearzi; | |
| bool insubmodel; | |
| float d_ziorigin; | |
| float d_zistepu; | |
| float d_zistepv; | |
| int32_t pad[2]; | |
| } surf_t; | |
| typedef struct edge_s | |
| { | |
| fixed16_t u; | |
| fixed16_t u_step; | |
| struct edge_s *prev; | |
| struct edge_s *next; | |
| uint16_t surfs[2]; | |
| struct edge_s *nextremove; | |
| float nearzi; | |
| medge_t *owner; | |
| } edge_t; | |
| typedef struct surfcache_s | |
| { | |
| struct surfcache_s *next; | |
| struct surfcache_s **owner; | |
| int32_t lightadj[MAXLIGHTMAPS]; | |
| int32_t dlight; | |
| int32_t size; | |
| uint32_t width; | |
| uint32_t height; | |
| float mipscale; | |
| struct texture_s *texture; | |
| uint8_t data[4]; | |
| } surfcache_t; | |
| typedef struct sspan_s | |
| { | |
| int32_t u; | |
| int32_t v; | |
| int32_t count; | |
| } sspan_t; | |
| typedef struct | |
| { | |
| int32_t ambientlight; | |
| int32_t shadelight; | |
| float *plightvec; | |
| } alight_t; | |
| typedef struct bedge_s | |
| { | |
| mvertex_t *v[2]; | |
| struct bedge_s *pnext; | |
| } bedge_t; | |
| typedef struct | |
| { | |
| float fv[3]; | |
| } auxvert_t; | |
| typedef struct clipplane_s | |
| { | |
| vec3_t normal; | |
| float dist; | |
| struct clipplane_s *next; | |
| uint8_t leftedge; | |
| uint8_t rightedge; | |
| uint8_t reserved[2]; | |
| } clipplane_t; | |
| typedef struct btofpoly_s | |
| { | |
| int32_t clipflags; | |
| msurface_t *psurf; | |
| } btofpoly_t; | |
| typedef struct | |
| { | |
| void *pdest; | |
| int16_t *pz; | |
| int32_t count; | |
| uint8_t *ptex; | |
| int32_t sfrac; | |
| int32_t tfrac; | |
| int32_t light; | |
| int32_t zi; | |
| } spanpackage_t; | |
| typedef struct | |
| { | |
| int32_t isflattop; | |
| int32_t numleftedges; | |
| int32_t *pleftedgevert0; | |
| int32_t *pleftedgevert1; | |
| int32_t *pleftedgevert2; | |
| int32_t numrightedges; | |
| int32_t *prightedgevert0; | |
| int32_t *prightedgevert1; | |
| int32_t *prightedgevert2; | |
| } edgetable; | |
| typedef struct | |
| { | |
| int32_t quotient; | |
| int32_t remainder; | |
| } adivtab_t; | |
| typedef struct | |
| { | |
| vrect_t rect; | |
| int32_t width; | |
| int32_t height; | |
| uint8_t *ptexbytes; | |
| int32_t rowbytes; | |
| } rectdesc_t; | |
| typedef struct cachepic_s | |
| { | |
| char name[MAX_QPATH]; | |
| cache_user_t cache; | |
| } cachepic_t; | |
| typedef struct | |
| { | |
| char *name; | |
| int32_t keynum; | |
| } keyname_t; | |
| enum | |
| { | |
| m_none, | |
| m_main, | |
| m_singleplayer, | |
| m_load, | |
| m_save, | |
| m_multiplayer, | |
| m_setup, | |
| m_net, | |
| m_options, | |
| m_video, | |
| m_keys, | |
| m_help, | |
| m_quit, | |
| m_serialconfig, | |
| m_modemconfig, | |
| m_lanconfig, | |
| m_gameoptions, | |
| m_search, | |
| m_slist | |
| } m_state; | |
| typedef struct | |
| { | |
| char *name; | |
| char *description; | |
| } level_t; | |
| typedef struct | |
| { | |
| char *description; | |
| int32_t firstLevel; | |
| int32_t levels; | |
| } episode_t; | |
| static struct | |
| { | |
| uint32_t length; | |
| uint32_t sequence; | |
| uint8_t data[MAX_DATAGRAM]; | |
| } packetBuffer; | |
| static struct | |
| { | |
| double time; | |
| int32_t op; | |
| int32_t session; | |
| } vcrConnect; | |
| static struct | |
| { | |
| double time; | |
| int32_t op; | |
| int32_t session; | |
| int32_t ret; | |
| int32_t len; | |
| } vcrGetMessage; | |
| static struct | |
| { | |
| double time; | |
| int32_t op; | |
| int32_t session; | |
| int32_t r; | |
| } vcrSendMessage; | |
| static struct | |
| { | |
| double time; | |
| int32_t op; | |
| int32_t session; | |
| } next; | |
| typedef struct | |
| { | |
| ddef_t *pcache; | |
| char field[MAX_FIELD_LEN]; | |
| } gefv_cache; | |
| typedef struct | |
| { | |
| int32_t s; | |
| dfunction_t *f; | |
| } prstack_t; | |
| typedef struct | |
| { | |
| int32_t index0; | |
| int32_t index1; | |
| } aedge_t; | |
| typedef enum | |
| { | |
| touchessolid, | |
| drawnode, | |
| nodrawnode | |
| } solidstate_t; | |
| typedef struct | |
| { | |
| float u; | |
| float v; | |
| int32_t ceilv; | |
| } evert_t; | |
| typedef struct | |
| { | |
| char manufacturer; | |
| char version; | |
| char encoding; | |
| char bits_per_pixel; | |
| uint16_t xmin; | |
| uint16_t ymin; | |
| uint16_t xmax; | |
| uint16_t ymax; | |
| uint16_t hres; | |
| uint16_t vres; | |
| unsigned char palette[48]; | |
| char reserved; | |
| char color_planes; | |
| uint16_t bytes_per_line; | |
| uint16_t palette_type; | |
| char filler[58]; | |
| unsigned char data; | |
| } pcx_t; | |
| typedef struct | |
| { | |
| vec3_t boxmins; | |
| vec3_t boxmaxs; | |
| float *mins; | |
| float *maxs; | |
| vec3_t mins2; | |
| vec3_t maxs2; | |
| float *start; | |
| float *end; | |
| trace_t trace; | |
| int32_t type; | |
| edict_t *passedict; | |
| } moveclip_t; | |
| typedef struct areanode_s | |
| { | |
| int32_t axis; | |
| float dist; | |
| struct areanode_s *children[2]; | |
| link_t trigger_edicts; | |
| link_t solid_edicts; | |
| } areanode_t; | |
| typedef struct memblock_s | |
| { | |
| int32_t size; | |
| int32_t tag; | |
| int32_t id; | |
| struct memblock_s *next; | |
| struct memblock_s *prev; | |
| int32_t pad; | |
| } memblock_t; | |
| typedef struct | |
| { | |
| int32_t size; | |
| memblock_t blocklist; | |
| memblock_t *rover; | |
| } memzone_t; | |
| typedef struct | |
| { | |
| int32_t sentinal; | |
| int32_t size; | |
| char name[8]; | |
| } hunk_t; | |
| typedef struct cache_system_s | |
| { | |
| int32_t size; | |
| cache_user_t *user; | |
| char name[16]; | |
| struct cache_system_s *prev; | |
| struct cache_system_s *next; | |
| struct cache_system_s *lru_prev; | |
| struct cache_system_s *lru_next; | |
| } cache_system_t; | |
| void VID_LockBuffer(void); | |
| void VID_UnlockBuffer(void); | |
| void SZ_Alloc(sizebuf_t *buf, int32_t startsize); | |
| void SZ_Free(sizebuf_t *buf); | |
| void SZ_Clear(sizebuf_t *buf); | |
| void *SZ_GetSpace(sizebuf_t *buf, int32_t length); | |
| void SZ_Write(sizebuf_t *buf, void *data, int32_t length); | |
| void SZ_Print(sizebuf_t *buf, char *data); | |
| void ClearLink(link_t *l); | |
| void RemoveLink(link_t *l); | |
| void InsertLinkBefore(link_t *l, link_t *before); | |
| void InsertLinkAfter(link_t *l, link_t *after); | |
| void MSG_WriteChar(sizebuf_t *sb, int32_t c); | |
| void MSG_WriteByte(sizebuf_t *sb, int32_t c); | |
| void MSG_WriteShort(sizebuf_t *sb, int32_t c); | |
| void MSG_WriteLong(sizebuf_t *sb, int32_t c); | |
| void MSG_WriteFloat(sizebuf_t *sb, float f); | |
| void MSG_WriteString(sizebuf_t *sb, char *s); | |
| void MSG_WriteCoord(sizebuf_t *sb, float f); | |
| void MSG_WriteAngle(sizebuf_t *sb, float f); | |
| void MSG_BeginReading(void); | |
| int32_t MSG_ReadChar(void); | |
| int32_t MSG_ReadByte(void); | |
| int32_t MSG_ReadShort(void); | |
| int32_t MSG_ReadLong(void); | |
| float MSG_ReadFloat(void); | |
| char *MSG_ReadString(void); | |
| float MSG_ReadCoord(void); | |
| float MSG_ReadAngle(void); | |
| char *COM_Parse(char *data); | |
| int32_t COM_CheckParm(char *parm); | |
| void COM_Init(char *path); | |
| void COM_InitArgv(int32_t argc, char **argv); | |
| char *COM_SkipPath(char *pathname); | |
| void COM_StripExtension(char *in, char *out); | |
| void COM_FileBase(char *in, char *out); | |
| void COM_DefaultExtension(char *path, char *extension); | |
| char *va(char *format, ...); | |
| void COM_WriteFile(char *filename, void *data, int32_t len); | |
| int32_t COM_OpenFile(char *filename, int32_t *hndl); | |
| int32_t COM_FOpenFile(char *filename, FILE **file); | |
| void COM_CloseFile(int32_t h); | |
| uint8_t *COM_LoadStackFile(char *path, void *buffer, int32_t bufsize); | |
| uint8_t *COM_LoadTempFile(char *path); | |
| uint8_t *COM_LoadHunkFile(char *path); | |
| void COM_LoadCacheFile(char *path, struct cache_user_s *cu); | |
| void VID_SetPalette(unsigned char *palette); | |
| void VID_ShiftPalette(unsigned char *palette); | |
| void VID_Init(unsigned char *palette); | |
| void VID_Shutdown(void); | |
| void VID_Update(vrect_t *rects); | |
| int32_t VID_SetMode(int32_t modenum, unsigned char *palette); | |
| void VID_HandlePause(bool pause); | |
| int32_t Sys_FileOpenRead(char *path, int32_t *hndl); | |
| int32_t Sys_FileOpenWrite(char *path); | |
| void Sys_FileClose(int32_t handle); | |
| void Sys_FileSeek(int32_t handle, int32_t position); | |
| int32_t Sys_FileRead(int32_t handle, void *dest, int32_t count); | |
| int32_t Sys_FileWrite(int32_t handle, void *data, int32_t count); | |
| int32_t Sys_FileTime(char *path); | |
| void Sys_mkdir(char *path); | |
| void Sys_DebugLog(char *file, char *fmt, ...); | |
| void Sys_Error(char *error, ...); | |
| void Sys_Printf(char *fmt, ...); | |
| void Sys_Quit(void); | |
| double Sys_FloatTime(void); | |
| char *Sys_ConsoleInput(void); | |
| void Sys_SendKeyEvents(void); | |
| void Sys_LowFPPrecision(void); | |
| void Sys_HighFPPrecision(void); | |
| void Sys_SetFPCW(void); | |
| void Memory_Init(void *buf, int32_t size); | |
| void Z_Free(void *ptr); | |
| void *Z_Malloc(int32_t size); | |
| void *Z_TagMalloc(int32_t size, int32_t tag); | |
| void Z_DumpHeap(void); | |
| void Z_CheckHeap(void); | |
| int32_t Z_FreeMemory(void); | |
| void *Hunk_Alloc(int32_t size); | |
| void *Hunk_AllocName(int32_t size, char *name); | |
| void *Hunk_HighAllocName(int32_t size, char *name); | |
| int32_t Hunk_LowMark(void); | |
| void Hunk_FreeToLowMark(int32_t mark); | |
| int32_t Hunk_HighMark(void); | |
| void Hunk_FreeToHighMark(int32_t mark); | |
| void *Hunk_TempAlloc(int32_t size); | |
| void Hunk_Check(void); | |
| void Cache_Flush(void); | |
| void *Cache_Check(cache_user_t *c); | |
| void Cache_Free(cache_user_t *c); | |
| void *Cache_Alloc(cache_user_t *c, int32_t size, char *name); | |
| void Cache_Report(void); | |
| void VectorMA(vec3_t veca, float scale, vec3_t vecb, vec3_t vecc); | |
| vec_t _DotProduct(vec3_t v1, vec3_t v2); | |
| void _VectorSubtract(vec3_t veca, vec3_t vecb, vec3_t out); | |
| void _VectorAdd(vec3_t veca, vec3_t vecb, vec3_t out); | |
| void _VectorCopy(vec3_t in, vec3_t out); | |
| int32_t VectorCompare(vec3_t v1, vec3_t v2); | |
| vec_t Length(vec3_t v); | |
| void CrossProduct(vec3_t v1, vec3_t v2, vec3_t cross); | |
| float VectorNormalize(vec3_t v); | |
| void VectorInverse(vec3_t v); | |
| void VectorScale(vec3_t in, vec_t scale, vec3_t out); | |
| int32_t Q_log2(int32_t val); | |
| void R_ConcatRotations(float in1[3][3], float in2[3][3], float out[3][3]); | |
| void R_ConcatTransforms(float in1[3][4], float in2[3][4], float out[3][4]); | |
| void FloorDivMod(double numer, double denom, int32_t *quotient, int32_t *rem); | |
| fixed16_t Invert24To16(fixed16_t val); | |
| int32_t GreatestCommonDivisor(int32_t i1, int32_t i2); | |
| void AngleVectors(vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); | |
| int32_t BoxOnPlaneSide(vec3_t emins, vec3_t emaxs, struct mplane_s *plane); | |
| float anglemod(float a); | |
| void W_LoadWadFile(char *filename); | |
| void W_CleanupName(char *in, char *out); | |
| lumpinfo_t *W_GetLumpinfo(char *name); | |
| void *W_GetLumpName(char *name); | |
| void *W_GetLumpNum(int32_t num); | |
| void SwapPic(qpic_t *pic); | |
| void Draw_Init(void); | |
| void Draw_Character(int32_t x, int32_t y, int32_t num); | |
| void Draw_DebugChar(char num); | |
| void Draw_Pic(int32_t x, int32_t y, qpic_t *pic); | |
| void Draw_TransPic(int32_t x, int32_t y, qpic_t *pic); | |
| void Draw_TransPicTranslate(int32_t x, int32_t y, qpic_t *pic, uint8_t *translation); | |
| void Draw_ConsoleBackground(int32_t lines); | |
| void Draw_BeginDisc(void); | |
| void Draw_EndDisc(void); | |
| void Draw_TileClear(int32_t x, int32_t y, int32_t w, int32_t h); | |
| void Draw_Fill(int32_t x, int32_t y, int32_t w, int32_t h, int32_t c); | |
| void Draw_FadeScreen(void); | |
| void Draw_String(int32_t x, int32_t y, char *str); | |
| qpic_t *Draw_PicFromWad(char *name); | |
| qpic_t *Draw_CachePic(char *path); | |
| void Cvar_RegisterVariable(cvar_t *variable); | |
| void Cvar_Set(char *var_name, char *value); | |
| void Cvar_SetValue(char *var_name, float value); | |
| float Cvar_VariableValue(char *var_name); | |
| char *Cvar_VariableString(char *var_name); | |
| char *Cvar_CompleteVariable(char *partial); | |
| bool Cvar_Command(void); | |
| void Cvar_WriteVariables(FILE *f); | |
| cvar_t *Cvar_FindVar(char *var_name); | |
| void SCR_Init(void); | |
| void SCR_UpdateScreen(void); | |
| void SCR_SizeUp(void); | |
| void SCR_SizeDown(void); | |
| void SCR_BringDownConsole(void); | |
| void SCR_CenterPrint(char *str); | |
| void SCR_BeginLoadingPlaque(void); | |
| void SCR_EndLoadingPlaque(void); | |
| int32_t SCR_ModalMessage(char *text); | |
| void SCR_UpdateWholeScreen(void); | |
| qsocket_t *NET_NewQSocket(void); | |
| void NET_FreeQSocket(qsocket_t *); | |
| double SetNetTime(void); | |
| void NET_Init(void); | |
| void NET_Shutdown(void); | |
| struct qsocket_s *NET_CheckNewConnections(void); | |
| struct qsocket_s *NET_Connect(char *host); | |
| bool NET_CanSendMessage(qsocket_t *sock); | |
| int32_t NET_GetMessage(struct qsocket_s *sock); | |
| int32_t NET_SendMessage(struct qsocket_s *sock, sizebuf_t *data); | |
| int32_t NET_SendUnreliableMessage(struct qsocket_s *sock, sizebuf_t *data); | |
| int32_t NET_SendToAll(sizebuf_t *data, int32_t blocktime); | |
| void NET_Close(struct qsocket_s *sock); | |
| void NET_Poll(void); | |
| void SchedulePollProcedure(PollProcedure *pp, double timeOffset); | |
| void NET_Slist_f(void); | |
| void Cbuf_Init(void); | |
| void Cbuf_AddText(char *text); | |
| void Cbuf_InsertText(char *text); | |
| void Cbuf_Execute(void); | |
| void Cmd_Init(void); | |
| void Cmd_AddCommand(char *cmd_name, xcommand_t function); | |
| bool Cmd_Exists(char *cmd_name); | |
| char *Cmd_CompleteCommand(char *partial); | |
| int32_t Cmd_Argc(void); | |
| char *Cmd_Argv(int32_t arg); | |
| char *Cmd_Args(void); | |
| int32_t Cmd_CheckParm(char *parm); | |
| void Cmd_TokenizeString(char *text); | |
| void Cmd_ExecuteString(char *text, cmd_source_t src); | |
| void Cmd_ForwardToServer(void); | |
| void Cmd_Print(char *text); | |
| void Sbar_Init(void); | |
| void Sbar_Changed(void); | |
| void Sbar_Draw(void); | |
| void Sbar_IntermissionOverlay(void); | |
| void Sbar_FinaleOverlay(void); | |
| void S_Init(void); | |
| void S_Startup(void); | |
| void S_Shutdown(void); | |
| void S_StartSound(int32_t entnum, int32_t entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation); | |
| void S_StaticSound(sfx_t *sfx, vec3_t origin, float vol, float attenuation); | |
| void S_StopSound(int32_t entnum, int32_t entchannel); | |
| void S_StopAllSounds(bool clear); | |
| void S_ClearBuffer(void); | |
| void S_Update(vec3_t origin, vec3_t v_forward, vec3_t v_right, vec3_t v_up); | |
| void S_ExtraUpdate(void); | |
| sfx_t *S_PrecacheSound(char *sample); | |
| void S_TouchSound(char *sample); | |
| void S_ClearPrecache(void); | |
| void S_BeginPrecaching(void); | |
| void S_EndPrecaching(void); | |
| void S_PaintChannels(int32_t endtime); | |
| void S_InitPaintChannels(void); | |
| channel_t *SND_PickChannel(int32_t entnum, int32_t entchannel); | |
| void SND_Spatialize(channel_t *ch); | |
| bool SNDDMA_Init(void); | |
| int32_t SNDDMA_GetDMAPos(void); | |
| void SNDDMA_Shutdown(void); | |
| void S_LocalSound(char *s); | |
| sfxcache_t *S_LoadSound(sfx_t *s); | |
| wavinfo_t GetWavinfo(char *name, uint8_t *wav, int32_t wavlength); | |
| void SND_InitScaletable(void); | |
| void SNDDMA_Submit(void); | |
| void S_AmbientOff(void); | |
| void S_AmbientOn(void); | |
| void R_Init(void); | |
| void R_InitTextures(void); | |
| void R_InitEfrags(void); | |
| void R_RenderView(void); | |
| void R_ViewChanged(vrect_t *pvrect, int32_t lineadj, float aspect); | |
| void R_InitSky(struct texture_s *mt); | |
| void R_AddEfrags(entity_t *ent); | |
| void R_RemoveEfrags(entity_t *ent); | |
| void R_NewMap(void); | |
| void R_ParseParticleEffect(void); | |
| void R_RunParticleEffect(vec3_t org, vec3_t dir, int32_t color, int32_t count); | |
| void R_RocketTrail(vec3_t start, vec3_t end, int32_t type); | |
| void R_EntityParticles(entity_t *ent); | |
| void R_BlobExplosion(vec3_t org); | |
| void R_ParticleExplosion(vec3_t org); | |
| void R_ParticleExplosion2(vec3_t org, int32_t colorStart, int32_t colorLength); | |
| void R_LavaSplash(vec3_t org); | |
| void R_TeleportSplash(vec3_t org); | |
| void R_PushDlights(void); | |
| int32_t D_SurfaceCacheForRes(int32_t width, int32_t height); | |
| void D_FlushCaches(void); | |
| void D_DeleteSurfaceCache(void); | |
| void D_InitCaches(void *buffer, int32_t size); | |
| void R_SetVrect(vrect_t *pvrect, vrect_t *pvrectin, int32_t lineadj); | |
| dlight_t *CL_AllocDlight(int32_t key); | |
| void CL_DecayLights(void); | |
| void CL_Init(void); | |
| void CL_EstablishConnection(char *host); | |
| void CL_Signon1(void); | |
| void CL_Signon2(void); | |
| void CL_Signon3(void); | |
| void CL_Signon4(void); | |
| void CL_Disconnect(void); | |
| void CL_Disconnect_f(void); | |
| void CL_NextDemo(void); | |
| void CL_InitInput(void); | |
| void CL_SendCmd(void); | |
| void CL_SendMove(usercmd_t *cmd); | |
| void CL_ParseTEnt(void); | |
| void CL_UpdateTEnts(void); | |
| void CL_ClearState(void); | |
| int32_t CL_ReadFromServer(void); | |
| void CL_WriteToServer(usercmd_t *cmd); | |
| void CL_BaseMove(usercmd_t *cmd); | |
| float CL_KeyState(kbutton_t *key); | |
| char *Key_KeynumToString(int32_t keynum); | |
| void CL_StopPlayback(void); | |
| int32_t CL_GetMessage(void); | |
| void CL_Stop_f(void); | |
| void CL_Record_f(void); | |
| void CL_PlayDemo_f(void); | |
| void CL_TimeDemo_f(void); | |
| void CL_ParseServerMessage(void); | |
| void CL_NewTranslation(int32_t slot); | |
| void V_StartPitchDrift(void); | |
| void V_StopPitchDrift(void); | |
| void V_RenderView(void); | |
| void V_UpdatePalette(void); | |
| void V_Register(void); | |
| void V_ParseDamage(void); | |
| void V_SetContentsColor(int32_t contents); | |
| void CL_InitTEnts(void); | |
| void CL_SignonReply(void); | |
| void PR_Init(void); | |
| void PR_ExecuteProgram(func_t fnum); | |
| void PR_LoadProgs(void); | |
| void PR_Profile_f(void); | |
| edict_t *ED_Alloc(void); | |
| void ED_Free(edict_t *ed); | |
| char *ED_NewString(char *string); | |
| void ED_Print(edict_t *ed); | |
| void ED_Write(FILE *f, edict_t *ed); | |
| char *ED_ParseEdict(char *data, edict_t *ent); | |
| void ED_WriteGlobals(FILE *f); | |
| void ED_ParseGlobals(char *data); | |
| void ED_LoadFromFile(char *data); | |
| edict_t *EDICT_NUM(int32_t n); | |
| int32_t NUM_FOR_EDICT(edict_t *e); | |
| void PR_RunError(char *error, ...); | |
| void ED_PrintEdicts(void); | |
| void ED_PrintNum(int32_t ent); | |
| eval_t *GetEdictFieldValue(edict_t *ed, char *field); | |
| void SV_Init(void); | |
| void SV_StartParticle(vec3_t org, vec3_t dir, int32_t color, int32_t count); | |
| void SV_StartSound(edict_t *entity, int32_t channel, char *sample, int32_t volume, float attenuation); | |
| void SV_DropClient(bool crash); | |
| void SV_SendClientMessages(void); | |
| void SV_ClearDatagram(void); | |
| int32_t SV_ModelIndex(char *name); | |
| void SV_SetIdealPitch(void); | |
| void SV_AddUpdates(void); | |
| void SV_ClientThink(void); | |
| void SV_AddClientToServer(struct qsocket_s *ret); | |
| void SV_ClientPrintf(char *fmt, ...); | |
| void SV_BroadcastPrintf(char *fmt, ...); | |
| void SV_Physics(void); | |
| bool SV_CheckBottom(edict_t *ent); | |
| bool SV_movestep(edict_t *ent, vec3_t move, bool relink); | |
| void SV_WriteClientdataToMessage(edict_t *ent, sizebuf_t *msg); | |
| void SV_MoveToGoal(void); | |
| void SV_CheckForNewClients(void); | |
| void SV_RunClients(void); | |
| void SV_SaveSpawnparms(); | |
| void SV_SpawnServer(char *server); | |
| void Mod_Init(void); | |
| void Mod_ClearAll(void); | |
| model_t *Mod_ForName(char *name, bool crash); | |
| void *Mod_Extradata(model_t *mod); | |
| void Mod_TouchModel(char *name); | |
| mleaf_t *Mod_PointInLeaf(float *p, model_t *model); | |
| uint8_t *Mod_LeafPVS(mleaf_t *leaf, model_t *model); | |
| void D_Aff8Patch(void *pcolormap); | |
| void D_BeginDirectRect(int32_t x, int32_t y, uint8_t *pbitmap, int32_t width, int32_t height); | |
| void D_DisableBackBufferAccess(void); | |
| void D_EndDirectRect(int32_t x, int32_t y, int32_t width, int32_t height); | |
| void D_PolysetDraw(void); | |
| void D_PolysetDrawFinalVerts(finalvert_t *fv, int32_t numverts); | |
| void D_DrawParticle(particle_t *pparticle); | |
| void D_DrawPoly(void); | |
| void D_DrawSprite(void); | |
| void D_DrawSurfaces(void); | |
| void D_DrawZPoint(void); | |
| void D_EnableBackBufferAccess(void); | |
| void D_EndParticles(void); | |
| void D_Init(void); | |
| void D_ViewChanged(void); | |
| void D_SetupFrame(void); | |
| void D_StartParticles(void); | |
| void D_TurnZOn(void); | |
| void D_WarpScreen(void); | |
| void D_FillRect(const vrect_t *vrect, int32_t color); | |
| void D_DrawRect(void); | |
| void D_UpdateRects(vrect_t *prect); | |
| void D_PolysetUpdateTables(void); | |
| void R_DrawSurface(void); | |
| void R_GenTile(msurface_t *psurf, void *pdest); | |
| void IN_Init(void); | |
| void IN_Shutdown(void); | |
| void IN_Commands(void); | |
| void IN_Move(usercmd_t *cmd); | |
| void IN_ClearStates(void); | |
| void SV_ClearWorld(void); | |
| void SV_UnlinkEdict(edict_t *ent); | |
| void SV_LinkEdict(edict_t *ent, bool touch_triggers); | |
| int32_t SV_PointContents(vec3_t p); | |
| int32_t SV_TruePointContents(vec3_t p); | |
| edict_t *SV_TestEntityPosition(edict_t *ent); | |
| trace_t SV_Move(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int32_t type, edict_t *passedict); | |
| void Key_Event(int32_t key, bool down); | |
| void Key_Init(void); | |
| void Key_WriteBindings(FILE *f); | |
| void Key_SetBinding(int32_t keynum, char *binding); | |
| void Key_ClearStates(void); | |
| void Con_DrawCharacter(int32_t cx, int32_t line, int32_t num); | |
| void Con_CheckResize(void); | |
| void Con_Init(void); | |
| void Con_DrawConsole(int32_t lines, bool drawinput); | |
| void Con_Print(char *txt); | |
| void Con_Printf(char *fmt, ...); | |
| void Con_DPrintf(char *fmt, ...); | |
| void Con_SafePrintf(char *fmt, ...); | |
| void Con_Clear_f(void); | |
| void Con_DrawNotify(void); | |
| void Con_ClearNotify(void); | |
| void Con_ToggleConsole_f(void); | |
| void Con_NotifyBox(char *text); | |
| void V_Init(void); | |
| float V_CalcRoll(vec3_t angles, vec3_t velocity); | |
| void M_Init(void); | |
| void M_Keydown(int32_t key); | |
| void M_Draw(void); | |
| void M_ToggleMenu_f(void); | |
| void CRC_Init(uint16_t *crcvalue); | |
| void CRC_ProcessByte(uint16_t *crcvalue, uint8_t data); | |
| uint16_t CRC_Value(uint16_t crcvalue); | |
| int32_t CDAudio_Init(void); | |
| void CDAudio_Play(uint8_t track, bool looping); | |
| void CDAudio_Stop(void); | |
| void CDAudio_Pause(void); | |
| void CDAudio_Resume(void); | |
| void CDAudio_Shutdown(void); | |
| void CDAudio_Update(void); | |
| void Host_ClearMemory(void); | |
| void Host_ServerFrame(void); | |
| void Host_InitCommands(void); | |
| void Host_Init(quakeparms_t *parms); | |
| void Host_Shutdown(void); | |
| void Host_Error(char *error, ...); | |
| void Host_EndGame(char *message, ...); | |
| void Host_Frame(float time); | |
| void Host_Quit_f(void); | |
| void Host_ClientCommands(char *fmt, ...); | |
| void Host_ShutdownServer(bool crash); | |
| void Chase_Init(void); | |
| void Chase_Reset(void); | |
| void Chase_Update(void); | |
| static void TraceLine(vec3_t start, vec3_t end, vec3_t impact); | |
| static void CL_FinishTimeDemo(void); | |
| static void CL_WriteDemoMessage(void); | |
| static void KeyDown(kbutton_t *b); | |
| static void KeyUp(kbutton_t *b); | |
| static void IN_KLookDown(void); | |
| static void IN_KLookUp(void); | |
| static void IN_MLookDown(void); | |
| static void IN_MLookUp(void); | |
| static void IN_UpDown(void); | |
| static void IN_UpUp(void); | |
| static void IN_DownDown(void); | |
| static void IN_DownUp(void); | |
| static void IN_LeftDown(void); | |
| static void IN_LeftUp(void); | |
| static void IN_RightDown(void); | |
| static void IN_RightUp(void); | |
| static void IN_ForwardDown(void); | |
| static void IN_ForwardUp(void); | |
| static void IN_BackDown(void); | |
| static void IN_BackUp(void); | |
| static void IN_LookupDown(void); | |
| static void IN_LookupUp(void); | |
| static void IN_LookdownDown(void); | |
| static void IN_LookdownUp(void); | |
| static void IN_MoveleftDown(void); | |
| static void IN_MoveleftUp(void); | |
| static void IN_MoverightDown(void); | |
| static void IN_MoverightUp(void); | |
| static void IN_SpeedDown(void); | |
| static void IN_SpeedUp(void); | |
| static void IN_StrafeDown(void); | |
| static void IN_StrafeUp(void); | |
| static void IN_AttackDown(void); | |
| static void IN_AttackUp(void); | |
| static void IN_UseDown(void); | |
| static void IN_UseUp(void); | |
| static void IN_JumpDown(void); | |
| static void IN_JumpUp(void); | |
| static void IN_Impulse(void); | |
| static void CL_AdjustAngles(void); | |
| static void CL_PrintEntities_f(void); | |
| static void SetPal(int32_t i); | |
| static float CL_LerpPoint(void); | |
| static void CL_RelinkEntities(void); | |
| static entity_t *CL_EntityNum(int32_t num); | |
| static void CL_ParseStartSoundPacket(void); | |
| static void CL_KeepaliveMessage(void); | |
| static void CL_ParseServerInfo(void); | |
| static void CL_ParseUpdate(int32_t bits); | |
| static void CL_ParseBaseline(entity_t *ent); | |
| static void CL_ParseClientdata(int32_t bits); | |
| static void CL_ParseStatic(void); | |
| static void CL_ParseStaticSound(void); | |
| static void CL_ParseBeam(model_t *m); | |
| static entity_t *CL_NewTempEntity(void); | |
| static void Cmd_Wait_f(void); | |
| static void Cmd_StuffCmds_f(void); | |
| static void Cmd_Exec_f(void); | |
| static void Cmd_Echo_f(void); | |
| static char *CopyString(char *in); | |
| static void Cmd_Alias_f(void); | |
| static void COM_InitFilesystem(void); | |
| static char *COM_FileExtension(char *in); | |
| static void COM_Path_f(void); | |
| void COM_Init(char *basedir); | |
| static void COM_CreatePath(char *path); | |
| static void COM_CopyFile(char *netpath, char *cachepath); | |
| static int32_t COM_FindFile(char *filename, int32_t *handle, FILE **file); | |
| int32_t COM_OpenFile(char *filename, int32_t *handle); | |
| static uint8_t *COM_LoadFile(char *path, int32_t usehunk); | |
| static pack_t *COM_LoadPackFile(char *packfile); | |
| static void COM_AddGameDirectory(char *dir); | |
| extern void M_Menu_Main_f(void); | |
| static void Con_MessageMode_f(void); | |
| static void Con_MessageMode2_f(void); | |
| static void Con_Linefeed(void); | |
| static void Con_DebugLog(char *file, char *fmt, ...); | |
| static void Con_DrawInput(void); | |
| extern void R_DrawLine(polyvert_t *polyvert0, polyvert_t *polyvert1); | |
| extern void TransformVector(vec3_t in, vec3_t out); | |
| extern void SetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv, fixed8_t endvertu, fixed8_t endvertv); | |
| extern void R_MakeSky(void); | |
| void D_DrawSpans8(espan_t *pspans); | |
| void D_DrawSpans16(espan_t *pspans); | |
| void D_DrawZSpans(espan_t *pspans); | |
| void Turbulent8(espan_t *pspan); | |
| void D_SpriteDrawSpans(sspan_t *pspan); | |
| void D_DrawSkyScans8(espan_t *pspan); | |
| void D_DrawSkyScans16(espan_t *pspan); | |
| void R_ShowSubDiv(void); | |
| surfcache_t *D_CacheSurface(msurface_t *surface, int32_t miplevel); | |
| extern int32_t D_MipLevelForScale(float scale); | |
| extern void R_RotateBmodel(void); | |
| extern void R_TransformFrustum(void); | |
| static void D_DrawSolidSurface(surf_t *surf, int32_t color); | |
| static void D_CalcGradients(msurface_t *pface); | |
| void D_FillRect(const vrect_t *vrect, const int32_t color); | |
| void R_RenderWorld(void); | |
| void R_ClearPolyList(void); | |
| void R_DrawPolyList(void); | |
| void R_DrawSprite(void); | |
| void R_RenderFace(msurface_t *fa, int32_t clipflags); | |
| void R_RenderPoly(msurface_t *fa, int32_t clipflags); | |
| void R_RenderBmodelFace(bedge_t *pedges, msurface_t *psurf); | |
| void R_TransformPlane(mplane_t *p, float *normal, float *dist); | |
| void R_SetSkyFrame(void); | |
| void R_DrawSurfaceBlock16(void); | |
| void R_DrawSurfaceBlock8(void); | |
| texture_t *R_TextureAnimation(texture_t *base); | |
| void R_GenSkyTile(void *pdest); | |
| void R_GenSkyTile16(void *pdest); | |
| void R_Surf8Patch(void); | |
| void R_Surf16Patch(void); | |
| void R_DrawSubmodelPolygons(model_t *pmodel, int32_t clipflags); | |
| void R_DrawSolidClippedSubmodelPolygons(model_t *pmodel); | |
| void R_AddPolygonEdges(emitpoint_t *pverts, int32_t numverts, int32_t miplevel); | |
| surf_t *R_GetSurf(void); | |
| void R_AliasDrawModel(alight_t *plighting); | |
| void R_BeginEdgeFrame(void); | |
| void R_ScanEdges(void); | |
| void R_InsertNewEdges(edge_t *edgestoadd, edge_t *edgelist); | |
| void R_StepActiveU(edge_t *pedge); | |
| void R_RemoveEdges(edge_t *pedge); | |
| extern void R_Surf8Start(void); | |
| extern void R_Surf8End(void); | |
| extern void R_Surf16Start(void); | |
| extern void R_Surf16End(void); | |
| extern void R_EdgeCodeStart(void); | |
| extern void R_EdgeCodeEnd(void); | |
| void R_InitTurb(void); | |
| void R_ZDrawSubmodelPolys(model_t *clmodel); | |
| bool R_AliasCheckBBox(void); | |
| void R_DrawParticles(void); | |
| void R_InitParticles(void); | |
| void R_ClearParticles(void); | |
| void R_ReadPointFile_f(void); | |
| void R_SurfacePatch(void); | |
| void R_AliasClipTriangle(mtriangle_t *ptri); | |
| void R_StoreEfrags(efrag_t **ppefrag); | |
| void R_TimeRefresh_f(void); | |
| void R_TimeGraph(void); | |
| void R_PrintAliasStats(void); | |
| void R_PrintTimes(void); | |
| void R_PrintDSpeeds(void); | |
| void R_AnimateLight(void); | |
| int32_t R_LightPoint(vec3_t p); | |
| void R_SetupFrame(void); | |
| void R_cshift_f(void); | |
| void R_EmitEdge(mvertex_t *pv0, mvertex_t *pv1); | |
| void R_ClipEdge(mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip); | |
| void R_SplitEntityOnNode2(mnode_t *node); | |
| void R_MarkLights(dlight_t *light, int32_t bit, mnode_t *node); | |
| static void D_PolysetDrawSpans8(spanpackage_t *pspanpackage); | |
| static void D_PolysetCalcGradients(int32_t skinwidth); | |
| static void D_DrawSubdiv(void); | |
| static void D_DrawNonSubdiv(void); | |
| static void D_PolysetRecursiveTriangle(int32_t *p1, int32_t *p2, int32_t *p3); | |
| static void D_PolysetSetEdgeTable(void); | |
| static void D_RasterizeAliasPolySmooth(void); | |
| static void D_PolysetScanLeftEdge(int32_t height); | |
| static void D_PolysetRecursiveTriangle(int32_t *lp1, int32_t *lp2, int32_t *lp3); | |
| static void D_PolysetSetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv, fixed8_t endvertu, fixed8_t endvertv); | |
| static void D_PolysetFillSpans8(spanpackage_t *pspanpackage); | |
| static void D_DrawTurbulent8Span(void); | |
| void D_DrawSpans8(espan_t *pspan); | |
| void D_DrawZSpans(espan_t *pspan); | |
| static void D_Sky_uv_To_st(int32_t u, int32_t v, fixed16_t *s, fixed16_t *t); | |
| static void D_SpriteScanLeftEdge(void); | |
| static void D_SpriteScanRightEdge(void); | |
| static void D_SpriteCalculateGradients(void); | |
| void D_CheckCacheGuard(void); | |
| void D_ClearCacheGuard(void); | |
| surfcache_t *D_SCAlloc(int32_t width, int32_t size); | |
| void D_SCDump(void); | |
| int32_t MaskForNum(int32_t num); | |
| int32_t D_log2(int32_t num); | |
| void Draw_CharToConback(int32_t num, uint8_t *dest); | |
| void R_DrawRect8(vrect_t *prect, int32_t rowbytes, uint8_t *psrc, int32_t transparent); | |
| void R_DrawRect16(vrect_t *prect, int32_t rowbytes, uint8_t *psrc, int32_t transparent); | |
| void Host_FindMaxClients(void); | |
| void Host_InitLocal(void); | |
| void Host_WriteConfiguration(void); | |
| bool Host_FilterTime(float time); | |
| void Host_GetConsoleCommands(void); | |
| void _Host_Frame(float time); | |
| void Host_InitVCR(quakeparms_t *parms); | |
| void Mod_Print(void); | |
| extern void M_Menu_Quit_f(void); | |
| void Host_Status_f(void); | |
| void Host_God_f(void); | |
| void Host_Notarget_f(void); | |
| void Host_Noclip_f(void); | |
| void Host_Fly_f(void); | |
| void Host_Ping_f(void); | |
| void Host_Map_f(void); | |
| void Host_Changelevel_f(void); | |
| void Host_Restart_f(void); | |
| void Host_Reconnect_f(void); | |
| void Host_Connect_f(void); | |
| void Host_SavegameComment(char *text); | |
| void Host_Savegame_f(void); | |
| void Host_Loadgame_f(void); | |
| void Host_Name_f(void); | |
| void Host_Version_f(void); | |
| void Host_Say(bool teamonly); | |
| void Host_Say_f(void); | |
| void Host_Say_Team_f(void); | |
| void Host_Tell_f(void); | |
| void Host_Color_f(void); | |
| void Host_Kill_f(void); | |
| void Host_Pause_f(void); | |
| void Host_PreSpawn_f(void); | |
| void Host_Spawn_f(void); | |
| void Host_Begin_f(void); | |
| void Host_Kick_f(void); | |
| void Host_Give_f(void); | |
| edict_t *FindViewthing(void); | |
| void Host_Viewmodel_f(void); | |
| void Host_Viewframe_f(void); | |
| void PrintFrameName(model_t *m, int32_t frame); | |
| void Host_Viewnext_f(void); | |
| void Host_Viewprev_f(void); | |
| void Host_Startdemos_f(void); | |
| void Host_Demos_f(void); | |
| void Host_Stopdemo_f(void); | |
| void Key_Console(int32_t key); | |
| void Key_Message(int32_t key); | |
| int32_t Key_StringToKeynum(char *str); | |
| void Key_Unbind_f(void); | |
| void Key_Unbindall_f(void); | |
| void Key_Bind_f(void); | |
| void ProjectPointOnPlane(vec3_t dst, const vec3_t p, const vec3_t normal); | |
| void PerpendicularVector(vec3_t dst, const vec3_t src); | |
| void RotatePointAroundVector(vec3_t dst, const vec3_t dir, const vec3_t point, float degrees); | |
| void BOPS_Error(void); | |
| int32_t BoxOnPlaneSide(vec3_t emins, vec3_t emaxs, mplane_t *p); | |
| double sqrt(double x); | |
| void M_Menu_SinglePlayer_f(void); | |
| void M_Menu_Load_f(void); | |
| void M_Menu_Save_f(void); | |
| void M_Menu_MultiPlayer_f(void); | |
| void M_Menu_Setup_f(void); | |
| void M_Menu_Net_f(void); | |
| void M_Menu_Options_f(void); | |
| void M_Menu_Keys_f(void); | |
| void M_Menu_Video_f(void); | |
| void M_Menu_Help_f(void); | |
| void M_Menu_SerialConfig_f(void); | |
| void M_Menu_ModemConfig_f(void); | |
| void M_Menu_LanConfig_f(void); | |
| void M_Menu_GameOptions_f(void); | |
| void M_Menu_Search_f(void); | |
| void M_Menu_ServerList_f(void); | |
| void M_Main_Draw(void); | |
| void M_SinglePlayer_Draw(void); | |
| void M_Load_Draw(void); | |
| void M_Save_Draw(void); | |
| void M_MultiPlayer_Draw(void); | |
| void M_Setup_Draw(void); | |
| void M_Net_Draw(void); | |
| void M_Options_Draw(void); | |
| void M_Keys_Draw(void); | |
| void M_Video_Draw(void); | |
| void M_Help_Draw(void); | |
| void M_Quit_Draw(void); | |
| void M_SerialConfig_Draw(void); | |
| void M_ModemConfig_Draw(void); | |
| void M_LanConfig_Draw(void); | |
| void M_GameOptions_Draw(void); | |
| void M_Search_Draw(void); | |
| void M_ServerList_Draw(void); | |
| void M_Main_Key(int32_t key); | |
| void M_SinglePlayer_Key(int32_t key); | |
| void M_Load_Key(int32_t key); | |
| void M_Save_Key(int32_t key); | |
| void M_MultiPlayer_Key(int32_t key); | |
| void M_Setup_Key(int32_t key); | |
| void M_Net_Key(int32_t key); | |
| void M_Options_Key(int32_t key); | |
| void M_Keys_Key(int32_t key); | |
| void M_Video_Key(int32_t key); | |
| void M_Help_Key(int32_t key); | |
| void M_Quit_Key(int32_t key); | |
| void M_SerialConfig_Key(int32_t key); | |
| void M_ModemConfig_Key(int32_t key); | |
| void M_LanConfig_Key(int32_t key); | |
| void M_GameOptions_Key(int32_t key); | |
| void M_Search_Key(int32_t key); | |
| void M_ServerList_Key(int32_t key); | |
| void M_ConfigureNetSubsystem(void); | |
| void M_DrawCharacter(int32_t cx, int32_t line, int32_t num); | |
| void M_Print(int32_t cx, int32_t cy, char *str); | |
| void M_PrintWhite(int32_t cx, int32_t cy, char *str); | |
| void M_DrawTransPic(int32_t x, int32_t y, qpic_t *pic); | |
| void M_DrawPic(int32_t x, int32_t y, qpic_t *pic); | |
| void M_BuildTranslationTable(int32_t top, int32_t bottom); | |
| void M_DrawTransPicTranslate(int32_t x, int32_t y, qpic_t *pic); | |
| void M_DrawTextBox(int32_t x, int32_t y, int32_t width, int32_t lines); | |
| void M_ScanSaves(void); | |
| void M_Load_Key(int32_t k); | |
| void M_Save_Key(int32_t k); | |
| void M_Setup_Key(int32_t k); | |
| void M_Net_Key(int32_t k); | |
| void M_AdjustSliders(int32_t dir); | |
| void M_DrawSlider(int32_t x, int32_t y, float range); | |
| void M_DrawCheckbox(int32_t x, int32_t y, int32_t on); | |
| void M_Options_Key(int32_t k); | |
| void M_FindKeysForCommand(char *command, int32_t *twokeys); | |
| void M_UnbindCommand(char *command); | |
| void M_Keys_Key(int32_t k); | |
| void M_NetStart_Change(int32_t dir); | |
| void M_ServerList_Key(int32_t k); | |
| void Mod_LoadSpriteModel(model_t *mod, void *buffer); | |
| void Mod_LoadBrushModel(model_t *mod, void *buffer); | |
| void Mod_LoadAliasModel(model_t *mod, void *buffer); | |
| model_t *Mod_LoadModel(model_t *mod, bool crash); | |
| mleaf_t *Mod_PointInLeaf(vec3_t p, model_t *model); | |
| uint8_t *Mod_DecompressVis(uint8_t *in, model_t *model); | |
| model_t *Mod_FindName(char *name); | |
| void Mod_LoadTextures(lump_t *l); | |
| void Mod_LoadLighting(lump_t *l); | |
| void Mod_LoadVisibility(lump_t *l); | |
| void Mod_LoadEntities(lump_t *l); | |
| void Mod_LoadVertexes(lump_t *l); | |
| void Mod_LoadSubmodels(lump_t *l); | |
| void Mod_LoadEdges(lump_t *l); | |
| void Mod_LoadTexinfo(lump_t *l); | |
| void CalcSurfaceExtents(msurface_t *s); | |
| void Mod_LoadFaces(lump_t *l); | |
| void Mod_SetParent(mnode_t *node, mnode_t *parent); | |
| void Mod_LoadNodes(lump_t *l); | |
| void Mod_LoadLeafs(lump_t *l); | |
| void Mod_LoadClipnodes(lump_t *l); | |
| void Mod_MakeHull0(void); | |
| void Mod_LoadMarksurfaces(lump_t *l); | |
| void Mod_LoadSurfedges(lump_t *l); | |
| void Mod_LoadPlanes(lump_t *l); | |
| float RadiusFromBounds(vec3_t mins, vec3_t maxs); | |
| void *Mod_LoadAliasFrame(void *pin, int32_t *pframeindex, int32_t numv, trivertx_t *pbboxmin, trivertx_t *pbboxmax, aliashdr_t *pheader, char *name); | |
| void *Mod_LoadAliasGroup(void *pin, int32_t *pframeindex, int32_t numv, trivertx_t *pbboxmin, trivertx_t *pbboxmax, aliashdr_t *pheader, char *name); | |
| void *Mod_LoadAliasSkin(void *pin, int32_t *pskinindex, int32_t skinsize, aliashdr_t *pheader); | |
| void *Mod_LoadAliasSkinGroup(void *pin, int32_t *pskinindex, int32_t skinsize, aliashdr_t *pheader); | |
| void *Mod_LoadSpriteFrame(void *pin, mspriteframe_t **ppframe); | |
| void *Mod_LoadSpriteGroup(void *pin, mspriteframe_t **ppframe); | |
| int32_t Datagram_Init(void); | |
| void Datagram_Listen(bool state); | |
| void Datagram_SearchForHosts(bool xmit); | |
| qsocket_t *Datagram_Connect(char *host); | |
| qsocket_t *Datagram_CheckNewConnections(void); | |
| int32_t Datagram_GetMessage(qsocket_t *sock); | |
| int32_t Datagram_SendMessage(qsocket_t *sock, sizebuf_t *data); | |
| int32_t Datagram_SendUnreliableMessage(qsocket_t *sock, sizebuf_t *data); | |
| bool Datagram_CanSendMessage(qsocket_t *sock); | |
| bool Datagram_CanSendUnreliableMessage(qsocket_t *sock); | |
| void Datagram_Close(qsocket_t *sock); | |
| void Datagram_Shutdown(void); | |
| int32_t SendMessageNext(qsocket_t *sock); | |
| int32_t ReSendMessage(qsocket_t *sock); | |
| void PrintStats(qsocket_t *s); | |
| void NET_Stats_f(void); | |
| static void Test_Poll(void); | |
| static void Test_f(void); | |
| static void Test2_Poll(void); | |
| static void Test2_f(void); | |
| static qsocket_t *_Datagram_CheckNewConnections(void); | |
| static void _Datagram_SearchForHosts(bool xmit); | |
| static qsocket_t *_Datagram_Connect(char *host); | |
| int32_t Loop_Init(void); | |
| void Loop_Listen(bool state); | |
| void Loop_SearchForHosts(bool xmit); | |
| qsocket_t *Loop_Connect(char *host); | |
| qsocket_t *Loop_CheckNewConnections(void); | |
| int32_t Loop_GetMessage(qsocket_t *sock); | |
| int32_t Loop_SendMessage(qsocket_t *sock, sizebuf_t *data); | |
| int32_t Loop_SendUnreliableMessage(qsocket_t *sock, sizebuf_t *data); | |
| bool Loop_CanSendMessage(qsocket_t *sock); | |
| bool Loop_CanSendUnreliableMessage(qsocket_t *sock); | |
| void Loop_Close(qsocket_t *sock); | |
| void Loop_Shutdown(void); | |
| static int32_t IntAlign(int32_t value); | |
| int32_t VCR_Init(void); | |
| void VCR_Listen(bool state); | |
| void VCR_SearchForHosts(bool xmit); | |
| qsocket_t *VCR_Connect(char *host); | |
| qsocket_t *VCR_CheckNewConnections(void); | |
| int32_t VCR_GetMessage(qsocket_t *sock); | |
| int32_t VCR_SendMessage(qsocket_t *sock, sizebuf_t *data); | |
| bool VCR_CanSendMessage(qsocket_t *sock); | |
| void VCR_Close(qsocket_t *sock); | |
| void VCR_Shutdown(void); | |
| static void Slist_Send(void); | |
| static void Slist_Poll(void); | |
| void NET_FreeQSocket(qsocket_t *sock); | |
| static void NET_Listen_f(void); | |
| static void MaxPlayers_f(void); | |
| static void NET_Port_f(void); | |
| static void PrintSlistHeader(void); | |
| static void PrintSlist(void); | |
| static void PrintSlistTrailer(void); | |
| qsocket_t *NET_Connect(char *host); | |
| qsocket_t *NET_CheckNewConnections(void); | |
| void NET_Close(qsocket_t *sock); | |
| int32_t NET_GetMessage(qsocket_t *sock); | |
| int32_t NET_SendMessage(qsocket_t *sock, sizebuf_t *data); | |
| int32_t NET_SendUnreliableMessage(qsocket_t *sock, sizebuf_t *data); | |
| void SchedulePollProcedure(PollProcedure *proc, double timeOffset); | |
| void VCR_ReadNext(void); | |
| void R_Surf8Patch(); | |
| void R_Surf16Patch(); | |
| char *PF_VarString(int32_t first); | |
| void PF_error(void); | |
| void PF_objerror(void); | |
| void PF_makevectors(void); | |
| void PF_setorigin(void); | |
| void SetMinMaxSize(edict_t *e, float *min, float *max, bool rotate); | |
| void PF_setsize(void); | |
| void PF_setmodel(void); | |
| void PF_bprint(void); | |
| void PF_sprint(void); | |
| void PF_centerprint(void); | |
| void PF_normalize(void); | |
| void PF_vlen(void); | |
| void PF_vectoyaw(void); | |
| void PF_vectoangles(void); | |
| void PF_random(void); | |
| void PF_particle(void); | |
| void PF_ambientsound(void); | |
| void PF_sound(void); | |
| void PF_break(void); | |
| void PF_traceline(void); | |
| void PF_checkpos(void); | |
| int32_t PF_newcheckclient(int32_t check); | |
| void PF_checkclient(void); | |
| void PF_stuffcmd(void); | |
| void PF_localcmd(void); | |
| void PF_cvar(void); | |
| void PF_cvar_set(void); | |
| void PF_findradius(void); | |
| void PF_dprint(void); | |
| void PF_ftos(void); | |
| void PF_fabs(void); | |
| void PF_vtos(void); | |
| void PF_Spawn(void); | |
| void PF_Remove(void); | |
| void PF_Find(void); | |
| void PR_CheckEmptyString(char *s); | |
| void PF_precache_file(void); | |
| void PF_precache_sound(void); | |
| void PF_precache_model(void); | |
| void PF_coredump(void); | |
| void PF_traceon(void); | |
| void PF_traceoff(void); | |
| void PF_eprint(void); | |
| void PF_walkmove(void); | |
| void PF_droptofloor(void); | |
| void PF_lightstyle(void); | |
| void PF_rint(void); | |
| void PF_floor(void); | |
| void PF_ceil(void); | |
| void PF_checkbottom(void); | |
| void PF_pointcontents(void); | |
| void PF_nextent(void); | |
| void PF_aim(void); | |
| void PF_changeyaw(void); | |
| sizebuf_t *WriteDest(void); | |
| void PF_WriteByte(void); | |
| void PF_WriteChar(void); | |
| void PF_WriteShort(void); | |
| void PF_WriteLong(void); | |
| void PF_WriteAngle(void); | |
| void PF_WriteCoord(void); | |
| void PF_WriteString(void); | |
| void PF_WriteEntity(void); | |
| void PF_makestatic(void); | |
| void PF_setspawnparms(void); | |
| void PF_changelevel(void); | |
| void PF_Fixme(void); | |
| ddef_t *ED_FieldAtOfs(int32_t ofs); | |
| bool ED_ParseEpair(void *base, ddef_t *key, char *s); | |
| void ED_ClearEdict(edict_t *e); | |
| ddef_t *ED_GlobalAtOfs(int32_t ofs); | |
| ddef_t *ED_FindField(char *name); | |
| ddef_t *ED_FindGlobal(char *name); | |
| dfunction_t *ED_FindFunction(char *name); | |
| char *PR_ValueString(etype_t type, eval_t *val); | |
| char *PR_UglyValueString(etype_t type, eval_t *val); | |
| char *PR_GlobalString(int32_t ofs); | |
| char *PR_GlobalStringNoContents(int32_t ofs); | |
| void ED_PrintEdict_f(void); | |
| void ED_Count(void); | |
| void PR_PrintStatement(dstatement_t *s); | |
| void PR_StackTrace(void); | |
| int32_t PR_EnterFunction(dfunction_t *f); | |
| int32_t PR_LeaveFunction(void); | |
| void R_AliasProjectFinalVert(finalvert_t *fv, auxvert_t *av); | |
| void R_Alias_clip_top(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out); | |
| void R_Alias_clip_bottom(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out); | |
| void R_Alias_clip_left(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out); | |
| void R_Alias_clip_right(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out); | |
| void R_Alias_clip_z(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out); | |
| int32_t R_AliasClip(finalvert_t *in, finalvert_t *out, int32_t flag, int32_t count, void (*clip)(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)); | |
| void R_AliasTransformAndProjectFinalVerts(finalvert_t *fv, stvert_t *pstverts); | |
| void R_AliasSetUpTransform(int32_t trivial_accept); | |
| void R_AliasTransformVector(vec3_t in, vec3_t out); | |
| void R_AliasTransformFinalVert(finalvert_t *fv, auxvert_t *av, trivertx_t *pverts, stvert_t *pstverts); | |
| void R_AliasPreparePoints(void); | |
| void R_AliasPrepareUnclippedPoints(void); | |
| void R_AliasSetupSkin(void); | |
| void R_AliasSetupLighting(alight_t *plighting); | |
| void R_AliasSetupFrame(void); | |
| void R_EntityRotate(vec3_t vec); | |
| void R_RecursiveClipBPoly(bedge_t *pedges, mnode_t *pnode, msurface_t *psurf); | |
| void R_RecursiveWorldNode(mnode_t *node, int32_t clipflags); | |
| void R_EmitCachedEdge(void); | |
| void R_ZDrawSubmodelPolys(model_t *pmodel); | |
| static void R_GenerateSpans(void); | |
| static void R_GenerateSpansBackward(void); | |
| static void R_LeadingEdge(edge_t *edge); | |
| static void R_LeadingEdgeBackwards(edge_t *edge); | |
| static void R_TrailingEdge(surf_t *surf, edge_t *edge); | |
| void R_DrawCulledPolys(void); | |
| static void R_CleanupSpan(); | |
| static void R_SplitEntityOnNode(mnode_t *node); | |
| static int32_t RecursiveLightPoint(mnode_t *node, vec3_t start, vec3_t end); | |
| void R_MarkLeaves(void); | |
| void CreatePassages(void); | |
| void SetVisibilityByPassages(void); | |
| void R_SetVrect(vrect_t *pvrectin, vrect_t *pvrect, int32_t lineadj); | |
| void R_DrawEntitiesOnList(void); | |
| void R_DrawViewModel(void); | |
| int32_t R_BmodelCheckBBox(model_t *clmodel, float *minmaxs); | |
| void R_DrawBEntitiesOnList(void); | |
| void R_EdgeDrawing(void); | |
| void R_RenderView_(void); | |
| void R_CheckVariables(void); | |
| void Show(void); | |
| void R_LineGraph(int32_t x, int32_t y, int32_t h); | |
| void WarpPalette(void); | |
| void R_SetUpFrustumIndexes(void); | |
| void R_InitSky(texture_t *mt); | |
| void R_RotateSprite(float beamlength); | |
| int32_t R_ClipSpriteFace(int32_t nump, clipplane_t *pclipplane); | |
| void R_SetupAndDrawSprite(); | |
| mspriteframe_t *R_GetSpriteframe(msprite_t *psprite); | |
| void R_DrawSurfaceBlock8_mip0(void); | |
| void R_DrawSurfaceBlock8_mip1(void); | |
| void R_DrawSurfaceBlock8_mip2(void); | |
| void R_DrawSurfaceBlock8_mip3(void); | |
| void R_AddDynamicLights(void); | |
| void R_BuildLightMap(void); | |
| void R_GenTurbTile(pixel_t *pbasetex, void *pdest); | |
| void R_GenTurbTile16(pixel_t *pbasetex, void *pdest); | |
| void Sbar_MiniDeathmatchOverlay(void); | |
| void Sbar_DeathmatchOverlay(void); | |
| void Sbar_ShowScores(void); | |
| void Sbar_DontShowScores(void); | |
| void Sbar_DrawPic(int32_t x, int32_t y, qpic_t *pic); | |
| void Sbar_DrawTransPic(int32_t x, int32_t y, qpic_t *pic); | |
| void Sbar_DrawCharacter(int32_t x, int32_t y, int32_t num); | |
| void Sbar_DrawString(int32_t x, int32_t y, char *str); | |
| int32_t Sbar_itoa(int32_t num, char *buf); | |
| void Sbar_DrawNum(int32_t x, int32_t y, int32_t num, int32_t digits, int32_t color); | |
| void Sbar_SortFrags(void); | |
| int32_t Sbar_ColorForMap(int32_t m); | |
| void Sbar_UpdateScoreboard(void); | |
| void Sbar_SoloScoreboard(void); | |
| void Sbar_DrawScoreboard(void); | |
| void Sbar_DrawInventory(void); | |
| void Sbar_DrawFrags(void); | |
| void Sbar_DrawFace(void); | |
| void Sbar_IntermissionNumber(int32_t x, int32_t y, int32_t num, int32_t digits, int32_t color); | |
| void SCR_ScreenShot_f(void); | |
| void SCR_EraseCenterString(void); | |
| void SCR_DrawCenterString(void); | |
| void SCR_CheckDrawCenterString(void); | |
| float CalcFov(float fov_x, float width, float height); | |
| static void SCR_CalcRefdef(void); | |
| void SCR_SizeUp_f(void); | |
| void SCR_SizeDown_f(void); | |
| void SCR_DrawRam(void); | |
| void SCR_DrawTurtle(void); | |
| void SCR_DrawNet(void); | |
| void SCR_DrawPause(void); | |
| void SCR_DrawLoading(void); | |
| void SCR_SetUpToDrawConsole(void); | |
| void SCR_DrawConsole(void); | |
| void WritePCXfile(char *filename, uint8_t *data, int32_t width, int32_t height, int32_t rowbytes, uint8_t *palette); | |
| void SCR_DrawNotifyString(void); | |
| void S_Play(void); | |
| void S_PlayVol(void); | |
| void S_SoundList(void); | |
| void S_Update_(); | |
| void S_StopAllSoundsC(void); | |
| void S_SoundInfo_f(void); | |
| sfx_t *S_FindName(char *name); | |
| void S_TouchSound(char *name); | |
| sfx_t *S_PrecacheSound(char *name); | |
| void S_UpdateAmbientSounds(void); | |
| void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up); | |
| void GetSoundtime(void); | |
| void S_Update_(void); | |
| void S_LocalSound(char *sound); | |
| uint8_t *S_Alloc(int32_t size); | |
| void ResampleSfx(sfx_t *sfx, int32_t inrate, int32_t inwidth, uint8_t *data); | |
| int16_t GetLittleShort(void); | |
| int32_t GetLittleLong(void); | |
| void FindNextChunk(char *name); | |
| void FindChunk(char *name); | |
| void DumpChunks(void); | |
| void Snd_WriteLinearBlastStereo16(void); | |
| void S_TransferStereo16(int32_t endtime); | |
| void S_TransferPaintBuffer(int32_t endtime); | |
| void SND_PaintChannelFrom8(channel_t *ch, sfxcache_t *sc, int32_t endtime); | |
| void SND_PaintChannelFrom16(channel_t *ch, sfxcache_t *sc, int32_t endtime); | |
| void SND_PaintChannelFrom8(channel_t *ch, sfxcache_t *sc, int32_t count); | |
| void SND_PaintChannelFrom16(channel_t *ch, sfxcache_t *sc, int32_t count); | |
| void SV_SendServerinfo(client_t *client); | |
| void SV_ConnectClient(int32_t clientnum); | |
| void SV_AddToFatPVS(vec3_t org, mnode_t *node); | |
| uint8_t *SV_FatPVS(vec3_t org); | |
| void SV_WriteEntitiesToClient(edict_t *clent, sizebuf_t *msg); | |
| void SV_CleanupEnts(void); | |
| bool SV_SendClientDatagram(client_t *client); | |
| void SV_UpdateToReliableMessages(void); | |
| void SV_SendNop(client_t *client); | |
| void SV_CreateBaseline(void); | |
| void SV_SendReconnect(void); | |
| void SV_SaveSpawnparms(void); | |
| bool SV_StepDirection(edict_t *ent, float yaw, float dist); | |
| void SV_FixCheckBottom(edict_t *ent); | |
| void SV_NewChaseDir(edict_t *actor, edict_t *enemy, float dist); | |
| bool SV_CloseEnough(edict_t *ent, edict_t *goal, float dist); | |
| void SV_Physics_Toss(edict_t *ent); | |
| void SV_CheckAllEnts(void); | |
| void SV_CheckVelocity(edict_t *ent); | |
| bool SV_RunThink(edict_t *ent); | |
| void SV_Impact(edict_t *e1, edict_t *e2); | |
| int32_t ClipVelocity(vec3_t in, vec3_t normal, vec3_t out, float overbounce); | |
| int32_t SV_FlyMove(edict_t *ent, float time, trace_t *steptrace); | |
| void SV_AddGravity(edict_t *ent); | |
| trace_t SV_PushEntity(edict_t *ent, vec3_t push); | |
| void SV_PushMove(edict_t *pusher, float movetime); | |
| void SV_Physics_Pusher(edict_t *ent); | |
| void SV_CheckStuck(edict_t *ent); | |
| bool SV_CheckWater(edict_t *ent); | |
| void SV_WallFriction(edict_t *ent, trace_t *trace); | |
| int32_t SV_TryUnstick(edict_t *ent, vec3_t oldvel); | |
| void SV_WalkMove(edict_t *ent); | |
| void SV_Physics_Client(edict_t *ent, int32_t num); | |
| void SV_Physics_None(edict_t *ent); | |
| void SV_Physics_Noclip(edict_t *ent); | |
| void SV_CheckWaterTransition(edict_t *ent); | |
| void SV_Physics_Step(edict_t *ent); | |
| void SV_UserFriction(void); | |
| void SV_Accelerate(void); | |
| void SV_AirAccelerate(vec3_t wishveloc); | |
| void DropPunchAngle(void); | |
| void SV_WaterMove(void); | |
| void SV_WaterJump(void); | |
| void SV_AirMove(void); | |
| void SV_ReadClientMove(usercmd_t *move); | |
| bool SV_ReadClientMessage(void); | |
| void Sys_DebugNumber(int32_t y, int32_t val); | |
| void Sys_Init(void); | |
| void Sys_Warn(char *warning, ...); | |
| int32_t findhandle(void); | |
| static int32_t Qfilelength(FILE *f); | |
| int32_t Sys_FileRead(int32_t handle, void *dst, int32_t count); | |
| int32_t Sys_FileWrite(int32_t handle, void *src, int32_t count); | |
| int main(int argc, char *argv[]); | |
| void VID_SetPalette(unsigned char *palette_data); | |
| static int TranslateKey(int key); | |
| void VID_LockBuffer(); | |
| void VID_UnlockBuffer(); | |
| float V_CalcBob(void); | |
| void V_DriftPitch(void); | |
| void BuildGammaTable(float g); | |
| bool V_CheckGamma(void); | |
| void V_cshift_f(void); | |
| void V_BonusFlash_f(void); | |
| void V_CalcPowerupCshift(void); | |
| float angledelta(float a); | |
| void CalcGunAngle(void); | |
| void V_BoundOffsets(void); | |
| void V_AddIdle(void); | |
| void V_CalcViewRoll(void); | |
| void V_CalcIntermissionRefdef(void); | |
| void V_CalcRefdef(void); | |
| int32_t SV_HullPointContents(hull_t *hull, int32_t num, vec3_t p); | |
| void SV_InitBoxHull(void); | |
| hull_t *SV_HullForBox(vec3_t mins, vec3_t maxs); | |
| hull_t *SV_HullForEntity(edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t offset); | |
| areanode_t *SV_CreateAreaNode(int32_t depth, vec3_t mins, vec3_t maxs); | |
| void SV_TouchLinks(edict_t *ent, areanode_t *node); | |
| void SV_FindTouchedLeafs(edict_t *ent, mnode_t *node); | |
| bool SV_RecursiveHullCheck(hull_t *hull, int32_t num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace); | |
| trace_t SV_ClipMoveToEntity(edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end); | |
| void SV_ClipToLinks(areanode_t *node, moveclip_t *clip); | |
| void SV_MoveBounds(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t boxmins, vec3_t boxmaxs); | |
| void Cache_FreeLow(int32_t new_low_hunk); | |
| void Cache_FreeHigh(int32_t new_high_hunk); | |
| void Z_ClearZone(memzone_t *zone, int32_t size); | |
| void Z_Print(memzone_t *zone); | |
| void R_FreeTextures(void); | |
| void Hunk_Print(bool all); | |
| cache_system_t *Cache_TryAlloc(int32_t size, bool nobottom); | |
| void Cache_Move(cache_system_t *c); | |
| void Cache_UnlinkLRU(cache_system_t *cs); | |
| void Cache_MakeLRU(cache_system_t *cs); | |
| void Cache_Print(void); | |
| void Cache_Compact(void); | |
| void Cache_Init(void); | |
| Music music = (Music){0}; | |
| cvar_t chase_back = {"chase_back", "100"}; | |
| cvar_t chase_up = {"chase_up", "16"}; | |
| cvar_t chase_right = {"chase_right", "0"}; | |
| cvar_t chase_active = {"chase_active", "0"}; | |
| vec3_t chase_pos; | |
| vec3_t chase_angles; | |
| vec3_t chase_dest; | |
| vec3_t chase_dest_angles; | |
| kbutton_t in_mlook; | |
| kbutton_t in_klook; | |
| kbutton_t in_left; | |
| kbutton_t in_right; | |
| kbutton_t in_forward; | |
| kbutton_t in_back; | |
| kbutton_t in_lookup; | |
| kbutton_t in_lookdown; | |
| kbutton_t in_moveleft; | |
| kbutton_t in_moveright; | |
| kbutton_t in_strafe; | |
| kbutton_t in_speed; | |
| kbutton_t in_use; | |
| kbutton_t in_jump; | |
| kbutton_t in_attack; | |
| kbutton_t in_up; | |
| kbutton_t in_down; | |
| int32_t in_impulse; | |
| cvar_t cl_upspeed = {"cl_upspeed", "200"}; | |
| cvar_t cl_forwardspeed = {"cl_forwardspeed", "200", 1}; | |
| cvar_t cl_backspeed = {"cl_backspeed", "200", 1}; | |
| cvar_t cl_sidespeed = {"cl_sidespeed", "350"}; | |
| cvar_t cl_movespeedkey = {"cl_movespeedkey", "2.0"}; | |
| cvar_t cl_yawspeed = {"cl_yawspeed", "140"}; | |
| cvar_t cl_pitchspeed = {"cl_pitchspeed", "150"}; | |
| cvar_t cl_anglespeedkey = {"cl_anglespeedkey", "1.5"}; | |
| cvar_t cl_name = {"_cl_name", "player", 1}; | |
| cvar_t cl_color = {"_cl_color", "0", 1}; | |
| cvar_t cl_shownet = {"cl_shownet", "0"}; | |
| cvar_t cl_nolerp = {"cl_nolerp", "0"}; | |
| cvar_t lookspring = {"lookspring", "0", 1}; | |
| cvar_t lookstrafe = {"lookstrafe", "0", 1}; | |
| cvar_t sensitivity = {"sensitivity", "3", 1}; | |
| cvar_t m_pitch = {"m_pitch", "0.022", 1}; | |
| cvar_t m_yaw = {"m_yaw", "0.022", 1}; | |
| cvar_t m_forward = {"m_forward", "1", 1}; | |
| cvar_t m_side = {"m_side", "0.8", 1}; | |
| client_static_t cls; | |
| client_state_t cl; | |
| efrag_t cl_efrags[MAX_EFRAGS]; | |
| entity_t cl_entities[MAX_EDICTS]; | |
| entity_t cl_static_entities[MAX_STATIC_ENTITIES]; | |
| lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES]; | |
| dlight_t cl_dlights[MAX_DLIGHTS]; | |
| int32_t cl_numvisedicts; | |
| entity_t *cl_visedicts[MAX_VISEDICTS]; | |
| char *svc_strings[] = {"svc_bad", "svc_nop", "svc_disconnect", "svc_updatestat", "svc_version", "svc_setview", "svc_sound", "svc_time", "svc_print", "svc_stufftext", "svc_setangle", "svc_serverinfo", "svc_lightstyle", "svc_updatename", "svc_updatefrags", "svc_clientdata", "svc_stopsound", "svc_updatecolors", "svc_particle", "svc_damage", "svc_spawnstatic", "OBSOLETE svc_spawnbinary", "svc_spawnbaseline", "svc_temp_entity", "svc_setpause", "svc_signonnum", "svc_centerprint", "svc_killedmonster", "svc_foundsecret", "svc_spawnstaticsound", "svc_intermission", "svc_finale", "svc_cdtrack", "svc_sellscreen", "svc_cutscene"}; | |
| int32_t bitcounts[16]; | |
| int32_t num_temp_entities; | |
| entity_t cl_temp_entities[MAX_TEMP_ENTITIES]; | |
| beam_t cl_beams[MAX_BEAMS]; | |
| sfx_t *cl_sfx_wizhit; | |
| sfx_t *cl_sfx_knighthit; | |
| sfx_t *cl_sfx_tink1; | |
| sfx_t *cl_sfx_ric1; | |
| sfx_t *cl_sfx_ric2; | |
| sfx_t *cl_sfx_ric3; | |
| sfx_t *cl_sfx_r_exp3; | |
| cmdalias_t *cmd_alias; | |
| bool cmd_wait; | |
| sizebuf_t cmd_text; | |
| int32_t cmd_argc; | |
| char *cmd_argv[MAX_ARGS]; | |
| char *cmd_null_string = ""; | |
| char *cmd_args = 0; | |
| cmd_source_t cmd_source; | |
| cmd_function_t *cmd_functions; | |
| char *largv[(MAX_NUM_ARGVS + NUM_SAFE_ARGVS) + 1]; | |
| char *argvdummy = " "; | |
| char *safeargvs[NUM_SAFE_ARGVS] = {"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse", "-dibonly"}; | |
| cvar_t registered = {"registered", "1"}; | |
| cvar_t cmdline = {"cmdline", "0", 0, 1}; | |
| bool com_modified; | |
| bool proghack; | |
| int32_t static_registered = 1; | |
| bool msg_suppress_1 = 0; | |
| char com_token[1024]; | |
| int32_t com_argc; | |
| char **com_argv; | |
| char com_cmdline[CMDLINE_LENGTH]; | |
| bool standard_quake = 1; | |
| bool rogue; | |
| bool hipnotic; | |
| uint16_t pop[] = {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6600, 0x0000, 0x0000, 0x0000, 0x6600, 0x0000, 0x0000, 0x0066, 0x0000, 0x0000, 0x0000, 0x0000, 0x0067, 0x0000, 0x0000, 0x6665, 0x0000, 0x0000, 0x0000, 0x0000, 0x0065, 0x6600, 0x0063, 0x6561, 0x0000, 0x0000, 0x0000, 0x0000, 0x0061, 0x6563, 0x0064, 0x6561, 0x0000, 0x0000, 0x0000, 0x0000, 0x0061, 0x6564, 0x0064, 0x6564, 0x0000, 0x6469, 0x6969, 0x6400, 0x0064, 0x6564, 0x0063, 0x6568, 0x6200, 0x0064, 0x6864, 0x0000, 0x6268, 0x6563, 0x0000, 0x6567, 0x6963, 0x0064, 0x6764, 0x0063, 0x6967, 0x6500, 0x0000, 0x6266, 0x6769, 0x6a68, 0x6768, 0x6a69, 0x6766, 0x6200, 0x0000, 0x0062, 0x6566, 0x6666, 0x6666, 0x6666, 0x6562, 0x0000, 0x0000, 0x0000, 0x0062, 0x6364, 0x6664, 0x6362, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0062, 0x6662, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0061, 0x6661, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6500, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6400, 0x0000, 0x0000, 0x0000}; | |
| int32_t msg_readcount; | |
| bool msg_badread; | |
| int32_t com_filesize; | |
| char com_cachedir[MAX_OSPATH]; | |
| char com_gamedir[MAX_OSPATH]; | |
| searchpath_t *com_searchpaths; | |
| cache_user_t *loadcache; | |
| uint8_t *loadbuf; | |
| int32_t loadsize; | |
| int32_t con_linewidth; | |
| float con_cursorspeed = 4; | |
| bool con_forcedup; | |
| int32_t con_totallines; | |
| int32_t con_backscroll; | |
| int32_t con_current; | |
| int32_t con_x; | |
| char *con_text = 0; | |
| cvar_t con_notifytime = {"con_notifytime", "3"}; | |
| float con_times[NUM_CON_TIMES]; | |
| int32_t con_vislines; | |
| bool con_debuglog; | |
| bool con_initialized; | |
| int32_t con_notifylines; | |
| uint16_t crctable[256] = {0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0}; | |
| cvar_t *cvar_vars; | |
| char *cvar_null_string = ""; | |
| fixed16_t sadjust; | |
| fixed16_t tadjust; | |
| fixed16_t bbextents; | |
| fixed16_t bbextentt; | |
| void (*prealspandrawer)(void); | |
| int32_t miplevel; | |
| float scale_for_mip; | |
| int32_t screenwidth; | |
| int32_t ubasestep; | |
| int32_t errorterm; | |
| int32_t erroradjustup; | |
| int32_t erroradjustdown; | |
| int32_t vstartscan; | |
| vec3_t transformed_modelorg; | |
| cvar_t d_subdiv16 = {"d_subdiv16", "1"}; | |
| cvar_t d_mipcap = {"d_mipcap", "0"}; | |
| cvar_t d_mipscale = {"d_mipscale", "1"}; | |
| surfcache_t *d_initial_rover; | |
| bool d_roverwrapped; | |
| int32_t d_minmip; | |
| float d_scalemip[NUM_MIPS - 1]; | |
| float basemip[NUM_MIPS - 1] = {1.0, 0.5 * 0.8, 0.25 * 0.8}; | |
| void (*d_drawspans)(espan_t *pspan); | |
| int32_t d_vrectx; | |
| int32_t d_vrecty; | |
| int32_t d_vrectright_particle; | |
| int32_t d_vrectbottom_particle; | |
| int32_t d_y_aspect_shift; | |
| int32_t d_pix_min; | |
| int32_t d_pix_max; | |
| int32_t d_pix_shift; | |
| int32_t d_scantable[MAXHEIGHT]; | |
| int16_t *zspantable[MAXHEIGHT]; | |
| int32_t r_p0[6]; | |
| int32_t r_p1[6]; | |
| int32_t r_p2[6]; | |
| uint8_t *d_pcolormap; | |
| int32_t d_aflatcolor; | |
| int32_t d_xdenom; | |
| edgetable *pedgetable; | |
| edgetable edgetables[12] = {{0, 1, r_p0, r_p2, 0, 2, r_p0, r_p1, r_p2}, {0, 2, r_p1, r_p0, r_p2, 1, r_p1, r_p2, 0}, {1, 1, r_p0, r_p2, 0, 1, r_p1, r_p2, 0}, {0, 1, r_p1, r_p0, 0, 2, r_p1, r_p2, r_p0}, {0, 2, r_p0, r_p2, r_p1, 1, r_p0, r_p1, 0}, {0, 1, r_p2, r_p1, 0, 1, r_p2, r_p0, 0}, {0, 1, r_p2, r_p1, 0, 2, r_p2, r_p0, r_p1}, {0, 2, r_p2, r_p1, r_p0, 1, r_p2, r_p0, 0}, {0, 1, r_p1, r_p0, 0, 1, r_p1, r_p2, 0}, {1, 1, r_p2, r_p1, 0, 1, r_p0, r_p1, 0}, {1, 1, r_p1, r_p0, 0, 1, r_p2, r_p0, 0}, {0, 1, r_p0, r_p2, 0, 1, r_p0, r_p1, 0}}; | |
| int32_t a_sstepxfrac; | |
| int32_t a_tstepxfrac; | |
| int32_t r_lstepx; | |
| int32_t a_ststepxwhole; | |
| int32_t r_sstepx; | |
| int32_t r_tstepx; | |
| int32_t r_lstepy; | |
| int32_t r_sstepy; | |
| int32_t r_tstepy; | |
| int32_t r_zistepx; | |
| int32_t r_zistepy; | |
| int32_t d_aspancount; | |
| int32_t d_countextrastep; | |
| spanpackage_t *a_spans; | |
| spanpackage_t *d_pedgespanpackage; | |
| int32_t ystart; | |
| uint8_t *d_pdest; | |
| uint8_t *d_ptex; | |
| int16_t *d_pz; | |
| int32_t d_sfrac; | |
| int32_t d_tfrac; | |
| int32_t d_light; | |
| int32_t d_zi; | |
| int32_t d_ptexextrastep; | |
| int32_t d_sfracextrastep; | |
| int32_t d_tfracextrastep; | |
| int32_t d_lightextrastep; | |
| int32_t d_pdestextrastep; | |
| int32_t d_lightbasestep; | |
| int32_t d_pdestbasestep; | |
| int32_t d_ptexbasestep; | |
| int32_t d_sfracbasestep; | |
| int32_t d_tfracbasestep; | |
| int32_t d_ziextrastep; | |
| int32_t d_zibasestep; | |
| int32_t d_pzextrastep; | |
| int32_t d_pzbasestep; | |
| adivtab_t adivtab[32 * 32] = {{1, 0}, {1, -1}, {1, -2}, {1, -3}, {1, -4}, {1, -5}, {1, -6}, {1, -7}, {2, -1}, {2, -3}, {3, 0}, {3, -3}, {5, 0}, {7, -1}, {15, 0}, {0, 0}, {-15, 0}, {-8, 1}, {-5, 0}, {-4, 1}, {-3, 0}, {-3, 3}, {-3, 6}, {-2, 1}, {-2, 3}, {-2, 5}, {-2, 7}, {-2, 9}, {-2, 11}, {-2, 13}, {-1, 0}, {-1, 1}, {0, -14}, {1, 0}, {1, -1}, {1, -2}, {1, -3}, {1, -4}, {1, -5}, {1, -6}, {2, 0}, {2, -2}, {2, -4}, {3, -2}, {4, -2}, {7, 0}, {14, 0}, {0, 0}, {-14, 0}, {-7, 0}, {-5, 1}, {-4, 2}, {-3, 1}, {-3, 4}, {-2, 0}, {-2, 2}, {-2, 4}, {-2, 6}, {-2, 8}, {-2, 10}, {-2, 12}, {-1, 0}, {-1, 1}, {-1, 2}, {0, -13}, {0, -13}, {1, 0}, {1, -1}, {1, -2}, {1, -3}, {1, -4}, {1, -5}, {1, -6}, {2, -1}, {2, -3}, {3, -1}, {4, -1}, {6, -1}, {13, 0}, {0, 0}, {-13, 0}, {-7, 1}, {-5, 2}, {-4, 3}, {-3, 2}, {-3, 5}, {-2, 1}, {-2, 3}, {-2, 5}, {-2, 7}, {-2, 9}, {-2, 11}, {-1, 0}, {-1, 1}, {-1, 2}, {-1, 3}, {0, -12}, {0, -12}, {0, -12}, {1, 0}, {1, -1}, {1, -2}, {1, -3}, {1, -4}, {1, -5}, {2, 0}, {2, -2}, {3, 0}, {4, 0}, {6, 0}, {12, 0}, {0, 0}, {-12, 0}, {-6, 0}, {-4, 0}, {-3, 0}, {-3, 3}, {-2, 0}, {-2, 2}, {-2, 4}, {-2, 6}, {-2, 8}, {-2, 10}, {-1, 0}, {-1, 1}, {-1, 2}, {-1, 3}, {-1, 4}, {0, -11}, {0, -11}, {0, -11}, {0, -11}, {1, 0}, {1, -1}, {1, -2}, {1, -3}, {1, -4}, {1, -5}, {2, -1}, {2, -3}, {3, -2}, {5, -1}, {11, 0}, {0, 0}, {-11, 0}, {-6, 1}, {-4, 1}, {-3, 1}, {-3, 4}, {-2, 1}, {-2, 3}, {-2, 5}, {-2, 7}, {-2, 9}, {-1, 0}, {-1, 1}, {-1, 2}, {-1, 3}, {-1, 4}, {-1, 5}, {0, -10}, {0, -10}, {0, -10}, {0, -10}, {0, -10}, {1, 0}, {1, -1}, {1, -2}, {1, -3}, {1, -4}, {2, 0}, {2, -2}, {3, -1}, {5, 0}, {10, 0}, {0, 0}, {-10, 0}, {-5, 0}, {-4, 2}, {-3, 2}, {-2, 0}, {-2, 2}, {-2, 4}, {-2, 6}, {-2, 8}, {-1, 0}, {-1, 1}, {-1, 2}, {-1, 3}, {-1, 4}, {-1, 5}, {-1, 6}, {0, -9}, {0, -9}, {0, -9}, {0, -9}, {0, -9}, {0, -9}, {1, 0}, {1, -1}, {1, -2}, {1, -3}, {1, -4}, {2, -1}, {3, 0}, {4, -1}, {9, 0}, {0, 0}, {-9, 0}, {-5, 1}, {-3, 0}, {-3, 3}, {-2, 1}, {-2, 3}, {-2, 5}, {-2, 7}, {-1, 0}, {-1, 1}, {-1, 2}, {-1, 3}, {-1, 4}, {-1, 5}, {-1, 6}, {-1, 7}, {0, -8}, {0, -8}, {0, -8}, {0, -8}, {0, -8}, {0, -8}, {0, -8}, {1, 0}, {1, -1}, {1, -2}, {1, -3}, {2, 0}, {2, -2}, {4, 0}, {8, 0}, {0, 0}, {-8, 0}, {-4, 0}, {-3, 1}, {-2, 0}, {-2, 2}, {-2, 4}, {-2, 6}, {-1, 0}, {-1, 1}, {-1, 2}, {-1, 3}, {-1, 4}, {-1, 5}, {-1, 6}, {-1, 7}, {-1, 8}, {0, -7}, {0, -7}, {0, -7}, {0, -7}, {0, -7}, {0, -7}, {0, -7}, {0, -7}, {1, 0}, {1, -1}, {1, -2}, {1, -3}, {2, -1}, {3, -1}, {7, 0}, {0, 0}, {-7, 0}, {-4, 1}, {-3, 2}, {-2, 1}, {-2, 3}, {-2, 5}, {-1, 0}, {-1, 1}, {-1, 2}, {-1, 3}, {-1, 4}, {-1, 5}, {-1, 6}, {-1, 7}, {-1, 8}, {-1, 9}, {0, -6}, {0, -6}, {0, -6}, {0, -6}, {0, -6}, {0, -6}, {0, -6}, {0, -6}, {0, -6}, {1, 0}, {1, -1}, {1, -2}, {2, 0}, {3, 0}, {6, 0}, {0, 0}, {-6, 0}, {-3, 0}, {-2, 0}, {-2, 2}, {-2, 4}, {-1, 0}, {-1, 1}, {-1, 2}, {-1, 3}, {-1, 4}, {-1, 5}, {-1, 6}, {-1, 7}, {-1, 8}, {-1, 9}, {-1, 10}, {0, -5}, {0, -5}, {0, -5}, {0, -5}, {0, -5}, {0, -5}, {0, -5}, {0, -5}, {0, -5}, {0, -5}, {1, 0}, {1, -1}, {1, -2}, {2, -1}, {5, 0}, {0, 0}, {-5, 0}, {-3, 1}, {-2, 1}, {-2, 3}, {-1, 0}, {-1, 1}, {-1, 2}, {-1, 3}, {-1, 4}, {-1, 5}, {-1, 6}, {-1, 7}, {-1, 8}, {-1, 9}, {-1, 10}, {-1, 11}, {0, -4}, {0, -4}, {0, -4}, {0, -4}, {0, -4}, {0, -4}, {0, -4}, {0, -4}, {0, -4}, {0, -4}, {0, -4}, {1, 0}, {1, -1}, {2, 0}, {4, 0}, {0, 0}, {-4, 0}, {-2, 0}, {-2, 2}, {-1, 0}, {-1, 1}, {-1, 2}, {-1, 3}, {-1, 4}, {-1, 5}, {-1, 6}, {-1, 7}, {-1, 8}, {-1, 9}, {-1, 10}, {-1, 11}, {-1, 12}, {0, -3}, {0, -3}, {0, -3}, {0, -3}, {0, -3}, {0, -3}, {0, -3}, {0, -3}, {0, -3}, {0, -3}, {0, -3}, {0, -3}, {1, 0}, {1, -1}, {3, 0}, {0, 0}, {-3, 0}, {-2, 1}, {-1, 0}, {-1, 1}, {-1, 2}, {-1, 3}, {-1, 4}, {-1, 5}, {-1, 6}, {-1, 7}, {-1, 8}, {-1, 9}, {-1, 10}, {-1, 11}, {-1, 12}, {-1, 13}, {0, -2}, {0, -2}, {0, -2}, {0, -2}, {0, -2}, {0, -2}, {0, -2}, {0, -2}, {0, -2}, {0, -2}, {0, -2}, {0, -2}, {0, -2}, {1, 0}, {2, 0}, {0, 0}, {-2, 0}, {-1, 0}, {-1, 1}, {-1, 2}, {-1, 3}, {-1, 4}, {-1, 5}, {-1, 6}, {-1, 7}, {-1, 8}, {-1, 9}, {-1, 10}, {-1, 11}, {-1, 12}, {-1, 13}, {-1, 14}, {0, -1}, {0, -1}, {0, -1}, {0, -1}, {0, -1}, {0, -1}, {0, -1}, {0, -1}, {0, -1}, {0, -1}, {0, -1}, {0, -1}, {0, -1}, {0, -1}, {1, 0}, {0, 0}, {-1, 0}, {-1, 1}, {-1, 2}, {-1, 3}, {-1, 4}, {-1, 5}, {-1, 6}, {-1, 7}, {-1, 8}, {-1, 9}, {-1, 10}, {-1, 11}, {-1, 12}, {-1, 13}, {-1, 14}, {-1, 15}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {-1, -14}, {-1, -13}, {-1, -12}, {-1, -11}, {-1, -10}, {-1, -9}, {-1, -8}, {-1, -7}, {-1, -6}, {-1, -5}, {-1, -4}, {-1, -3}, {-1, -2}, {-1, -1}, {-1, 0}, {0, 0}, {1, 0}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {-1, -13}, {-1, -12}, {-1, -11}, {-1, -10}, {-1, -9}, {-1, -8}, {-1, -7}, {-1, -6}, {-1, -5}, {-1, -4}, {-1, -3}, {-1, -2}, {-1, -1}, {-1, 0}, {-2, 0}, {0, 0}, {2, 0}, {1, 0}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {-1, -12}, {-1, -11}, {-1, -10}, {-1, -9}, {-1, -8}, {-1, -7}, {-1, -6}, {-1, -5}, {-1, -4}, {-1, -3}, {-1, -2}, {-1, -1}, {-1, 0}, {-2, -1}, {-3, 0}, {0, 0}, {3, 0}, {1, 1}, {1, 0}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {-1, -11}, {-1, -10}, {-1, -9}, {-1, -8}, {-1, -7}, {-1, -6}, {-1, -5}, {-1, -4}, {-1, -3}, {-1, -2}, {-1, -1}, {-1, 0}, {-2, -2}, {-2, 0}, {-4, 0}, {0, 0}, {4, 0}, {2, 0}, {1, 1}, {1, 0}, {0, 4}, {0, 4}, {0, 4}, {0, 4}, {0, 4}, {0, 4}, {0, 4}, {0, 4}, {0, 4}, {0, 4}, {0, 4}, {0, 4}, {-1, -10}, {-1, -9}, {-1, -8}, {-1, -7}, {-1, -6}, {-1, -5}, {-1, -4}, {-1, -3}, {-1, -2}, {-1, -1}, {-1, 0}, {-2, -3}, {-2, -1}, {-3, -1}, {-5, 0}, {0, 0}, {5, 0}, {2, 1}, {1, 2}, {1, 1}, {1, 0}, {0, 5}, {0, 5}, {0, 5}, {0, 5}, {0, 5}, {0, 5}, {0, 5}, {0, 5}, {0, 5}, {0, 5}, {0, 5}, {-1, -9}, {-1, -8}, {-1, -7}, {-1, -6}, {-1, -5}, {-1, -4}, {-1, -3}, {-1, -2}, {-1, -1}, {-1, 0}, {-2, -4}, {-2, -2}, {-2, 0}, {-3, 0}, {-6, 0}, {0, 0}, {6, 0}, {3, 0}, {2, 0}, {1, 2}, {1, 1}, {1, 0}, {0, 6}, {0, 6}, {0, 6}, {0, 6}, {0, 6}, {0, 6}, {0, 6}, {0, 6}, {0, 6}, {0, 6}, {-1, -8}, {-1, -7}, {-1, -6}, {-1, -5}, {-1, -4}, {-1, -3}, {-1, -2}, {-1, -1}, {-1, 0}, {-2, -5}, {-2, -3}, {-2, -1}, {-3, -2}, {-4, -1}, {-7, 0}, {0, 0}, {7, 0}, {3, 1}, {2, 1}, {1, 3}, {1, 2}, {1, 1}, {1, 0}, {0, 7}, {0, 7}, {0, 7}, {0, 7}, {0, 7}, {0, 7}, {0, 7}, {0, 7}, {0, 7}, {-1, -7}, {-1, -6}, {-1, -5}, {-1, -4}, {-1, -3}, {-1, -2}, {-1, -1}, {-1, 0}, {-2, -6}, {-2, -4}, {-2, -2}, {-2, 0}, {-3, -1}, {-4, 0}, {-8, 0}, {0, 0}, {8, 0}, {4, 0}, {2, 2}, {2, 0}, {1, 3}, {1, 2}, {1, 1}, {1, 0}, {0, 8}, {0, 8}, {0, 8}, {0, 8}, {0, 8}, {0, 8}, {0, 8}, {0, 8}, {-1, -6}, {-1, -5}, {-1, -4}, {-1, -3}, {-1, -2}, {-1, -1}, {-1, 0}, {-2, -7}, {-2, -5}, {-2, -3}, {-2, -1}, {-3, -3}, {-3, 0}, {-5, -1}, {-9, 0}, {0, 0}, {9, 0}, {4, 1}, {3, 0}, {2, 1}, {1, 4}, {1, 3}, {1, 2}, {1, 1}, {1, 0}, {0, 9}, {0, 9}, {0, 9}, {0, 9}, {0, 9}, {0, 9}, {0, 9}, {-1, -5}, {-1, -4}, {-1, -3}, {-1, -2}, {-1, -1}, {-1, 0}, {-2, -8}, {-2, -6}, {-2, -4}, {-2, -2}, {-2, 0}, {-3, -2}, {-4, -2}, {-5, 0}, {-10, 0}, {0, 0}, {10, 0}, {5, 0}, {3, 1}, {2, 2}, {2, 0}, {1, 4}, {1, 3}, {1, 2}, {1, 1}, {1, 0}, {0, 10}, {0, 10}, {0, 10}, {0, 10}, {0, 10}, {0, 10}, {-1, -4}, {-1, -3}, {-1, -2}, {-1, -1}, {-1, 0}, {-2, -9}, {-2, -7}, {-2, -5}, {-2, -3}, {-2, -1}, {-3, -4}, {-3, -1}, {-4, -1}, {-6, -1}, {-11, 0}, {0, 0}, {11, 0}, {5, 1}, {3, 2}, {2, 3}, {2, 1}, {1, 5}, {1, 4}, {1, 3}, {1, 2}, {1, 1}, {1, 0}, {0, 11}, {0, 11}, {0, 11}, {0, 11}, {0, 11}, {-1, -3}, {-1, -2}, {-1, -1}, {-1, 0}, {-2, -10}, {-2, -8}, {-2, -6}, {-2, -4}, {-2, -2}, {-2, 0}, {-3, -3}, {-3, 0}, {-4, 0}, {-6, 0}, {-12, 0}, {0, 0}, {12, 0}, {6, 0}, {4, 0}, {3, 0}, {2, 2}, {2, 0}, {1, 5}, {1, 4}, {1, 3}, {1, 2}, {1, 1}, {1, 0}, {0, 12}, {0, 12}, {0, 12}, {0, 12}, {-1, -2}, {-1, -1}, {-1, 0}, {-2, -11}, {-2, -9}, {-2, -7}, {-2, -5}, {-2, -3}, {-2, -1}, {-3, -5}, {-3, -2}, {-4, -3}, {-5, -2}, {-7, -1}, {-13, 0}, {0, 0}, {13, 0}, {6, 1}, {4, 1}, {3, 1}, {2, 3}, {2, 1}, {1, 6}, {1, 5}, {1, 4}, {1, 3}, {1, 2}, {1, 1}, {1, 0}, {0, 13}, {0, 13}, {0, 13}, {-1, -1}, {-1, 0}, {-2, -12}, {-2, -10}, {-2, -8}, {-2, -6}, {-2, -4}, {-2, -2}, {-2, 0}, {-3, -4}, {-3, -1}, {-4, -2}, {-5, -1}, {-7, 0}, {-14, 0}, {0, 0}, {14, 0}, {7, 0}, {4, 2}, {3, 2}, {2, 4}, {2, 2}, {2, 0}, {1, 6}, {1, 5}, {1, 4}, {1, 3}, {1, 2}, {1, 1}, {1, 0}, {0, 14}, {0, 14}, {-1, 0}, {-2, -13}, {-2, -11}, {-2, -9}, {-2, -7}, {-2, -5}, {-2, -3}, {-2, -1}, {-3, -6}, {-3, -3}, {-3, 0}, {-4, -1}, {-5, 0}, {-8, -1}, {-15, 0}, {0, 0}, {15, 0}, {7, 1}, {5, 0}, {3, 3}, {3, 0}, {2, 3}, {2, 1}, {1, 7}, {1, 6}, {1, 5}, {1, 4}, {1, 3}, {1, 2}, {1, 1}, {1, 0}, {0, 15}, {-2, -14}, {-2, -12}, {-2, -10}, {-2, -8}, {-2, -6}, {-2, -4}, {-2, -2}, {-2, 0}, {-3, -5}, {-3, -2}, {-4, -4}, {-4, 0}, {-6, -2}, {-8, 0}, {-16, 0}, {0, 0}, {16, 0}, {8, 0}, {5, 1}, {4, 0}, {3, 1}, {2, 4}, {2, 2}, {2, 0}, {1, 7}, {1, 6}, {1, 5}, {1, 4}, {1, 3}, {1, 2}, {1, 1}, {1, 0}}; | |
| uint8_t *skintable[MAX_LBM_HEIGHT]; | |
| int32_t skinwidth; | |
| uint8_t *skinstart; | |
| unsigned char *r_turb_pbase; | |
| unsigned char *r_turb_pdest; | |
| fixed16_t r_turb_s; | |
| fixed16_t r_turb_t; | |
| fixed16_t r_turb_sstep; | |
| fixed16_t r_turb_tstep; | |
| int32_t *r_turb_turb; | |
| int32_t r_turb_spancount; | |
| int32_t sprite_height; | |
| int32_t minindex; | |
| int32_t maxindex; | |
| sspan_t *sprite_spans; | |
| float surfscale; | |
| bool r_cache_thrash; | |
| int32_t sc_size; | |
| surfcache_t *sc_rover; | |
| surfcache_t *sc_base; | |
| float d_sdivzstepu; | |
| float d_tdivzstepu; | |
| float d_zistepu; | |
| float d_sdivzstepv; | |
| float d_tdivzstepv; | |
| float d_zistepv; | |
| float d_sdivzorigin; | |
| float d_tdivzorigin; | |
| float d_ziorigin; | |
| pixel_t *cacheblock; | |
| int32_t cachewidth; | |
| pixel_t *d_viewbuffer; | |
| int16_t *d_pzbuffer; | |
| uint32_t d_zrowbytes; | |
| uint32_t d_zwidth; | |
| rectdesc_t r_rectdesc; | |
| uint8_t *draw_chars; | |
| qpic_t *draw_disc; | |
| qpic_t *draw_backtile; | |
| cachepic_t menu_cachepics[MAX_CACHED_PICS]; | |
| int32_t menu_numcachepics; | |
| quakeparms_t host_parms; | |
| bool host_initialized; | |
| double host_frametime; | |
| double host_time; | |
| double realtime; | |
| double oldrealtime; | |
| int32_t host_framecount; | |
| int32_t host_hunklevel; | |
| int32_t minimum_memory; | |
| client_t *host_client; | |
| jmp_buf host_abortserver; | |
| uint8_t *host_basepal; | |
| uint8_t *host_colormap; | |
| cvar_t host_framerate = {"host_framerate", "0"}; | |
| cvar_t host_speeds = {"host_speeds", "0"}; | |
| cvar_t sys_ticrate = {"sys_ticrate", "0.05"}; | |
| cvar_t serverprofile = {"serverprofile", "0"}; | |
| cvar_t fraglimit = {"fraglimit", "0", 0, 1}; | |
| cvar_t timelimit = {"timelimit", "0", 0, 1}; | |
| cvar_t teamplay = {"teamplay", "0", 0, 1}; | |
| cvar_t samelevel = {"samelevel", "0"}; | |
| cvar_t noexit = {"noexit", "0", 0, 1}; | |
| cvar_t developer = {"developer", "0"}; | |
| cvar_t skill = {"skill", "1"}; | |
| cvar_t deathmatch = {"deathmatch", "0"}; | |
| cvar_t coop = {"coop", "0"}; | |
| cvar_t pausable = {"pausable", "1"}; | |
| cvar_t temp1 = {"temp1", "0"}; | |
| int32_t current_skill; | |
| bool noclip_anglehack; | |
| char key_lines[32][MAXCMDLINE]; | |
| int32_t key_linepos; | |
| int32_t shift_down = 0; | |
| int32_t key_lastpress; | |
| int32_t edit_line = 0; | |
| int32_t history_line = 0; | |
| keydest_t key_dest; | |
| int32_t key_count; | |
| char *keybindings[256]; | |
| bool consolekeys[256]; | |
| bool menubound[256]; | |
| int32_t keyshift[256]; | |
| int32_t key_repeats[256]; | |
| bool keydown[256]; | |
| keyname_t keynames[] = {{"TAB", K_TAB}, {"ENTER", K_ENTER}, {"ESCAPE", K_ESCAPE}, {"SPACE", K_SPACE}, {"BACKSPACE", K_BACKSPACE}, {"UPARROW", K_UPARROW}, {"DOWNARROW", K_DOWNARROW}, {"LEFTARROW", K_LEFTARROW}, {"RIGHTARROW", K_RIGHTARROW}, {"ALT", K_ALT}, {"CTRL", K_CTRL}, {"SHIFT", K_SHIFT}, {"F1", K_F1}, {"F2", K_F2}, {"F3", K_F3}, {"F4", K_F4}, {"F5", K_F5}, {"F6", K_F6}, {"F7", K_F7}, {"F8", K_F8}, {"F9", K_F9}, {"F10", K_F10}, {"F11", K_F11}, {"F12", K_F12}, {"INS", K_INS}, {"DEL", K_DEL}, {"PGDN", K_PGDN}, {"PGUP", K_PGUP}, {"HOME", K_HOME}, {"END", K_END}, {"MOUSE1", K_MOUSE1}, {"MOUSE2", K_MOUSE2}, {"MOUSE3", K_MOUSE3}, {"JOY1", K_JOY1}, {"JOY2", K_JOY2}, {"JOY3", K_JOY3}, {"JOY4", K_JOY4}, {"AUX1", K_AUX1}, {"AUX2", K_AUX2}, {"AUX3", K_AUX3}, {"AUX4", K_AUX4}, {"AUX5", K_AUX5}, {"AUX6", K_AUX6}, {"AUX7", K_AUX7}, {"AUX8", K_AUX8}, {"AUX9", K_AUX9}, {"AUX10", K_AUX10}, {"AUX11", K_AUX11}, {"AUX12", K_AUX12}, {"AUX13", K_AUX13}, {"AUX14", K_AUX14}, {"AUX15", K_AUX15}, {"AUX16", K_AUX16}, {"AUX17", K_AUX17}, {"AUX18", K_AUX18}, {"AUX19", K_AUX19}, {"AUX20", K_AUX20}, {"AUX21", K_AUX21}, {"AUX22", K_AUX22}, {"AUX23", K_AUX23}, {"AUX24", K_AUX24}, {"AUX25", K_AUX25}, {"AUX26", K_AUX26}, {"AUX27", K_AUX27}, {"AUX28", K_AUX28}, {"AUX29", K_AUX29}, {"AUX30", K_AUX30}, {"AUX31", K_AUX31}, {"AUX32", K_AUX32}, {"PAUSE", K_PAUSE}, {"MWHEELUP", K_MWHEELUP}, {"MWHEELDOWN", K_MWHEELDOWN}, {"SEMICOLON", ';'}, {0, 0}}; | |
| char chat_buffer[32]; | |
| bool team_message = 0; | |
| vec3_t vec3_origin = {0, 0, 0}; | |
| int32_t nanmask = 255 << 23; | |
| void (*vid_menudrawfn)(void); | |
| void (*vid_menukeyfn)(int32_t key); | |
| bool m_entersound; | |
| bool m_recursiveDraw; | |
| int32_t m_return_state; | |
| bool m_return_onerror; | |
| char m_return_reason[32]; | |
| uint8_t identityTable[256]; | |
| uint8_t translationTable[256]; | |
| int32_t m_save_demonum; | |
| int32_t m_main_cursor; | |
| int32_t m_singleplayer_cursor; | |
| int32_t load_cursor; | |
| char m_filenames[MAX_SAVEGAMES][SAVEGAME_COMMENT_LENGTH + 1]; | |
| int32_t loadable[MAX_SAVEGAMES]; | |
| int32_t m_multiplayer_cursor; | |
| int32_t setup_cursor = 4; | |
| int32_t setup_cursor_table[] = {40, 56, 80, 104, 140}; | |
| char setup_hostname[16]; | |
| char setup_myname[16]; | |
| int32_t setup_oldtop; | |
| int32_t setup_oldbottom; | |
| int32_t setup_top; | |
| int32_t setup_bottom; | |
| int32_t m_net_cursor; | |
| int32_t m_net_items; | |
| int32_t m_net_saveHeight; | |
| char *net_helpMessage[] = {" ", " Two computers connected", " through two modems. ", " ", " ", " Two computers connected", " by a null-modem cable. ", " ", " Novell network LANs ", " or Windows 95 DOS-box. ", " ", "(LAN=Local Area Network)", " Commonly used to play ", " over the Internet, but ", " also used on a Local ", " Area Network. "}; | |
| int32_t options_cursor; | |
| char *bindnames[][2] = {{"+attack", "attack"}, {"impulse 10", "change weapon"}, {"+jump", "jump / swim up"}, {"+forward", "walk forward"}, {"+back", "backpedal"}, {"+left", "turn left"}, {"+right", "turn right"}, {"+speed", "run"}, {"+moveleft", "step left"}, {"+moveright", "step right"}, {"+strafe", "sidestep"}, {"+lookup", "look up"}, {"+lookdown", "look down"}, {"centerview", "center view"}, {"+mlook", "mouse look"}, {"+klook", "keyboard look"}, {"+moveup", "swim up"}, {"+movedown", "swim down"}}; | |
| int32_t keys_cursor; | |
| int32_t bind_grab; | |
| int32_t help_page; | |
| int32_t msgNumber; | |
| int32_t m_quit_prevstate; | |
| bool wasInMenus; | |
| char *quitMessage[] = {" Are you gonna quit ", " this game just like ", " everything else? ", " ", " Milord, methinks that ", " thou art a lowly ", " quitter. Is this true? ", " ", " Do I need to bust your ", " face open for trying ", " to quit? ", " ", " Man, I oughta smack you", " for trying to quit! ", " Press Y to get ", " smacked out. ", " Press Y to quit like a ", " big loser in life. ", " Press N to stay proud ", " and successful! ", " If you press Y to ", " quit, I will summon ", " Satan all over your ", " hard drive! ", " Um, Asmodeus dislikes ", " his children trying to ", " quit. Press Y to return", " to your Tinkertoys. ", " If you quit now, I'll ", " throw a blanket-party ", " for you next time! ", " "}; | |
| int32_t serialConfig_cursor; | |
| int32_t serialConfig_cursor_table[] = {48, 64, 80, 96, 112, 132}; | |
| int32_t ISA_uarts[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8}; | |
| int32_t ISA_IRQs[] = {4, 3, 4, 3}; | |
| int32_t serialConfig_baudrate[] = {9600, 14400, 19200, 28800, 38400, 57600}; | |
| int32_t serialConfig_comport; | |
| int32_t serialConfig_irq; | |
| int32_t serialConfig_baud; | |
| char serialConfig_phone[16]; | |
| int32_t modemConfig_cursor; | |
| int32_t modemConfig_cursor_table[] = {40, 56, 88, 120, 156}; | |
| char modemConfig_dialing; | |
| char modemConfig_clear[16]; | |
| char modemConfig_init[32]; | |
| char modemConfig_hangup[16]; | |
| int32_t lanConfig_cursor = -1; | |
| int32_t lanConfig_cursor_table[] = {72, 92, 124}; | |
| int32_t lanConfig_port; | |
| char lanConfig_portname[6]; | |
| char lanConfig_joinname[22]; | |
| level_t levels[] = {{"start", "Entrance"}, {"e1m1", "Slipgate Complex"}, {"e1m2", "Castle of the Damned"}, {"e1m3", "The Necropolis"}, {"e1m4", "The Grisly Grotto"}, {"e1m5", "Gloom Keep"}, {"e1m6", "The Door To Chthon"}, {"e1m7", "The House of Chthon"}, {"e1m8", "Ziggurat Vertigo"}, {"e2m1", "The Installation"}, {"e2m2", "Ogre Citadel"}, {"e2m3", "Crypt of Decay"}, {"e2m4", "The Ebon Fortress"}, {"e2m5", "The Wizard's Manse"}, {"e2m6", "The Dismal Oubliette"}, {"e2m7", "Underearth"}, {"e3m1", "Termination Central"}, {"e3m2", "The Vaults of Zin"}, {"e3m3", "The Tomb of Terror"}, {"e3m4", "Satan's Dark Delight"}, {"e3m5", "Wind Tunnels"}, {"e3m6", "Chambers of Torment"}, {"e3m7", "The Haunted Halls"}, {"e4m1", "The Sewage System"}, {"e4m2", "The Tower of Despair"}, {"e4m3", "The Elder God Shrine"}, {"e4m4", "The Palace of Hate"}, {"e4m5", "Hell's Atrium"}, {"e4m6", "The Pain Maze"}, {"e4m7", "Azure Agony"}, {"e4m8", "The Nameless City"}, {"end", "Shub-Niggurath's Pit"}, {"dm1", "Place of Two Deaths"}, {"dm2", "Claustrophobopolis"}, {"dm3", "The Abandoned Base"}, {"dm4", "The Bad Place"}, {"dm5", "The Cistern"}, {"dm6", "The Dark Zone"}}; | |
| level_t hipnoticlevels[] = {{"start", "Command HQ"}, {"hip1m1", "The Pumping Station"}, {"hip1m2", "Storage Facility"}, {"hip1m3", "The Lost Mine"}, {"hip1m4", "Research Facility"}, {"hip1m5", "Military Complex"}, {"hip2m1", "Ancient Realms"}, {"hip2m2", "The Black Cathedral"}, {"hip2m3", "The Catacombs"}, {"hip2m4", "The Crypt"}, {"hip2m5", "Mortum's Keep"}, {"hip2m6", "The Gremlin's Domain"}, {"hip3m1", "Tur Torment"}, {"hip3m2", "Pandemonium"}, {"hip3m3", "Limbo"}, {"hip3m4", "The Gauntlet"}, {"hipend", "Armagon's Lair"}, {"hipdm1", "The Edge of Oblivion"}}; | |
| level_t roguelevels[] = {{"start", "Split Decision"}, {"r1m1", "Deviant's Domain"}, {"r1m2", "Dread Portal"}, {"r1m3", "Judgement Call"}, {"r1m4", "Cave of Death"}, {"r1m5", "Towers of Wrath"}, {"r1m6", "Temple of Pain"}, {"r1m7", "Tomb of the Overlord"}, {"r2m1", "Tempus Fugit"}, {"r2m2", "Elemental Fury I"}, {"r2m3", "Elemental Fury II"}, {"r2m4", "Curse of Osiris"}, {"r2m5", "Wizard's Keep"}, {"r2m6", "Blood Sacrifice"}, {"r2m7", "Last Bastion"}, {"r2m8", "Source of Evil"}, {"ctf1", "Division of Change"}}; | |
| episode_t episodes[] = {{"Welcome to Quake", 0, 1}, {"Doomed Dimension", 1, 8}, {"Realm of Black Magic", 9, 7}, {"Netherworld", 16, 7}, {"The Elder World", 23, 8}, {"Final Level", 31, 1}, {"Deathmatch Arena", 32, 6}}; | |
| episode_t hipnoticepisodes[] = {{"Scourge of Armagon", 0, 1}, {"Fortress of the Dead", 1, 5}, {"Dominion of Darkness", 6, 6}, {"The Rift", 12, 4}, {"Final Level", 16, 1}, {"Deathmatch Arena", 17, 1}}; | |
| episode_t rogueepisodes[] = {{"Introduction", 0, 1}, {"Hell's Fortress", 1, 7}, {"Corridors of Time", 8, 8}, {"Deathmatch Arena", 16, 1}}; | |
| int32_t startepisode; | |
| int32_t startlevel; | |
| int32_t maxplayers; | |
| bool m_serverInfoMessage = 0; | |
| double m_serverInfoMessageTime; | |
| int32_t gameoptions_cursor_table[] = {40, 56, 64, 72, 80, 88, 96, 112, 120}; | |
| int32_t gameoptions_cursor; | |
| bool searchComplete = 0; | |
| double searchCompleteTime; | |
| int32_t slist_cursor; | |
| bool slist_sorted; | |
| model_t *loadmodel; | |
| char loadname[32]; | |
| uint8_t mod_novis[MAX_MAP_LEAFS / 8]; | |
| model_t mod_known[MAX_MOD_KNOWN]; | |
| int32_t mod_numknown; | |
| uint8_t *mod_base; | |
| int32_t net_landriverlevel; | |
| int32_t packetsSent = 0; | |
| int32_t packetsReSent = 0; | |
| int32_t packetsReceived = 0; | |
| int32_t receivedDuplicateCount = 0; | |
| int32_t shortPacketCount = 0; | |
| int32_t droppedDatagrams; | |
| int32_t myDriverLevel; | |
| bool testInProgress = 0; | |
| int32_t testPollCount; | |
| int32_t testDriver; | |
| int32_t testSocket; | |
| PollProcedure testPollProcedure = {0, 0.0, Test_Poll}; | |
| bool test2InProgress = 0; | |
| int32_t test2Driver; | |
| int32_t test2Socket; | |
| PollProcedure test2PollProcedure = {0, 0.0, Test2_Poll}; | |
| bool localconnectpending = 0; | |
| qsocket_t *loop_client = 0; | |
| qsocket_t *loop_server = 0; | |
| qsocket_t *net_activeSockets = 0; | |
| qsocket_t *net_freeSockets = 0; | |
| int32_t net_numsockets = 0; | |
| bool serialAvailable = 0; | |
| bool ipxAvailable = 0; | |
| bool tcpipAvailable = 0; | |
| int32_t net_hostport; | |
| int32_t DEFAULTnet_hostport = 26000; | |
| char my_ipx_address[NET_NAMELEN]; | |
| char my_tcpip_address[NET_NAMELEN]; | |
| void (*GetComPortConfig)(int32_t portNumber, int32_t *port, int32_t *irq, int32_t *baud, bool *useModem); | |
| void (*SetComPortConfig)(int32_t portNumber, int32_t port, int32_t irq, int32_t baud, bool useModem); | |
| void (*GetModemConfig)(int32_t portNumber, char *dialType, char *clear, char *init, char *hangup); | |
| void (*SetModemConfig)(int32_t portNumber, char *dialType, char *clear, char *init, char *hangup); | |
| bool listening = 0; | |
| bool slistInProgress = 0; | |
| bool slistSilent = 0; | |
| bool slistLocal = 1; | |
| double slistStartTime; | |
| int32_t slistLastShown; | |
| PollProcedure slistSendProcedure = {0, 0.0, Slist_Send}; | |
| PollProcedure slistPollProcedure = {0, 0.0, Slist_Poll}; | |
| sizebuf_t net_message; | |
| int32_t net_activeconnections = 0; | |
| int32_t messagesSent = 0; | |
| int32_t messagesReceived = 0; | |
| int32_t unreliableMessagesSent = 0; | |
| int32_t unreliableMessagesReceived = 0; | |
| cvar_t net_messagetimeout = {"net_messagetimeout", "300"}; | |
| cvar_t hostname = {"hostname", "UNNAMED"}; | |
| bool configRestored = 0; | |
| cvar_t config_com_port = {"_config_com_port", "0x3f8", 1}; | |
| cvar_t config_com_irq = {"_config_com_irq", "4", 1}; | |
| cvar_t config_com_baud = {"_config_com_baud", "57600", 1}; | |
| cvar_t config_com_modem = {"_config_com_modem", "1", 1}; | |
| cvar_t config_modem_dialtype = {"_config_modem_dialtype", "T", 1}; | |
| cvar_t config_modem_clear = {"_config_modem_clear", "ATZ", 1}; | |
| cvar_t config_modem_init = {"_config_modem_init", "", 1}; | |
| cvar_t config_modem_hangup = {"_config_modem_hangup", "AT H", 1}; | |
| int32_t vcrFile = -1; | |
| bool recording = 0; | |
| int32_t net_driverlevel; | |
| double net_time; | |
| int32_t hostCacheCount = 0; | |
| hostcache_t hostcache[HOSTCACHESIZE]; | |
| PollProcedure *pollProcedureList = 0; | |
| net_driver_t net_drivers[MAX_NET_DRIVERS] = {{"Loopback", 0, Loop_Init, Loop_Listen, Loop_SearchForHosts, Loop_Connect, Loop_CheckNewConnections, Loop_GetMessage, Loop_SendMessage, Loop_SendUnreliableMessage, Loop_CanSendMessage, Loop_CanSendUnreliableMessage, Loop_Close, Loop_Shutdown}}; | |
| int32_t net_numdrivers = 1; | |
| net_landriver_t net_landrivers[MAX_NET_DRIVERS]; | |
| int32_t net_numlandrivers = 0; | |
| uint8_t checkpvs[MAX_MAP_LEAFS / 8]; | |
| int32_t c_invis; | |
| int32_t c_notvis; | |
| char pr_string_temp[128]; | |
| cvar_t sv_aim = {"sv_aim", "0.93"}; | |
| builtin_t pr_builtin[] = {PF_Fixme, PF_makevectors, PF_setorigin, PF_setmodel, PF_setsize, PF_Fixme, PF_break, PF_random, PF_sound, PF_normalize, PF_error, PF_objerror, PF_vlen, PF_vectoyaw, PF_Spawn, PF_Remove, PF_traceline, PF_checkclient, PF_Find, PF_precache_sound, PF_precache_model, PF_stuffcmd, PF_findradius, PF_bprint, PF_sprint, PF_dprint, PF_ftos, PF_vtos, PF_coredump, PF_traceon, PF_traceoff, PF_eprint, PF_walkmove, PF_Fixme, PF_droptofloor, PF_lightstyle, PF_rint, PF_floor, PF_ceil, PF_Fixme, PF_checkbottom, PF_pointcontents, PF_Fixme, PF_fabs, PF_aim, PF_cvar, PF_localcmd, PF_nextent, PF_particle, PF_changeyaw, PF_Fixme, PF_vectoangles, PF_WriteByte, PF_WriteChar, PF_WriteShort, PF_WriteLong, PF_WriteCoord, PF_WriteAngle, PF_WriteString, PF_WriteEntity, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, PF_Fixme, SV_MoveToGoal, PF_precache_file, PF_makestatic, PF_changelevel, PF_Fixme, PF_cvar_set, PF_centerprint, PF_ambientsound, PF_precache_model, PF_precache_sound, PF_precache_file, PF_setspawnparms}; | |
| builtin_t *pr_builtins = pr_builtin; | |
| int32_t pr_numbuiltins = (sizeof(pr_builtin)) / (sizeof(pr_builtin[0])); | |
| dprograms_t *progs; | |
| dfunction_t *pr_functions; | |
| char *pr_strings; | |
| ddef_t *pr_fielddefs; | |
| ddef_t *pr_globaldefs; | |
| dstatement_t *pr_statements; | |
| globalvars_t *pr_global_struct; | |
| float *pr_globals; | |
| int32_t pr_edict_size; | |
| uint16_t pr_crc; | |
| int32_t type_size[8] = {1, (sizeof(string_t)) / 4, 1, 3, 1, 1, (sizeof(func_t)) / 4, (sizeof(void *)) / 4}; | |
| cvar_t nomonsters = {"nomonsters", "0"}; | |
| cvar_t gamecfg = {"gamecfg", "0"}; | |
| cvar_t scratch1 = {"scratch1", "0"}; | |
| cvar_t scratch2 = {"scratch2", "0"}; | |
| cvar_t scratch3 = {"scratch3", "0"}; | |
| cvar_t scratch4 = {"scratch4", "0"}; | |
| cvar_t savedgamecfg = {"savedgamecfg", "0", 1}; | |
| cvar_t saved1 = {"saved1", "0", 1}; | |
| cvar_t saved2 = {"saved2", "0", 1}; | |
| cvar_t saved3 = {"saved3", "0", 1}; | |
| cvar_t saved4 = {"saved4", "0", 1}; | |
| gefv_cache gefvCache[GEFV_CACHESIZE] = {{0, ""}, {0, ""}}; | |
| prstack_t pr_stack[MAX_STACK_DEPTH]; | |
| int32_t pr_depth; | |
| int32_t localstack[LOCALSTACK_SIZE]; | |
| int32_t localstack_used; | |
| bool pr_trace; | |
| dfunction_t *pr_xfunction; | |
| int32_t pr_xstatement; | |
| int32_t pr_argc; | |
| char *pr_opnames[] = {"DONE", "MUL_F", "MUL_V", "MUL_FV", "MUL_VF", "DIV", "ADD_F", "ADD_V", "SUB_F", "SUB_V", "EQ_F", "EQ_V", "EQ_S", "EQ_E", "EQ_FNC", "NE_F", "NE_V", "NE_S", "NE_E", "NE_FNC", "LE", "GE", "LT", "GT", "INDIRECT", "INDIRECT", "INDIRECT", "INDIRECT", "INDIRECT", "INDIRECT", "ADDRESS", "STORE_F", "STORE_V", "STORE_S", "STORE_ENT", "STORE_FLD", "STORE_FNC", "STOREP_F", "STOREP_V", "STOREP_S", "STOREP_ENT", "STOREP_FLD", "STOREP_FNC", "RETURN", "NOT_F", "NOT_V", "NOT_S", "NOT_ENT", "NOT_FNC", "IF", "IFNOT", "CALL0", "CALL1", "CALL2", "CALL3", "CALL4", "CALL5", "CALL6", "CALL7", "CALL8", "STATE", "GOTO", "AND", "OR", "BITAND", "BITOR"}; | |
| finalvert_t _fv[2][8]; | |
| auxvert_t av[8]; | |
| mtriangle_t *ptriangles; | |
| affinetridesc_t r_affinetridesc; | |
| void *acolormap; | |
| trivertx_t *r_apverts; | |
| mdl_t *pmdl; | |
| vec3_t r_plightvec; | |
| int32_t r_ambientlight; | |
| float r_shadelight; | |
| aliashdr_t *paliashdr; | |
| finalvert_t *pfinalverts; | |
| auxvert_t *pauxverts; | |
| float ziscale; | |
| model_t *pmodel; | |
| vec3_t alias_forward; | |
| vec3_t alias_right; | |
| vec3_t alias_up; | |
| maliasskindesc_t *pskindesc; | |
| int32_t r_amodels_drawn; | |
| int32_t a_skinwidth; | |
| int32_t r_anumverts; | |
| float aliastransform[3][4]; | |
| aedge_t aedges[12] = {{0, 1}, {1, 2}, {2, 3}, {3, 0}, {4, 5}, {5, 6}, {6, 7}, {7, 4}, {0, 5}, {1, 4}, {2, 7}, {3, 6}}; | |
| float r_avertexnormals[NUMVERTEXNORMALS][3] = {{-0.525731, 0.000000, 0.850651}, {-0.442863, 0.238856, 0.864188}, {-0.295242, 0.000000, 0.955423}, {-0.309017, 0.500000, 0.809017}, {-0.162460, 0.262866, 0.951056}, {0.000000, 0.000000, 1.000000}, {0.000000, 0.850651, 0.525731}, {-0.147621, 0.716567, 0.681718}, {0.147621, 0.716567, 0.681718}, {0.000000, 0.525731, 0.850651}, {0.309017, 0.500000, 0.809017}, {0.525731, 0.000000, 0.850651}, {0.295242, 0.000000, 0.955423}, {0.442863, 0.238856, 0.864188}, {0.162460, 0.262866, 0.951056}, {-0.681718, 0.147621, 0.716567}, {-0.809017, 0.309017, 0.500000}, {-0.587785, 0.425325, 0.688191}, {-0.850651, 0.525731, 0.000000}, {-0.864188, 0.442863, 0.238856}, {-0.716567, 0.681718, 0.147621}, {-0.688191, 0.587785, 0.425325}, {-0.500000, 0.809017, 0.309017}, {-0.238856, 0.864188, 0.442863}, {-0.425325, 0.688191, 0.587785}, {-0.716567, 0.681718, -0.147621}, {-0.500000, 0.809017, -0.309017}, {-0.525731, 0.850651, 0.000000}, {0.000000, 0.850651, -0.525731}, {-0.238856, 0.864188, -0.442863}, {0.000000, 0.955423, -0.295242}, {-0.262866, 0.951056, -0.162460}, {0.000000, 1.000000, 0.000000}, {0.000000, 0.955423, 0.295242}, {-0.262866, 0.951056, 0.162460}, {0.238856, 0.864188, 0.442863}, {0.262866, 0.951056, 0.162460}, {0.500000, 0.809017, 0.309017}, {0.238856, 0.864188, -0.442863}, {0.262866, 0.951056, -0.162460}, {0.500000, 0.809017, -0.309017}, {0.850651, 0.525731, 0.000000}, {0.716567, 0.681718, 0.147621}, {0.716567, 0.681718, -0.147621}, {0.525731, 0.850651, 0.000000}, {0.425325, 0.688191, 0.587785}, {0.864188, 0.442863, 0.238856}, {0.688191, 0.587785, 0.425325}, {0.809017, 0.309017, 0.500000}, {0.681718, 0.147621, 0.716567}, {0.587785, 0.425325, 0.688191}, {0.955423, 0.295242, 0.000000}, {1.000000, 0.000000, 0.000000}, {0.951056, 0.162460, 0.262866}, {0.850651, -0.525731, 0.000000}, {0.955423, -0.295242, 0.000000}, {0.864188, -0.442863, 0.238856}, {0.951056, -0.162460, 0.262866}, {0.809017, -0.309017, 0.500000}, {0.681718, -0.147621, 0.716567}, {0.850651, 0.000000, 0.525731}, {0.864188, 0.442863, -0.238856}, {0.809017, 0.309017, -0.500000}, {0.951056, 0.162460, -0.262866}, {0.525731, 0.000000, -0.850651}, {0.681718, 0.147621, -0.716567}, {0.681718, -0.147621, -0.716567}, {0.850651, 0.000000, -0.525731}, {0.809017, -0.309017, -0.500000}, {0.864188, -0.442863, -0.238856}, {0.951056, -0.162460, -0.262866}, {0.147621, 0.716567, -0.681718}, {0.309017, 0.500000, -0.809017}, {0.425325, 0.688191, -0.587785}, {0.442863, 0.238856, -0.864188}, {0.587785, 0.425325, -0.688191}, {0.688191, 0.587785, -0.425325}, {-0.147621, 0.716567, -0.681718}, {-0.309017, 0.500000, -0.809017}, {0.000000, 0.525731, -0.850651}, {-0.525731, 0.000000, -0.850651}, {-0.442863, 0.238856, -0.864188}, {-0.295242, 0.000000, -0.955423}, {-0.162460, 0.262866, -0.951056}, {0.000000, 0.000000, -1.000000}, {0.295242, 0.000000, -0.955423}, {0.162460, 0.262866, -0.951056}, {-0.442863, -0.238856, -0.864188}, {-0.309017, -0.500000, -0.809017}, {-0.162460, -0.262866, -0.951056}, {0.000000, -0.850651, -0.525731}, {-0.147621, -0.716567, -0.681718}, {0.147621, -0.716567, -0.681718}, {0.000000, -0.525731, -0.850651}, {0.309017, -0.500000, -0.809017}, {0.442863, -0.238856, -0.864188}, {0.162460, -0.262866, -0.951056}, {0.238856, -0.864188, -0.442863}, {0.500000, -0.809017, -0.309017}, {0.425325, -0.688191, -0.587785}, {0.716567, -0.681718, -0.147621}, {0.688191, -0.587785, -0.425325}, {0.587785, -0.425325, -0.688191}, {0.000000, -0.955423, -0.295242}, {0.000000, -1.000000, 0.000000}, {0.262866, -0.951056, -0.162460}, {0.000000, -0.850651, 0.525731}, {0.000000, -0.955423, 0.295242}, {0.238856, -0.864188, 0.442863}, {0.262866, -0.951056, 0.162460}, {0.500000, -0.809017, 0.309017}, {0.716567, -0.681718, 0.147621}, {0.525731, -0.850651, 0.000000}, {-0.238856, -0.864188, -0.442863}, {-0.500000, -0.809017, -0.309017}, {-0.262866, -0.951056, -0.162460}, {-0.850651, -0.525731, 0.000000}, {-0.716567, -0.681718, -0.147621}, {-0.716567, -0.681718, 0.147621}, {-0.525731, -0.850651, 0.000000}, {-0.500000, -0.809017, 0.309017}, {-0.238856, -0.864188, 0.442863}, {-0.262866, -0.951056, 0.162460}, {-0.864188, -0.442863, 0.238856}, {-0.809017, -0.309017, 0.500000}, {-0.688191, -0.587785, 0.425325}, {-0.681718, -0.147621, 0.716567}, {-0.442863, -0.238856, 0.864188}, {-0.587785, -0.425325, 0.688191}, {-0.309017, -0.500000, 0.809017}, {-0.147621, -0.716567, 0.681718}, {-0.425325, -0.688191, 0.587785}, {-0.162460, -0.262866, 0.951056}, {0.442863, -0.238856, 0.864188}, {0.162460, -0.262866, 0.951056}, {0.309017, -0.500000, 0.809017}, {0.147621, -0.716567, 0.681718}, {0.000000, -0.525731, 0.850651}, {0.425325, -0.688191, 0.587785}, {0.587785, -0.425325, 0.688191}, {0.688191, -0.587785, 0.425325}, {-0.955423, 0.295242, 0.000000}, {-0.951056, 0.162460, 0.262866}, {-1.000000, 0.000000, 0.000000}, {-0.850651, 0.000000, 0.525731}, {-0.955423, -0.295242, 0.000000}, {-0.951056, -0.162460, 0.262866}, {-0.864188, 0.442863, -0.238856}, {-0.951056, 0.162460, -0.262866}, {-0.809017, 0.309017, -0.500000}, {-0.864188, -0.442863, -0.238856}, {-0.951056, -0.162460, -0.262866}, {-0.809017, -0.309017, -0.500000}, {-0.681718, 0.147621, -0.716567}, {-0.681718, -0.147621, -0.716567}, {-0.850651, 0.000000, -0.525731}, {-0.688191, 0.587785, -0.425325}, {-0.587785, 0.425325, -0.688191}, {-0.425325, 0.688191, -0.587785}, {-0.425325, -0.688191, -0.587785}, {-0.587785, -0.425325, -0.688191}, {-0.688191, -0.587785, -0.425325}}; | |
| bool insubmodel; | |
| entity_t *currententity; | |
| vec3_t modelorg; | |
| vec3_t base_modelorg; | |
| vec3_t r_entorigin; | |
| float entity_rotation[3][3]; | |
| vec3_t r_worldmodelorg; | |
| int32_t r_currentbkey; | |
| mvertex_t *pbverts; | |
| bedge_t *pbedges; | |
| int32_t numbverts; | |
| int32_t numbedges; | |
| mvertex_t *pfrontenter; | |
| mvertex_t *pfrontexit; | |
| bool makeclippededge; | |
| uint32_t cacheoffset; | |
| int32_t c_faceclip; | |
| zpointdesc_t r_zpointdesc; | |
| polydesc_t r_polydesc; | |
| clipplane_t *entity_clipplanes; | |
| clipplane_t view_clipplanes[4]; | |
| clipplane_t world_clipplanes[16]; | |
| medge_t *r_pedge; | |
| bool r_leftclipped; | |
| bool r_rightclipped; | |
| bool makeleftedge; | |
| bool makerightedge; | |
| bool r_nearzionly; | |
| int32_t sintable[SIN_BUFFER_SIZE]; | |
| int32_t intsintable[SIN_BUFFER_SIZE]; | |
| mvertex_t r_leftenter; | |
| mvertex_t r_leftexit; | |
| mvertex_t r_rightenter; | |
| mvertex_t r_rightexit; | |
| int32_t r_emitted; | |
| float r_nearzi; | |
| float r_u1; | |
| float r_v1; | |
| float r_lzi1; | |
| int32_t r_ceilv1; | |
| bool r_lastvertvalid; | |
| edge_t *auxedges; | |
| edge_t *r_edges; | |
| edge_t *edge_p; | |
| edge_t *edge_max; | |
| surf_t *surfaces; | |
| surf_t *surface_p; | |
| surf_t *surf_max; | |
| edge_t *newedges[MAXHEIGHT]; | |
| edge_t *removeedges[MAXHEIGHT]; | |
| espan_t *span_p; | |
| espan_t *max_span_p; | |
| int32_t r_currentkey; | |
| int32_t current_iv; | |
| int32_t edge_head_u_shift20; | |
| int32_t edge_tail_u_shift20; | |
| void (*pdrawfunc)(void); | |
| edge_t edge_head; | |
| edge_t edge_tail; | |
| edge_t edge_aftertail; | |
| edge_t edge_sentinel; | |
| float fv; | |
| mnode_t *r_pefragtopnode; | |
| efrag_t **lastlink; | |
| vec3_t r_emins; | |
| vec3_t r_emaxs; | |
| entity_t *r_addent; | |
| int32_t r_dlightframecount; | |
| void *colormap; | |
| vec3_t viewlightvec; | |
| alight_t r_viewlighting = {128, 192, viewlightvec}; | |
| float r_time1; | |
| int32_t r_numallocatededges; | |
| bool r_drawpolys; | |
| bool r_drawculledpolys; | |
| bool r_worldpolysbacktofront; | |
| bool r_recursiveaffinetriangles = 1; | |
| int32_t r_pixbytes = 1; | |
| float r_aliasuvscale = 1.0; | |
| int32_t r_outofsurfaces; | |
| int32_t r_outofedges; | |
| bool r_dowarp; | |
| bool r_dowarpold; | |
| bool r_viewchanged; | |
| int32_t numbtofpolys; | |
| btofpoly_t *pbtofpolys; | |
| mvertex_t *r_pcurrentvertbase; | |
| int32_t c_surf; | |
| int32_t r_maxsurfsseen; | |
| int32_t r_maxedgesseen; | |
| int32_t r_cnumsurfs; | |
| bool r_surfsonstack; | |
| int32_t r_clipflags; | |
| uint8_t *r_warpbuffer; | |
| uint8_t *r_stack_start; | |
| bool r_fov_greater_than_90; | |
| vec3_t vup; | |
| vec3_t base_vup; | |
| vec3_t vpn; | |
| vec3_t base_vpn; | |
| vec3_t vright; | |
| vec3_t base_vright; | |
| vec3_t r_origin; | |
| refdef_t r_refdef; | |
| float xcenter; | |
| float ycenter; | |
| float xscale; | |
| float yscale; | |
| float xscaleinv; | |
| float yscaleinv; | |
| float xscaleshrink; | |
| float yscaleshrink; | |
| float aliasxscale; | |
| float aliasyscale; | |
| float aliasxcenter; | |
| float aliasycenter; | |
| float pixelAspect; | |
| float screenAspect; | |
| float verticalFieldOfView; | |
| float xOrigin; | |
| float yOrigin; | |
| mplane_t screenedge[4]; | |
| int32_t r_framecount = 1; | |
| int32_t r_visframecount; | |
| int32_t d_spanpixcount; | |
| int32_t r_polycount; | |
| int32_t r_drawnpolycount; | |
| int32_t r_wholepolycount; | |
| int32_t *pfrustum_indexes[4]; | |
| int32_t r_frustum_indexes[4 * 6]; | |
| int32_t reinit_surfcache = 1; | |
| mleaf_t *r_viewleaf; | |
| mleaf_t *r_oldviewleaf; | |
| texture_t *r_notexture_mip; | |
| float r_aliastransition; | |
| float r_resfudge; | |
| int32_t d_lightstylevalue[256]; | |
| float dp_time1; | |
| float dp_time2; | |
| float db_time1; | |
| float db_time2; | |
| float rw_time1; | |
| float rw_time2; | |
| float se_time1; | |
| float se_time2; | |
| float de_time1; | |
| float de_time2; | |
| float dv_time1; | |
| float dv_time2; | |
| cvar_t r_draworder = {"r_draworder", "0"}; | |
| cvar_t r_speeds = {"r_speeds", "0"}; | |
| cvar_t r_timegraph = {"r_timegraph", "0"}; | |
| cvar_t r_graphheight = {"r_graphheight", "10"}; | |
| cvar_t r_clearcolor = {"r_clearcolor", "2"}; | |
| cvar_t r_waterwarp = {"r_waterwarp", "1"}; | |
| cvar_t r_fullbright = {"r_fullbright", "0"}; | |
| cvar_t r_drawentities = {"r_drawentities", "1"}; | |
| cvar_t r_drawviewmodel = {"r_drawviewmodel", "1"}; | |
| cvar_t r_aliasstats = {"r_polymodelstats", "0"}; | |
| cvar_t r_dspeeds = {"r_dspeeds", "0"}; | |
| cvar_t r_drawflat = {"r_drawflat", "0"}; | |
| cvar_t r_ambient = {"r_ambient", "0"}; | |
| cvar_t r_reportsurfout = {"r_reportsurfout", "0"}; | |
| cvar_t r_maxsurfs = {"r_maxsurfs", "0"}; | |
| cvar_t r_numsurfs = {"r_numsurfs", "0"}; | |
| cvar_t r_reportedgeout = {"r_reportedgeout", "0"}; | |
| cvar_t r_maxedges = {"r_maxedges", "0"}; | |
| cvar_t r_numedges = {"r_numedges", "0"}; | |
| cvar_t r_aliastransbase = {"r_aliastransbase", "200"}; | |
| cvar_t r_aliastransadj = {"r_aliastransadj", "100"}; | |
| int32_t ramp1[8] = {0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61}; | |
| int32_t ramp2[8] = {0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66}; | |
| int32_t ramp3[8] = {0x6d, 0x6b, 6, 5, 4, 3}; | |
| particle_t *active_particles; | |
| particle_t *free_particles; | |
| particle_t *particles; | |
| int32_t r_numparticles; | |
| vec3_t r_pright; | |
| vec3_t r_pup; | |
| vec3_t r_ppn; | |
| vec3_t avelocities[NUMVERTEXNORMALS]; | |
| float beamlength = 16; | |
| vec3_t avelocity = {23, 7, 3}; | |
| float partstep = 0.01; | |
| float timescale = 0.01; | |
| int32_t iskyspeed = 8; | |
| int32_t iskyspeed2 = 2; | |
| float skyspeed; | |
| float skyspeed2; | |
| float skytime; | |
| uint8_t *r_skysource; | |
| int32_t r_skymade; | |
| int32_t r_skydirect; | |
| uint8_t bottomsky[128 * 131]; | |
| uint8_t bottommask[128 * 131]; | |
| uint8_t newsky[128 * 256]; | |
| int32_t clip_current; | |
| vec5_t clip_verts[2][MAXWORKINGVERTS]; | |
| int32_t sprite_width; | |
| spritedesc_t r_spritedesc; | |
| drawsurf_t r_drawsurf; | |
| int32_t lightleft; | |
| int32_t sourcesstep; | |
| int32_t blocksize; | |
| int32_t sourcetstep; | |
| int32_t lightdelta; | |
| int32_t lightdeltastep; | |
| int32_t lightright; | |
| int32_t lightleftstep; | |
| int32_t lightrightstep; | |
| int32_t blockdivshift; | |
| uint32_t blockdivmask; | |
| void *prowdestbase; | |
| unsigned char *pbasesource; | |
| int32_t surfrowbytes; | |
| uint32_t *r_lightptr; | |
| int32_t r_stepback; | |
| int32_t r_lightwidth; | |
| int32_t r_numhblocks; | |
| int32_t r_numvblocks; | |
| unsigned char *r_source; | |
| unsigned char *r_sourcemax; | |
| void (*surfmiptable[4])(void) = {R_DrawSurfaceBlock8_mip0, R_DrawSurfaceBlock8_mip1, R_DrawSurfaceBlock8_mip2, R_DrawSurfaceBlock8_mip3}; | |
| uint32_t blocklights[18 * 18]; | |
| int32_t r_bmodelactive; | |
| int32_t sb_updates; | |
| qpic_t *sb_nums[2][11]; | |
| qpic_t *sb_colon; | |
| qpic_t *sb_slash; | |
| qpic_t *sb_ibar; | |
| qpic_t *sb_sbar; | |
| qpic_t *sb_scorebar; | |
| qpic_t *sb_weapons[7][8]; | |
| qpic_t *sb_ammo[4]; | |
| qpic_t *sb_sigil[4]; | |
| qpic_t *sb_armor[3]; | |
| qpic_t *sb_items[32]; | |
| qpic_t *sb_faces[7][2]; | |
| qpic_t *sb_face_invis; | |
| qpic_t *sb_face_quad; | |
| qpic_t *sb_face_invuln; | |
| qpic_t *sb_face_invis_invuln; | |
| bool sb_showscores; | |
| int32_t sb_lines; | |
| qpic_t *rsb_invbar[2]; | |
| qpic_t *rsb_weapons[5]; | |
| qpic_t *rsb_items[2]; | |
| qpic_t *rsb_ammo[3]; | |
| qpic_t *rsb_teambord; | |
| qpic_t *hsb_weapons[7][5]; | |
| int32_t hipweapons[4] = {HIT_LASER_CANNON_BIT, HIT_MJOLNIR_BIT, 4, HIT_PROXIMITY_GUN_BIT}; | |
| qpic_t *hsb_items[2]; | |
| int32_t fragsort[MAX_SCOREBOARD]; | |
| char scoreboardtext[MAX_SCOREBOARD][20]; | |
| int32_t scoreboardtop[MAX_SCOREBOARD]; | |
| int32_t scoreboardbottom[MAX_SCOREBOARD]; | |
| int32_t scoreboardcount[MAX_SCOREBOARD]; | |
| int32_t scoreboardlines; | |
| int32_t scr_copytop; | |
| int32_t scr_copyeverything; | |
| float scr_con_current; | |
| float scr_conlines; | |
| float oldscreensize; | |
| float oldfov; | |
| cvar_t scr_viewsize = {"viewsize", "100", 1}; | |
| cvar_t scr_fov = {"fov", "90"}; | |
| cvar_t scr_conspeed = {"scr_conspeed", "300"}; | |
| cvar_t scr_centertime = {"scr_centertime", "2"}; | |
| cvar_t scr_showram = {"showram", "1"}; | |
| cvar_t scr_showturtle = {"showturtle", "0"}; | |
| cvar_t scr_showpause = {"showpause", "1"}; | |
| cvar_t scr_printspeed = {"scr_printspeed", "8"}; | |
| bool scr_initialized; | |
| qpic_t *scr_ram; | |
| qpic_t *scr_net; | |
| qpic_t *scr_turtle; | |
| int32_t scr_fullupdate; | |
| int32_t clearconsole; | |
| int32_t clearnotify; | |
| viddef_t vid; | |
| vrect_t *pconupdate; | |
| vrect_t scr_vrect; | |
| bool scr_disabled_for_loading; | |
| bool scr_drawloading; | |
| float scr_disabled_time; | |
| bool scr_skipupdate; | |
| bool block_drawing; | |
| char scr_centerstring[1024]; | |
| float scr_centertime_start; | |
| float scr_centertime_off; | |
| int32_t scr_center_lines; | |
| int32_t scr_erase_lines; | |
| int32_t scr_erase_center; | |
| char *scr_notifystring; | |
| bool scr_drawdialog; | |
| channel_t channels[MAX_CHANNELS]; | |
| int32_t total_channels; | |
| int32_t snd_blocked = 0; | |
| bool snd_ambient = 1; | |
| bool snd_initialized = 0; | |
| volatile dma_t *shm = 0; | |
| volatile dma_t sn; | |
| vec3_t listener_origin; | |
| vec3_t listener_forward; | |
| vec3_t listener_right; | |
| vec3_t listener_up; | |
| vec_t sound_nominal_clip_dist = 1000.0; | |
| int32_t soundtime; | |
| int32_t paintedtime; | |
| sfx_t *known_sfx; | |
| int32_t num_sfx; | |
| sfx_t *ambient_sfx[NUM_AMBIENTS]; | |
| int32_t desired_speed = 44100; | |
| int32_t desired_bits = 16; | |
| int32_t sound_started = 0; | |
| cvar_t bgmvolume = {"bgmvolume", "1", 1}; | |
| cvar_t volume = {"volume", "0.7", 1}; | |
| cvar_t nosound = {"nosound", "0"}; | |
| cvar_t precache = {"precache", "1"}; | |
| cvar_t loadas8bit = {"loadas8bit", "0"}; | |
| cvar_t bgmbuffer = {"bgmbuffer", "4096"}; | |
| cvar_t ambient_level = {"ambient_level", "0.3"}; | |
| cvar_t ambient_fade = {"ambient_fade", "100"}; | |
| cvar_t snd_noextraupdate = {"snd_noextraupdate", "0"}; | |
| cvar_t snd_show = {"snd_show", "0"}; | |
| cvar_t _snd_mixahead = {"_snd_mixahead", "0.1", 1}; | |
| bool fakedma = 0; | |
| int32_t fakedma_updates = 15; | |
| int32_t cache_full_cycle; | |
| uint8_t *data_p; | |
| uint8_t *iff_end; | |
| uint8_t *last_chunk; | |
| uint8_t *iff_data; | |
| int32_t iff_chunk_len; | |
| portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE]; | |
| int32_t snd_scaletable[32][256]; | |
| int32_t *snd_p; | |
| int32_t snd_linear_count; | |
| int32_t snd_vol; | |
| int16_t *snd_out; | |
| dma_t the_shm; | |
| int32_t snd_inited; | |
| AudioStream stream; | |
| void *mixbuffer = 0; | |
| server_t sv; | |
| server_static_t svs; | |
| char localmodels[MAX_MODELS][5]; | |
| int32_t fatbytes; | |
| uint8_t fatpvs[MAX_MAP_LEAFS / 8]; | |
| int32_t c_yes; | |
| int32_t c_no; | |
| cvar_t sv_friction = {"sv_friction", "4", 0, 1}; | |
| cvar_t sv_stopspeed = {"sv_stopspeed", "100"}; | |
| cvar_t sv_gravity = {"sv_gravity", "800", 0, 1}; | |
| cvar_t sv_maxvelocity = {"sv_maxvelocity", "2000"}; | |
| cvar_t sv_nostep = {"sv_nostep", "0"}; | |
| edict_t *sv_player; | |
| cvar_t sv_edgefriction = {"edgefriction", "2"}; | |
| vec3_t forward; | |
| vec3_t right; | |
| vec3_t up; | |
| vec3_t wishdir; | |
| float wishspeed; | |
| float *angles; | |
| float *origin; | |
| float *velocity; | |
| bool onground; | |
| usercmd_t cmd; | |
| cvar_t sv_idealpitchscale = {"sv_idealpitchscale", "0.8"}; | |
| cvar_t sv_maxspeed = {"sv_maxspeed", "320", 0, 1}; | |
| cvar_t sv_accelerate = {"sv_accelerate", "10"}; | |
| bool isDedicated; | |
| char *basedir = "."; | |
| cvar_t sys_nostdout = {"sys_nostdout", "0"}; | |
| FILE *sys_handles[MAX_HANDLES]; | |
| uint16_t d_8to16table[256]; | |
| Image image8bpp = {0}; | |
| Image image32bpp = {0}; | |
| Texture2D screenTexture = {0}; | |
| Color palette[256]; | |
| bool mouse_avail; | |
| float mouse_x; | |
| float mouse_y; | |
| int32_t mouse_oldbuttonstate = 0; | |
| void (*vid_menudrawfn)(void) = 0; | |
| void (*vid_menukeyfn)(int32_t key) = 0; | |
| cvar_t lcd_x = {"lcd_x", "0"}; | |
| cvar_t lcd_yaw = {"lcd_yaw", "0"}; | |
| cvar_t scr_ofsx = {"scr_ofsx", "0", 0}; | |
| cvar_t scr_ofsy = {"scr_ofsy", "0", 0}; | |
| cvar_t scr_ofsz = {"scr_ofsz", "0", 0}; | |
| cvar_t cl_rollspeed = {"cl_rollspeed", "200"}; | |
| cvar_t cl_rollangle = {"cl_rollangle", "2.0"}; | |
| cvar_t cl_bob = {"cl_bob", "0.02", 0}; | |
| cvar_t cl_bobcycle = {"cl_bobcycle", "0.6", 0}; | |
| cvar_t cl_bobup = {"cl_bobup", "0.5", 0}; | |
| cvar_t v_kicktime = {"v_kicktime", "0.5", 0}; | |
| cvar_t v_kickroll = {"v_kickroll", "0.6", 0}; | |
| cvar_t v_kickpitch = {"v_kickpitch", "0.6", 0}; | |
| cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "2", 0}; | |
| cvar_t v_iroll_cycle = {"v_iroll_cycle", "0.5", 0}; | |
| cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "1", 0}; | |
| cvar_t v_iyaw_level = {"v_iyaw_level", "0.3", 0}; | |
| cvar_t v_iroll_level = {"v_iroll_level", "0.1", 0}; | |
| cvar_t v_ipitch_level = {"v_ipitch_level", "0.3", 0}; | |
| cvar_t v_idlescale = {"v_idlescale", "0", 0}; | |
| cvar_t crosshair = {"crosshair", "0", 1}; | |
| cvar_t cl_crossx = {"cl_crossx", "0", 0}; | |
| cvar_t cl_crossy = {"cl_crossy", "0", 0}; | |
| cvar_t gl_cshiftpercent = {"gl_cshiftpercent", "100", 0}; | |
| float v_dmg_time; | |
| float v_dmg_roll; | |
| float v_dmg_pitch; | |
| cvar_t v_centermove = {"v_centermove", "0.15", 0}; | |
| cvar_t v_centerspeed = {"v_centerspeed", "500"}; | |
| cshift_t cshift_empty = {{130, 80, 50}, 0}; | |
| cshift_t cshift_water = {{130, 80, 50}, 128}; | |
| cshift_t cshift_slime = {{0, 25, 5}, 150}; | |
| cshift_t cshift_lava = {{255, 80, 0}, 150}; | |
| cvar_t v_gamma = {"gamma", "1", 1}; | |
| uint8_t gammatable[256]; | |
| int32_t wad_numlumps; | |
| lumpinfo_t *wad_lumps; | |
| uint8_t *wad_base; | |
| hull_t box_hull; | |
| dclipnode_t box_clipnodes[6]; | |
| mplane_t box_planes[6]; | |
| areanode_t sv_areanodes[AREA_NODES]; | |
| int32_t sv_numareanodes; | |
| memzone_t *mainzone; | |
| uint8_t *hunk_base; | |
| int32_t hunk_size; | |
| int32_t hunk_low_used; | |
| int32_t hunk_high_used; | |
| bool hunk_tempactive; | |
| int32_t hunk_tempmark; | |
| cache_system_t cache_head; | |
| int32_t CDAudio_Init(void) | |
| { | |
| return 0; | |
| } | |
| void CDAudio_Play(uint8_t track, bool looping) | |
| { | |
| if (IsMusicValid(music)) | |
| { | |
| UnloadMusicStream(music); | |
| } | |
| char filename[256]; | |
| snprintf(filename, sizeof(filename), "id1/music/%d.mp3", track); | |
| music = LoadMusicStream(filename); | |
| if (!IsMusicValid(music)) | |
| { | |
| Con_Printf("Could not load music file: %s\n", filename); | |
| return; | |
| } | |
| music.looping = looping; | |
| PlayMusicStream(music); | |
| } | |
| void CDAudio_Stop(void) | |
| { | |
| if (IsMusicValid(music)) | |
| { | |
| StopMusicStream(music); | |
| UnloadMusicStream(music); | |
| music = (Music){0}; | |
| } | |
| } | |
| void CDAudio_Pause(void) | |
| { | |
| if (IsMusicValid(music)) | |
| { | |
| PauseMusicStream(music); | |
| } | |
| } | |
| void CDAudio_Resume(void) | |
| { | |
| if (IsMusicValid(music)) | |
| { | |
| ResumeMusicStream(music); | |
| } | |
| } | |
| void CDAudio_Shutdown(void) | |
| { | |
| CDAudio_Stop(); | |
| } | |
| void CDAudio_Update(void) | |
| { | |
| if (IsMusicValid(music)) | |
| { | |
| UpdateMusicStream(music); | |
| SetMusicVolume(music, bgmvolume.value); | |
| } | |
| } | |
| void Chase_Init(void) | |
| { | |
| Cvar_RegisterVariable(&chase_back); | |
| Cvar_RegisterVariable(&chase_up); | |
| Cvar_RegisterVariable(&chase_right); | |
| Cvar_RegisterVariable(&chase_active); | |
| } | |
| void Chase_Reset(void) | |
| { | |
| } | |
| static void TraceLine(vec3_t start, vec3_t end, vec3_t impact) | |
| { | |
| trace_t trace; | |
| memset(&trace, 0, sizeof(trace)); | |
| SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, 0, 1, start, end, &trace); | |
| VectorCopy(trace.endpos, impact); | |
| } | |
| void Chase_Update(void) | |
| { | |
| int32_t i; | |
| float dist; | |
| vec3_t forward; | |
| vec3_t up; | |
| vec3_t right; | |
| vec3_t dest; | |
| vec3_t stop; | |
| AngleVectors(cl.viewangles, forward, right, up); | |
| for (i = 0; i < 3; i++) | |
| chase_dest[i] = (r_refdef.vieworg[i] - (forward[i] * chase_back.value)) - (right[i] * chase_right.value); | |
| chase_dest[2] = r_refdef.vieworg[2] + chase_up.value; | |
| VectorMA(r_refdef.vieworg, 4096, forward, dest); | |
| TraceLine(r_refdef.vieworg, dest, stop); | |
| VectorSubtract(stop, r_refdef.vieworg, stop); | |
| dist = DotProduct(stop, forward); | |
| if (dist < 1) | |
| dist = 1; | |
| r_refdef.viewangles[PITCH] = ((-atan(stop[2] / dist)) / M_PI) * 180; | |
| VectorCopy(chase_dest, r_refdef.vieworg); | |
| } | |
| void CL_StopPlayback(void) | |
| { | |
| if (!cls.demoplayback) | |
| return; | |
| fclose(cls.demofile); | |
| cls.demoplayback = 0; | |
| cls.demofile = 0; | |
| cls.state = ca_disconnected; | |
| if (cls.timedemo) | |
| CL_FinishTimeDemo(); | |
| } | |
| static void CL_WriteDemoMessage(void) | |
| { | |
| int32_t len; | |
| int32_t i; | |
| float f; | |
| len = net_message.cursize; | |
| fwrite(&len, 4, 1, cls.demofile); | |
| for (i = 0; i < 3; i++) | |
| { | |
| f = cl.viewangles[i]; | |
| fwrite(&f, 4, 1, cls.demofile); | |
| } | |
| fwrite(net_message.data, net_message.cursize, 1, cls.demofile); | |
| fflush(cls.demofile); | |
| } | |
| int32_t CL_GetMessage(void) | |
| { | |
| int32_t r; | |
| int32_t i; | |
| float f; | |
| if (cls.demoplayback) | |
| { | |
| if (cls.signon == SIGNONS) | |
| { | |
| if (cls.timedemo) | |
| { | |
| if (host_framecount == cls.td_lastframe) | |
| return 0; | |
| cls.td_lastframe = host_framecount; | |
| if (host_framecount == (cls.td_startframe + 1)) | |
| cls.td_starttime = realtime; | |
| } | |
| else | |
| if (cl.time <= cl.mtime[0]) | |
| { | |
| return 0; | |
| } | |
| } | |
| fread(&net_message.cursize, 4, 1, cls.demofile); | |
| VectorCopy(cl.mviewangles[0], cl.mviewangles[1]); | |
| for (i = 0; i < 3; i++) | |
| { | |
| r = fread(&f, 4, 1, cls.demofile); | |
| cl.mviewangles[0][i] = f; | |
| } | |
| net_message.cursize = net_message.cursize; | |
| if (net_message.cursize > MAX_MSGLEN) | |
| Sys_Error("Demo message > MAX_MSGLEN"); | |
| r = fread(net_message.data, net_message.cursize, 1, cls.demofile); | |
| if (r != 1) | |
| { | |
| CL_StopPlayback(); | |
| return 0; | |
| } | |
| return 1; | |
| } | |
| while (1) | |
| { | |
| r = NET_GetMessage(cls.netcon); | |
| if ((r != 1) && (r != 2)) | |
| return r; | |
| if ((net_message.cursize == 1) && (net_message.data[0] == svc_nop)) | |
| Con_Printf("<-- server to client keepalive\n"); | |
| else | |
| break; | |
| } | |
| if (cls.demorecording) | |
| CL_WriteDemoMessage(); | |
| return r; | |
| } | |
| void CL_Stop_f(void) | |
| { | |
| if (cmd_source != src_command) | |
| return; | |
| if (!cls.demorecording) | |
| { | |
| Con_Printf("Not recording a demo.\n"); | |
| return; | |
| } | |
| SZ_Clear(&net_message); | |
| MSG_WriteByte(&net_message, svc_disconnect); | |
| CL_WriteDemoMessage(); | |
| fclose(cls.demofile); | |
| cls.demofile = 0; | |
| cls.demorecording = 0; | |
| Con_Printf("Completed demo\n"); | |
| } | |
| void CL_Record_f(void) | |
| { | |
| int32_t c; | |
| char name[MAX_OSPATH]; | |
| int32_t track; | |
| if (cmd_source != src_command) | |
| return; | |
| c = Cmd_Argc(); | |
| if (((c != 2) && (c != 3)) && (c != 4)) | |
| { | |
| Con_Printf("record <demoname> [<map> [cd track]]\n"); | |
| return; | |
| } | |
| if (strstr(Cmd_Argv(1), "..")) | |
| { | |
| Con_Printf("Relative pathnames are not allowed.\n"); | |
| return; | |
| } | |
| if ((c == 2) && (cls.state == ca_connected)) | |
| { | |
| Con_Printf("Can not record - already connected to server\nClient demo recording must be started before connecting\n"); | |
| return; | |
| } | |
| if (c == 4) | |
| { | |
| track = atoi(Cmd_Argv(3)); | |
| Con_Printf("Forcing CD track to %i\n", cls.forcetrack); | |
| } | |
| else | |
| track = -1; | |
| sprintf(name, "%s/%s", com_gamedir, Cmd_Argv(1)); | |
| if (c > 2) | |
| Cmd_ExecuteString(va("map %s", Cmd_Argv(2)), src_command); | |
| COM_DefaultExtension(name, ".dem"); | |
| Con_Printf("recording to %s.\n", name); | |
| cls.demofile = fopen(name, "wb"); | |
| if (!cls.demofile) | |
| { | |
| Con_Printf("ERROR: couldn't open.\n"); | |
| return; | |
| } | |
| cls.forcetrack = track; | |
| fprintf(cls.demofile, "%i\n", cls.forcetrack); | |
| cls.demorecording = 1; | |
| } | |
| void CL_PlayDemo_f(void) | |
| { | |
| char name[256]; | |
| int32_t c; | |
| bool neg = 0; | |
| if (cmd_source != src_command) | |
| return; | |
| if (Cmd_Argc() != 2) | |
| { | |
| Con_Printf("play <demoname> : plays a demo\n"); | |
| return; | |
| } | |
| CL_Disconnect(); | |
| strcpy(name, Cmd_Argv(1)); | |
| COM_DefaultExtension(name, ".dem"); | |
| Con_Printf("Playing demo from %s.\n", name); | |
| COM_FOpenFile(name, &cls.demofile); | |
| if (!cls.demofile) | |
| { | |
| Con_Printf("ERROR: couldn't open.\n"); | |
| cls.demonum = -1; | |
| return; | |
| } | |
| cls.demoplayback = 1; | |
| cls.state = ca_connected; | |
| cls.forcetrack = 0; | |
| while ((c = getc(cls.demofile)) != '\n') | |
| if (c == '-') | |
| neg = 1; | |
| else | |
| cls.forcetrack = (cls.forcetrack * 10) + (c - '0'); | |
| if (neg) | |
| cls.forcetrack = -cls.forcetrack; | |
| } | |
| static void CL_FinishTimeDemo(void) | |
| { | |
| int32_t frames; | |
| float time; | |
| cls.timedemo = 0; | |
| frames = (host_framecount - cls.td_startframe) - 1; | |
| time = realtime - cls.td_starttime; | |
| if (!time) | |
| time = 1; | |
| Con_Printf("%i frames %5.1f seconds %5.1f fps\n", frames, time, frames / time); | |
| Sys_Quit(); | |
| } | |
| void CL_TimeDemo_f(void) | |
| { | |
| if (cmd_source != src_command) | |
| return; | |
| if (Cmd_Argc() != 2) | |
| { | |
| Con_Printf("timedemo <demoname> : gets demo speeds\n"); | |
| return; | |
| } | |
| CL_PlayDemo_f(); | |
| cls.timedemo = 1; | |
| cls.td_startframe = host_framecount; | |
| cls.td_lastframe = -1; | |
| } | |
| static void KeyDown(kbutton_t *b) | |
| { | |
| int32_t k; | |
| char *c; | |
| c = Cmd_Argv(1); | |
| if (c[0]) | |
| k = atoi(c); | |
| else | |
| k = -1; | |
| if ((k == b->down[0]) || (k == b->down[1])) | |
| return; | |
| if (!b->down[0]) | |
| b->down[0] = k; | |
| else | |
| if (!b->down[1]) | |
| b->down[1] = k; | |
| else | |
| { | |
| Con_Printf("Three keys down for a button!\n"); | |
| return; | |
| } | |
| if (b->state & 1) | |
| return; | |
| b->state |= 1 + 2; | |
| } | |
| static void KeyUp(kbutton_t *b) | |
| { | |
| int32_t k; | |
| char *c; | |
| c = Cmd_Argv(1); | |
| if (c[0]) | |
| k = atoi(c); | |
| else | |
| { | |
| b->down[0] = (b->down[1] = 0); | |
| b->state = 4; | |
| return; | |
| } | |
| if (b->down[0] == k) | |
| b->down[0] = 0; | |
| else | |
| if (b->down[1] == k) | |
| b->down[1] = 0; | |
| else | |
| return; | |
| if (b->down[0] || b->down[1]) | |
| return; | |
| if (!(b->state & 1)) | |
| return; | |
| b->state &= ~1; | |
| b->state |= 4; | |
| } | |
| static void IN_KLookDown(void) | |
| { | |
| KeyDown(&in_klook); | |
| } | |
| static void IN_KLookUp(void) | |
| { | |
| KeyUp(&in_klook); | |
| } | |
| static void IN_MLookDown(void) | |
| { | |
| KeyDown(&in_mlook); | |
| } | |
| static void IN_MLookUp(void) | |
| { | |
| KeyUp(&in_mlook); | |
| if ((!(in_mlook.state & 1)) && lookspring.value) | |
| V_StartPitchDrift(); | |
| } | |
| static void IN_UpDown(void) | |
| { | |
| KeyDown(&in_up); | |
| } | |
| static void IN_UpUp(void) | |
| { | |
| KeyUp(&in_up); | |
| } | |
| static void IN_DownDown(void) | |
| { | |
| KeyDown(&in_down); | |
| } | |
| static void IN_DownUp(void) | |
| { | |
| KeyUp(&in_down); | |
| } | |
| static void IN_LeftDown(void) | |
| { | |
| KeyDown(&in_left); | |
| } | |
| static void IN_LeftUp(void) | |
| { | |
| KeyUp(&in_left); | |
| } | |
| static void IN_RightDown(void) | |
| { | |
| KeyDown(&in_right); | |
| } | |
| static void IN_RightUp(void) | |
| { | |
| KeyUp(&in_right); | |
| } | |
| static void IN_ForwardDown(void) | |
| { | |
| KeyDown(&in_forward); | |
| } | |
| static void IN_ForwardUp(void) | |
| { | |
| KeyUp(&in_forward); | |
| } | |
| static void IN_BackDown(void) | |
| { | |
| KeyDown(&in_back); | |
| } | |
| static void IN_BackUp(void) | |
| { | |
| KeyUp(&in_back); | |
| } | |
| static void IN_LookupDown(void) | |
| { | |
| KeyDown(&in_lookup); | |
| } | |
| static void IN_LookupUp(void) | |
| { | |
| KeyUp(&in_lookup); | |
| } | |
| static void IN_LookdownDown(void) | |
| { | |
| KeyDown(&in_lookdown); | |
| } | |
| static void IN_LookdownUp(void) | |
| { | |
| KeyUp(&in_lookdown); | |
| } | |
| static void IN_MoveleftDown(void) | |
| { | |
| KeyDown(&in_moveleft); | |
| } | |
| static void IN_MoveleftUp(void) | |
| { | |
| KeyUp(&in_moveleft); | |
| } | |
| static void IN_MoverightDown(void) | |
| { | |
| KeyDown(&in_moveright); | |
| } | |
| static void IN_MoverightUp(void) | |
| { | |
| KeyUp(&in_moveright); | |
| } | |
| static void IN_SpeedDown(void) | |
| { | |
| KeyDown(&in_speed); | |
| } | |
| static void IN_SpeedUp(void) | |
| { | |
| KeyUp(&in_speed); | |
| } | |
| static void IN_StrafeDown(void) | |
| { | |
| KeyDown(&in_strafe); | |
| } | |
| static void IN_StrafeUp(void) | |
| { | |
| KeyUp(&in_strafe); | |
| } | |
| static void IN_AttackDown(void) | |
| { | |
| KeyDown(&in_attack); | |
| } | |
| static void IN_AttackUp(void) | |
| { | |
| KeyUp(&in_attack); | |
| } | |
| static void IN_UseDown(void) | |
| { | |
| KeyDown(&in_use); | |
| } | |
| static void IN_UseUp(void) | |
| { | |
| KeyUp(&in_use); | |
| } | |
| static void IN_JumpDown(void) | |
| { | |
| KeyDown(&in_jump); | |
| } | |
| static void IN_JumpUp(void) | |
| { | |
| KeyUp(&in_jump); | |
| } | |
| static void IN_Impulse(void) | |
| { | |
| in_impulse = (int32_t) strtol(Cmd_Argv(1), 0, 0); | |
| } | |
| float CL_KeyState(kbutton_t *key) | |
| { | |
| float val; | |
| bool impulsedown; | |
| bool impulseup; | |
| bool down; | |
| impulsedown = key->state & 2; | |
| impulseup = key->state & 4; | |
| down = key->state & 1; | |
| val = 0; | |
| if (impulsedown && (!impulseup)) | |
| if (down) | |
| val = 0.5; | |
| else | |
| val = 0; | |
| if (impulseup && (!impulsedown)) | |
| if (down) | |
| val = 0; | |
| else | |
| val = 0; | |
| if ((!impulsedown) && (!impulseup)) | |
| if (down) | |
| val = 1.0; | |
| else | |
| val = 0; | |
| if (impulsedown && impulseup) | |
| if (down) | |
| val = 0.75; | |
| else | |
| val = 0.25; | |
| key->state &= 1; | |
| return val; | |
| } | |
| static void CL_AdjustAngles(void) | |
| { | |
| float speed; | |
| float up; | |
| float down; | |
| if (in_speed.state & 1) | |
| speed = host_frametime * cl_anglespeedkey.value; | |
| else | |
| speed = host_frametime; | |
| if (!(in_strafe.state & 1)) | |
| { | |
| cl.viewangles[YAW] -= (speed * cl_yawspeed.value) * CL_KeyState(&in_right); | |
| cl.viewangles[YAW] += (speed * cl_yawspeed.value) * CL_KeyState(&in_left); | |
| cl.viewangles[YAW] = anglemod(cl.viewangles[YAW]); | |
| } | |
| if (in_klook.state & 1) | |
| { | |
| V_StopPitchDrift(); | |
| cl.viewangles[PITCH] -= (speed * cl_pitchspeed.value) * CL_KeyState(&in_forward); | |
| cl.viewangles[PITCH] += (speed * cl_pitchspeed.value) * CL_KeyState(&in_back); | |
| } | |
| up = CL_KeyState(&in_lookup); | |
| down = CL_KeyState(&in_lookdown); | |
| cl.viewangles[PITCH] -= (speed * cl_pitchspeed.value) * up; | |
| cl.viewangles[PITCH] += (speed * cl_pitchspeed.value) * down; | |
| if (up || down) | |
| V_StopPitchDrift(); | |
| if (cl.viewangles[PITCH] > 80) | |
| cl.viewangles[PITCH] = 80; | |
| if (cl.viewangles[PITCH] < (-70)) | |
| cl.viewangles[PITCH] = -70; | |
| if (cl.viewangles[ROLL] > 50) | |
| cl.viewangles[ROLL] = 50; | |
| if (cl.viewangles[ROLL] < (-50)) | |
| cl.viewangles[ROLL] = -50; | |
| } | |
| void CL_BaseMove(usercmd_t *cmd) | |
| { | |
| if (cls.signon != SIGNONS) | |
| return; | |
| CL_AdjustAngles(); | |
| memset(cmd, 0, sizeof(*cmd)); | |
| if (in_strafe.state & 1) | |
| { | |
| cmd->sidemove += cl_sidespeed.value * CL_KeyState(&in_right); | |
| cmd->sidemove -= cl_sidespeed.value * CL_KeyState(&in_left); | |
| } | |
| cmd->sidemove += cl_sidespeed.value * CL_KeyState(&in_moveright); | |
| cmd->sidemove -= cl_sidespeed.value * CL_KeyState(&in_moveleft); | |
| cmd->upmove += cl_upspeed.value * CL_KeyState(&in_up); | |
| cmd->upmove -= cl_upspeed.value * CL_KeyState(&in_down); | |
| if (!(in_klook.state & 1)) | |
| { | |
| cmd->forwardmove += cl_forwardspeed.value * CL_KeyState(&in_forward); | |
| cmd->forwardmove -= cl_backspeed.value * CL_KeyState(&in_back); | |
| } | |
| if (in_speed.state & 1) | |
| { | |
| cmd->forwardmove *= cl_movespeedkey.value; | |
| cmd->sidemove *= cl_movespeedkey.value; | |
| cmd->upmove *= cl_movespeedkey.value; | |
| } | |
| } | |
| void CL_SendMove(usercmd_t *cmd) | |
| { | |
| int32_t i; | |
| int32_t bits; | |
| sizebuf_t buf; | |
| uint8_t data[128]; | |
| buf.maxsize = 128; | |
| buf.cursize = 0; | |
| buf.data = data; | |
| cl.cmd = *cmd; | |
| MSG_WriteByte(&buf, clc_move); | |
| MSG_WriteFloat(&buf, cl.mtime[0]); | |
| for (i = 0; i < 3; i++) | |
| MSG_WriteAngle(&buf, cl.viewangles[i]); | |
| MSG_WriteShort(&buf, cmd->forwardmove); | |
| MSG_WriteShort(&buf, cmd->sidemove); | |
| MSG_WriteShort(&buf, cmd->upmove); | |
| bits = 0; | |
| if (in_attack.state & 3) | |
| bits |= 1; | |
| in_attack.state &= ~2; | |
| if (in_jump.state & 3) | |
| bits |= 2; | |
| in_jump.state &= ~2; | |
| MSG_WriteByte(&buf, bits); | |
| MSG_WriteByte(&buf, in_impulse); | |
| in_impulse = 0; | |
| if (cls.demoplayback) | |
| return; | |
| if ((++cl.movemessages) <= 2) | |
| return; | |
| if (NET_SendUnreliableMessage(cls.netcon, &buf) == (-1)) | |
| { | |
| Con_Printf("CL_SendMove: lost server connection\n"); | |
| CL_Disconnect(); | |
| } | |
| } | |
| void CL_InitInput(void) | |
| { | |
| Cmd_AddCommand("+moveup", IN_UpDown); | |
| Cmd_AddCommand("-moveup", IN_UpUp); | |
| Cmd_AddCommand("+movedown", IN_DownDown); | |
| Cmd_AddCommand("-movedown", IN_DownUp); | |
| Cmd_AddCommand("+left", IN_LeftDown); | |
| Cmd_AddCommand("-left", IN_LeftUp); | |
| Cmd_AddCommand("+right", IN_RightDown); | |
| Cmd_AddCommand("-right", IN_RightUp); | |
| Cmd_AddCommand("+forward", IN_ForwardDown); | |
| Cmd_AddCommand("-forward", IN_ForwardUp); | |
| Cmd_AddCommand("+back", IN_BackDown); | |
| Cmd_AddCommand("-back", IN_BackUp); | |
| Cmd_AddCommand("+lookup", IN_LookupDown); | |
| Cmd_AddCommand("-lookup", IN_LookupUp); | |
| Cmd_AddCommand("+lookdown", IN_LookdownDown); | |
| Cmd_AddCommand("-lookdown", IN_LookdownUp); | |
| Cmd_AddCommand("+strafe", IN_StrafeDown); | |
| Cmd_AddCommand("-strafe", IN_StrafeUp); | |
| Cmd_AddCommand("+moveleft", IN_MoveleftDown); | |
| Cmd_AddCommand("-moveleft", IN_MoveleftUp); | |
| Cmd_AddCommand("+moveright", IN_MoverightDown); | |
| Cmd_AddCommand("-moveright", IN_MoverightUp); | |
| Cmd_AddCommand("+speed", IN_SpeedDown); | |
| Cmd_AddCommand("-speed", IN_SpeedUp); | |
| Cmd_AddCommand("+attack", IN_AttackDown); | |
| Cmd_AddCommand("-attack", IN_AttackUp); | |
| Cmd_AddCommand("+use", IN_UseDown); | |
| Cmd_AddCommand("-use", IN_UseUp); | |
| Cmd_AddCommand("+jump", IN_JumpDown); | |
| Cmd_AddCommand("-jump", IN_JumpUp); | |
| Cmd_AddCommand("impulse", IN_Impulse); | |
| Cmd_AddCommand("+klook", IN_KLookDown); | |
| Cmd_AddCommand("-klook", IN_KLookUp); | |
| Cmd_AddCommand("+mlook", IN_MLookDown); | |
| Cmd_AddCommand("-mlook", IN_MLookUp); | |
| } | |
| void CL_ClearState(void) | |
| { | |
| int32_t i; | |
| if (!sv.active) | |
| Host_ClearMemory(); | |
| memset(&cl, 0, sizeof(cl)); | |
| SZ_Clear(&cls.message); | |
| memset(cl_efrags, 0, sizeof(cl_efrags)); | |
| memset(cl_entities, 0, sizeof(cl_entities)); | |
| memset(cl_dlights, 0, sizeof(cl_dlights)); | |
| memset(cl_lightstyle, 0, sizeof(cl_lightstyle)); | |
| memset(cl_temp_entities, 0, sizeof(cl_temp_entities)); | |
| memset(cl_beams, 0, sizeof(cl_beams)); | |
| cl.free_efrags = cl_efrags; | |
| for (i = 0; i < (MAX_EFRAGS - 1); i++) | |
| cl.free_efrags[i].entnext = &cl.free_efrags[i + 1]; | |
| cl.free_efrags[i].entnext = 0; | |
| } | |
| void CL_Disconnect(void) | |
| { | |
| S_StopAllSounds(1); | |
| if (cls.demoplayback) | |
| CL_StopPlayback(); | |
| else | |
| if (cls.state == ca_connected) | |
| { | |
| if (cls.demorecording) | |
| CL_Stop_f(); | |
| Con_DPrintf("Sending clc_disconnect\n"); | |
| SZ_Clear(&cls.message); | |
| MSG_WriteByte(&cls.message, clc_disconnect); | |
| NET_SendUnreliableMessage(cls.netcon, &cls.message); | |
| SZ_Clear(&cls.message); | |
| NET_Close(cls.netcon); | |
| cls.state = ca_disconnected; | |
| if (sv.active) | |
| Host_ShutdownServer(0); | |
| } | |
| cls.demoplayback = (cls.timedemo = 0); | |
| cls.signon = 0; | |
| } | |
| void CL_Disconnect_f(void) | |
| { | |
| CL_Disconnect(); | |
| if (sv.active) | |
| Host_ShutdownServer(0); | |
| } | |
| void CL_EstablishConnection(char *host) | |
| { | |
| if (cls.state == ca_dedicated) | |
| return; | |
| if (cls.demoplayback) | |
| return; | |
| CL_Disconnect(); | |
| cls.netcon = NET_Connect(host); | |
| if (!cls.netcon) | |
| Host_Error("CL_Connect: connect failed\n"); | |
| Con_DPrintf("CL_EstablishConnection: connected to %s\n", host); | |
| cls.demonum = -1; | |
| cls.state = ca_connected; | |
| cls.signon = 0; | |
| } | |
| void CL_SignonReply(void) | |
| { | |
| char str[8192]; | |
| Con_DPrintf("CL_SignonReply: %i\n", cls.signon); | |
| switch (cls.signon) | |
| { | |
| case 1: | |
| MSG_WriteByte(&cls.message, clc_stringcmd); | |
| MSG_WriteString(&cls.message, "prespawn"); | |
| break; | |
| case 2: | |
| MSG_WriteByte(&cls.message, clc_stringcmd); | |
| MSG_WriteString(&cls.message, va("name \"%s\"\n", cl_name.string)); | |
| MSG_WriteByte(&cls.message, clc_stringcmd); | |
| MSG_WriteString(&cls.message, va("color %i %i\n", ((int32_t) cl_color.value) >> 4, ((int32_t) cl_color.value) & 15)); | |
| MSG_WriteByte(&cls.message, clc_stringcmd); | |
| sprintf(str, "spawn %s", cls.spawnparms); | |
| MSG_WriteString(&cls.message, str); | |
| break; | |
| case 3: | |
| MSG_WriteByte(&cls.message, clc_stringcmd); | |
| MSG_WriteString(&cls.message, "begin"); | |
| Cache_Report(); | |
| break; | |
| case 4: | |
| SCR_EndLoadingPlaque(); | |
| break; | |
| } | |
| } | |
| void CL_NextDemo(void) | |
| { | |
| char str[1024]; | |
| if (cls.demonum == (-1)) | |
| return; | |
| SCR_BeginLoadingPlaque(); | |
| if ((!cls.demos[cls.demonum][0]) || (cls.demonum == MAX_DEMOS)) | |
| { | |
| cls.demonum = 0; | |
| if (!cls.demos[cls.demonum][0]) | |
| { | |
| Con_Printf("No demos listed with startdemos\n"); | |
| cls.demonum = -1; | |
| return; | |
| } | |
| } | |
| sprintf(str, "playdemo %s\n", cls.demos[cls.demonum]); | |
| Cbuf_InsertText(str); | |
| cls.demonum++; | |
| } | |
| static void CL_PrintEntities_f(void) | |
| { | |
| entity_t *ent; | |
| int32_t i; | |
| for (i = 0, ent = cl_entities; i < cl.num_entities; i++, ent++) | |
| { | |
| Con_Printf("%3i:", i); | |
| if (!ent->model) | |
| { | |
| Con_Printf("EMPTY\n"); | |
| continue; | |
| } | |
| Con_Printf("%s:%2i (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n", ent->model->name, ent->frame, ent->origin[0], ent->origin[1], ent->origin[2], ent->angles[0], ent->angles[1], ent->angles[2]); | |
| } | |
| } | |
| static void SetPal(int32_t i) | |
| { | |
| } | |
| dlight_t *CL_AllocDlight(int32_t key) | |
| { | |
| int32_t i; | |
| dlight_t *dl; | |
| if (key) | |
| { | |
| dl = cl_dlights; | |
| for (i = 0; i < MAX_DLIGHTS; i++, dl++) | |
| { | |
| if (dl->key == key) | |
| { | |
| memset(dl, 0, sizeof(*dl)); | |
| dl->key = key; | |
| return dl; | |
| } | |
| } | |
| } | |
| dl = cl_dlights; | |
| for (i = 0; i < MAX_DLIGHTS; i++, dl++) | |
| { | |
| if (dl->die < cl.time) | |
| { | |
| memset(dl, 0, sizeof(*dl)); | |
| dl->key = key; | |
| return dl; | |
| } | |
| } | |
| dl = &cl_dlights[0]; | |
| memset(dl, 0, sizeof(*dl)); | |
| dl->key = key; | |
| return dl; | |
| } | |
| void CL_DecayLights(void) | |
| { | |
| int32_t i; | |
| dlight_t *dl; | |
| float time; | |
| time = cl.time - cl.oldtime; | |
| dl = cl_dlights; | |
| for (i = 0; i < MAX_DLIGHTS; i++, dl++) | |
| { | |
| if ((dl->die < cl.time) || (!dl->radius)) | |
| continue; | |
| dl->radius -= time * dl->decay; | |
| if (dl->radius < 0) | |
| dl->radius = 0; | |
| } | |
| } | |
| static float CL_LerpPoint(void) | |
| { | |
| float f; | |
| float frac; | |
| f = cl.mtime[0] - cl.mtime[1]; | |
| if ((((!f) || cl_nolerp.value) || cls.timedemo) || sv.active) | |
| { | |
| cl.time = cl.mtime[0]; | |
| return 1; | |
| } | |
| if (f > 0.1) | |
| { | |
| cl.mtime[1] = cl.mtime[0] - 0.1; | |
| f = 0.1; | |
| } | |
| frac = (cl.time - cl.mtime[1]) / f; | |
| if (frac < 0) | |
| { | |
| if (frac < (-0.01)) | |
| { | |
| SetPal(1); | |
| cl.time = cl.mtime[1]; | |
| } | |
| frac = 0; | |
| } | |
| else | |
| if (frac > 1) | |
| { | |
| if (frac > 1.01) | |
| { | |
| SetPal(2); | |
| cl.time = cl.mtime[0]; | |
| } | |
| frac = 1; | |
| } | |
| else | |
| SetPal(0); | |
| return frac; | |
| } | |
| static void CL_RelinkEntities(void) | |
| { | |
| entity_t *ent; | |
| int32_t i; | |
| int32_t j; | |
| float frac; | |
| float f; | |
| float d; | |
| vec3_t delta; | |
| float bobjrotate; | |
| vec3_t oldorg; | |
| dlight_t *dl; | |
| frac = CL_LerpPoint(); | |
| cl_numvisedicts = 0; | |
| for (i = 0; i < 3; i++) | |
| cl.velocity[i] = cl.mvelocity[1][i] + (frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i])); | |
| if (cls.demoplayback) | |
| { | |
| for (j = 0; j < 3; j++) | |
| { | |
| d = cl.mviewangles[0][j] - cl.mviewangles[1][j]; | |
| if (d > 180) | |
| d -= 360; | |
| else | |
| if (d < (-180)) | |
| d += 360; | |
| cl.viewangles[j] = cl.mviewangles[1][j] + (frac * d); | |
| } | |
| } | |
| bobjrotate = anglemod(100 * cl.time); | |
| for (i = 1, ent = cl_entities + 1; i < cl.num_entities; i++, ent++) | |
| { | |
| if (!ent->model) | |
| { | |
| if (ent->forcelink) | |
| R_RemoveEfrags(ent); | |
| continue; | |
| } | |
| if (ent->msgtime != cl.mtime[0]) | |
| { | |
| ent->model = 0; | |
| continue; | |
| } | |
| VectorCopy(ent->origin, oldorg); | |
| if (ent->forcelink) | |
| { | |
| VectorCopy(ent->msg_origins[0], ent->origin); | |
| VectorCopy(ent->msg_angles[0], ent->angles); | |
| } | |
| else | |
| { | |
| f = frac; | |
| for (j = 0; j < 3; j++) | |
| { | |
| delta[j] = ent->msg_origins[0][j] - ent->msg_origins[1][j]; | |
| if ((delta[j] > 100) || (delta[j] < (-100))) | |
| f = 1; | |
| } | |
| for (j = 0; j < 3; j++) | |
| { | |
| ent->origin[j] = ent->msg_origins[1][j] + (f * delta[j]); | |
| d = ent->msg_angles[0][j] - ent->msg_angles[1][j]; | |
| if (d > 180) | |
| d -= 360; | |
| else | |
| if (d < (-180)) | |
| d += 360; | |
| ent->angles[j] = ent->msg_angles[1][j] + (f * d); | |
| } | |
| } | |
| if (ent->model->flags & EF_ROTATE) | |
| ent->angles[1] = bobjrotate; | |
| if (ent->effects & EF_BRIGHTFIELD) | |
| R_EntityParticles(ent); | |
| if (ent->effects & EF_MUZZLEFLASH) | |
| { | |
| vec3_t fv; | |
| vec3_t rv; | |
| vec3_t uv; | |
| dl = CL_AllocDlight(i); | |
| VectorCopy(ent->origin, dl->origin); | |
| dl->origin[2] += 16; | |
| AngleVectors(ent->angles, fv, rv, uv); | |
| VectorMA(dl->origin, 18, fv, dl->origin); | |
| dl->radius = 200 + (rand() & 31); | |
| dl->minlight = 32; | |
| dl->die = cl.time + 0.1; | |
| } | |
| if (ent->effects & EF_BRIGHTLIGHT) | |
| { | |
| dl = CL_AllocDlight(i); | |
| VectorCopy(ent->origin, dl->origin); | |
| dl->origin[2] += 16; | |
| dl->radius = 400 + (rand() & 31); | |
| dl->die = cl.time + 0.001; | |
| } | |
| if (ent->effects & EF_DIMLIGHT) | |
| { | |
| dl = CL_AllocDlight(i); | |
| VectorCopy(ent->origin, dl->origin); | |
| dl->radius = 200 + (rand() & 31); | |
| dl->die = cl.time + 0.001; | |
| } | |
| if (ent->model->flags & EF_GIB) | |
| R_RocketTrail(oldorg, ent->origin, 2); | |
| else | |
| if (ent->model->flags & EF_ZOMGIB) | |
| R_RocketTrail(oldorg, ent->origin, 4); | |
| else | |
| if (ent->model->flags & EF_TRACER) | |
| R_RocketTrail(oldorg, ent->origin, 3); | |
| else | |
| if (ent->model->flags & EF_TRACER2) | |
| R_RocketTrail(oldorg, ent->origin, 5); | |
| else | |
| if (ent->model->flags & EF_ROCKET) | |
| { | |
| R_RocketTrail(oldorg, ent->origin, 0); | |
| dl = CL_AllocDlight(i); | |
| VectorCopy(ent->origin, dl->origin); | |
| dl->radius = 200; | |
| dl->die = cl.time + 0.01; | |
| } | |
| else | |
| if (ent->model->flags & EF_GRENADE) | |
| R_RocketTrail(oldorg, ent->origin, 1); | |
| else | |
| if (ent->model->flags & EF_TRACER3) | |
| R_RocketTrail(oldorg, ent->origin, 6); | |
| ent->forcelink = 0; | |
| if ((i == cl.viewentity) && (!chase_active.value)) | |
| continue; | |
| if (cl_numvisedicts < MAX_VISEDICTS) | |
| { | |
| cl_visedicts[cl_numvisedicts] = ent; | |
| cl_numvisedicts++; | |
| } | |
| } | |
| } | |
| int32_t CL_ReadFromServer(void) | |
| { | |
| int32_t ret; | |
| cl.oldtime = cl.time; | |
| cl.time += host_frametime; | |
| do | |
| { | |
| ret = CL_GetMessage(); | |
| if (ret == (-1)) | |
| Host_Error("CL_ReadFromServer: lost server connection"); | |
| if (!ret) | |
| break; | |
| cl.last_received_message = realtime; | |
| CL_ParseServerMessage(); | |
| } | |
| while (ret && (cls.state == ca_connected)); | |
| if (cl_shownet.value) | |
| Con_Printf("\n"); | |
| CL_RelinkEntities(); | |
| CL_UpdateTEnts(); | |
| return 0; | |
| } | |
| void CL_SendCmd(void) | |
| { | |
| usercmd_t cmd; | |
| if (cls.state != ca_connected) | |
| return; | |
| if (cls.signon == SIGNONS) | |
| { | |
| CL_BaseMove(&cmd); | |
| IN_Move(&cmd); | |
| CL_SendMove(&cmd); | |
| } | |
| if (cls.demoplayback) | |
| { | |
| SZ_Clear(&cls.message); | |
| return; | |
| } | |
| if (!cls.message.cursize) | |
| return; | |
| if (!NET_CanSendMessage(cls.netcon)) | |
| { | |
| Con_DPrintf("CL_WriteToServer: can't send\n"); | |
| return; | |
| } | |
| if (NET_SendMessage(cls.netcon, &cls.message) == (-1)) | |
| Host_Error("CL_WriteToServer: lost server connection"); | |
| SZ_Clear(&cls.message); | |
| } | |
| void CL_Init(void) | |
| { | |
| SZ_Alloc(&cls.message, 1024); | |
| CL_InitInput(); | |
| CL_InitTEnts(); | |
| Cvar_RegisterVariable(&cl_name); | |
| Cvar_RegisterVariable(&cl_color); | |
| Cvar_RegisterVariable(&cl_upspeed); | |
| Cvar_RegisterVariable(&cl_forwardspeed); | |
| Cvar_RegisterVariable(&cl_backspeed); | |
| Cvar_RegisterVariable(&cl_sidespeed); | |
| Cvar_RegisterVariable(&cl_movespeedkey); | |
| Cvar_RegisterVariable(&cl_yawspeed); | |
| Cvar_RegisterVariable(&cl_pitchspeed); | |
| Cvar_RegisterVariable(&cl_anglespeedkey); | |
| Cvar_RegisterVariable(&cl_shownet); | |
| Cvar_RegisterVariable(&cl_nolerp); | |
| Cvar_RegisterVariable(&lookspring); | |
| Cvar_RegisterVariable(&lookstrafe); | |
| Cvar_RegisterVariable(&sensitivity); | |
| Cvar_RegisterVariable(&m_pitch); | |
| Cvar_RegisterVariable(&m_yaw); | |
| Cvar_RegisterVariable(&m_forward); | |
| Cvar_RegisterVariable(&m_side); | |
| Cmd_AddCommand("entities", CL_PrintEntities_f); | |
| Cmd_AddCommand("disconnect", CL_Disconnect_f); | |
| Cmd_AddCommand("record", CL_Record_f); | |
| Cmd_AddCommand("stop", CL_Stop_f); | |
| Cmd_AddCommand("playdemo", CL_PlayDemo_f); | |
| Cmd_AddCommand("timedemo", CL_TimeDemo_f); | |
| } | |
| static entity_t *CL_EntityNum(int32_t num) | |
| { | |
| if (num >= cl.num_entities) | |
| { | |
| if (num >= MAX_EDICTS) | |
| Host_Error("CL_EntityNum: %i is an invalid number", num); | |
| while (cl.num_entities <= num) | |
| { | |
| cl_entities[cl.num_entities].colormap = vid.colormap; | |
| cl.num_entities++; | |
| } | |
| } | |
| return &cl_entities[num]; | |
| } | |
| static void CL_ParseStartSoundPacket(void) | |
| { | |
| vec3_t pos; | |
| int32_t channel; | |
| int32_t ent; | |
| int32_t sound_num; | |
| int32_t volume; | |
| int32_t field_mask; | |
| float attenuation; | |
| int32_t i; | |
| field_mask = MSG_ReadByte(); | |
| if (field_mask & SND_VOLUME) | |
| volume = MSG_ReadByte(); | |
| else | |
| volume = DEFAULT_SOUND_PACKET_VOLUME; | |
| if (field_mask & SND_ATTENUATION) | |
| attenuation = MSG_ReadByte() / 64.0; | |
| else | |
| attenuation = DEFAULT_SOUND_PACKET_ATTENUATION; | |
| channel = MSG_ReadShort(); | |
| sound_num = MSG_ReadByte(); | |
| ent = channel >> 3; | |
| channel &= 7; | |
| if (ent > MAX_EDICTS) | |
| Host_Error("CL_ParseStartSoundPacket: ent = %i", ent); | |
| for (i = 0; i < 3; i++) | |
| pos[i] = MSG_ReadCoord(); | |
| S_StartSound(ent, channel, cl.sound_precache[sound_num], pos, volume / 255.0, attenuation); | |
| } | |
| static void CL_KeepaliveMessage(void) | |
| { | |
| float time; | |
| static float lastmsg; | |
| int32_t ret; | |
| sizebuf_t old; | |
| uint8_t olddata[8192]; | |
| if (sv.active) | |
| return; | |
| if (cls.demoplayback) | |
| return; | |
| old = net_message; | |
| memcpy(olddata, net_message.data, net_message.cursize); | |
| do | |
| { | |
| ret = CL_GetMessage(); | |
| switch (ret) | |
| { | |
| default: | |
| Host_Error("CL_KeepaliveMessage: CL_GetMessage failed"); | |
| case 0: | |
| break; | |
| case 1: | |
| Host_Error("CL_KeepaliveMessage: received a message"); | |
| break; | |
| case 2: | |
| if (MSG_ReadByte() != svc_nop) | |
| Host_Error("CL_KeepaliveMessage: datagram wasn't a nop"); | |
| break; | |
| } | |
| } | |
| while (ret); | |
| net_message = old; | |
| memcpy(net_message.data, olddata, net_message.cursize); | |
| time = Sys_FloatTime(); | |
| if ((time - lastmsg) < 5) | |
| return; | |
| lastmsg = time; | |
| Con_Printf("--> client to server keepalive\n"); | |
| MSG_WriteByte(&cls.message, clc_nop); | |
| NET_SendMessage(cls.netcon, &cls.message); | |
| SZ_Clear(&cls.message); | |
| } | |
| static void CL_ParseServerInfo(void) | |
| { | |
| char *str; | |
| int32_t i; | |
| int32_t nummodels; | |
| int32_t numsounds; | |
| char model_precache[MAX_MODELS][MAX_QPATH]; | |
| char sound_precache[MAX_SOUNDS][MAX_QPATH]; | |
| Con_DPrintf("Serverinfo packet received.\n"); | |
| CL_ClearState(); | |
| i = MSG_ReadLong(); | |
| if (i != PROTOCOL_VERSION) | |
| { | |
| Con_Printf("Server returned version %i, not %i", i, PROTOCOL_VERSION); | |
| return; | |
| } | |
| cl.maxclients = MSG_ReadByte(); | |
| if ((cl.maxclients < 1) || (cl.maxclients > MAX_SCOREBOARD)) | |
| { | |
| Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients); | |
| return; | |
| } | |
| cl.scores = Hunk_AllocName(cl.maxclients * (sizeof(*cl.scores)), "scores"); | |
| cl.gametype = MSG_ReadByte(); | |
| str = MSG_ReadString(); | |
| strncpy(cl.levelname, str, (sizeof(cl.levelname)) - 1); | |
| Con_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n"); | |
| Con_Printf("%c%s\n", 2, str); | |
| memset(cl.model_precache, 0, sizeof(cl.model_precache)); | |
| for (nummodels = 1;; nummodels++) | |
| { | |
| str = MSG_ReadString(); | |
| if (!str[0]) | |
| break; | |
| if (nummodels == MAX_MODELS) | |
| { | |
| Con_Printf("Server sent too many model precaches\n"); | |
| return; | |
| } | |
| strcpy(model_precache[nummodels], str); | |
| Mod_TouchModel(str); | |
| } | |
| memset(cl.sound_precache, 0, sizeof(cl.sound_precache)); | |
| for (numsounds = 1;; numsounds++) | |
| { | |
| str = MSG_ReadString(); | |
| if (!str[0]) | |
| break; | |
| if (numsounds == MAX_SOUNDS) | |
| { | |
| Con_Printf("Server sent too many sound precaches\n"); | |
| return; | |
| } | |
| strcpy(sound_precache[numsounds], str); | |
| S_TouchSound(str); | |
| } | |
| for (i = 1; i < nummodels; i++) | |
| { | |
| cl.model_precache[i] = Mod_ForName(model_precache[i], 0); | |
| if (cl.model_precache[i] == 0) | |
| { | |
| Con_Printf("Model %s not found\n", model_precache[i]); | |
| return; | |
| } | |
| CL_KeepaliveMessage(); | |
| } | |
| S_BeginPrecaching(); | |
| for (i = 1; i < numsounds; i++) | |
| { | |
| cl.sound_precache[i] = S_PrecacheSound(sound_precache[i]); | |
| CL_KeepaliveMessage(); | |
| } | |
| S_EndPrecaching(); | |
| cl_entities[0].model = (cl.worldmodel = cl.model_precache[1]); | |
| R_NewMap(); | |
| Hunk_Check(); | |
| noclip_anglehack = 0; | |
| } | |
| static void CL_ParseUpdate(int32_t bits) | |
| { | |
| int32_t i; | |
| model_t *model; | |
| int32_t modnum; | |
| bool forcelink; | |
| entity_t *ent; | |
| int32_t num; | |
| int32_t skin; | |
| if (cls.signon == (SIGNONS - 1)) | |
| { | |
| cls.signon = SIGNONS; | |
| CL_SignonReply(); | |
| } | |
| if (bits & U_MOREBITS) | |
| { | |
| i = MSG_ReadByte(); | |
| bits |= i << 8; | |
| } | |
| if (bits & U_LONGENTITY) | |
| num = MSG_ReadShort(); | |
| else | |
| num = MSG_ReadByte(); | |
| ent = CL_EntityNum(num); | |
| for (i = 0; i < 16; i++) | |
| if (bits & (1 << i)) | |
| bitcounts[i]++; | |
| if (ent->msgtime != cl.mtime[1]) | |
| forcelink = 1; | |
| else | |
| forcelink = 0; | |
| ent->msgtime = cl.mtime[0]; | |
| if (bits & U_MODEL) | |
| { | |
| modnum = MSG_ReadByte(); | |
| if (modnum >= MAX_MODELS) | |
| Host_Error("CL_ParseModel: bad modnum"); | |
| } | |
| else | |
| modnum = ent->baseline.modelindex; | |
| model = cl.model_precache[modnum]; | |
| if (model != ent->model) | |
| { | |
| ent->model = model; | |
| if (model) | |
| { | |
| if (model->synctype == ST_RAND) | |
| ent->syncbase = ((float) (rand() & 0x7fff)) / 0x7fff; | |
| else | |
| ent->syncbase = 0.0; | |
| } | |
| else | |
| forcelink = 1; | |
| } | |
| if (bits & U_FRAME) | |
| ent->frame = MSG_ReadByte(); | |
| else | |
| ent->frame = ent->baseline.frame; | |
| if (bits & U_COLORMAP) | |
| i = MSG_ReadByte(); | |
| else | |
| i = ent->baseline.colormap; | |
| if (!i) | |
| ent->colormap = vid.colormap; | |
| else | |
| { | |
| if (i > cl.maxclients) | |
| Sys_Error("i >= cl.maxclients"); | |
| ent->colormap = cl.scores[i - 1].translations; | |
| } | |
| if (bits & U_SKIN) | |
| ent->skinnum = MSG_ReadByte(); | |
| else | |
| ent->skinnum = ent->baseline.skin; | |
| if (bits & U_EFFECTS) | |
| ent->effects = MSG_ReadByte(); | |
| else | |
| ent->effects = ent->baseline.effects; | |
| VectorCopy(ent->msg_origins[0], ent->msg_origins[1]); | |
| VectorCopy(ent->msg_angles[0], ent->msg_angles[1]); | |
| if (bits & U_ORIGIN1) | |
| ent->msg_origins[0][0] = MSG_ReadCoord(); | |
| else | |
| ent->msg_origins[0][0] = ent->baseline.origin[0]; | |
| if (bits & U_ANGLE1) | |
| ent->msg_angles[0][0] = MSG_ReadAngle(); | |
| else | |
| ent->msg_angles[0][0] = ent->baseline.angles[0]; | |
| if (bits & U_ORIGIN2) | |
| ent->msg_origins[0][1] = MSG_ReadCoord(); | |
| else | |
| ent->msg_origins[0][1] = ent->baseline.origin[1]; | |
| if (bits & U_ANGLE2) | |
| ent->msg_angles[0][1] = MSG_ReadAngle(); | |
| else | |
| ent->msg_angles[0][1] = ent->baseline.angles[1]; | |
| if (bits & U_ORIGIN3) | |
| ent->msg_origins[0][2] = MSG_ReadCoord(); | |
| else | |
| ent->msg_origins[0][2] = ent->baseline.origin[2]; | |
| if (bits & U_ANGLE3) | |
| ent->msg_angles[0][2] = MSG_ReadAngle(); | |
| else | |
| ent->msg_angles[0][2] = ent->baseline.angles[2]; | |
| if (bits & U_NOLERP) | |
| ent->forcelink = 1; | |
| if (forcelink) | |
| { | |
| VectorCopy(ent->msg_origins[0], ent->msg_origins[1]); | |
| VectorCopy(ent->msg_origins[0], ent->origin); | |
| VectorCopy(ent->msg_angles[0], ent->msg_angles[1]); | |
| VectorCopy(ent->msg_angles[0], ent->angles); | |
| ent->forcelink = 1; | |
| } | |
| } | |
| static void CL_ParseBaseline(entity_t *ent) | |
| { | |
| int32_t i; | |
| ent->baseline.modelindex = MSG_ReadByte(); | |
| ent->baseline.frame = MSG_ReadByte(); | |
| ent->baseline.colormap = MSG_ReadByte(); | |
| ent->baseline.skin = MSG_ReadByte(); | |
| for (i = 0; i < 3; i++) | |
| { | |
| ent->baseline.origin[i] = MSG_ReadCoord(); | |
| ent->baseline.angles[i] = MSG_ReadAngle(); | |
| } | |
| } | |
| static void CL_ParseClientdata(int32_t bits) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| if (bits & SU_VIEWHEIGHT) | |
| cl.viewheight = MSG_ReadChar(); | |
| else | |
| cl.viewheight = DEFAULT_VIEWHEIGHT; | |
| if (bits & SU_IDEALPITCH) | |
| cl.idealpitch = MSG_ReadChar(); | |
| else | |
| cl.idealpitch = 0; | |
| VectorCopy(cl.mvelocity[0], cl.mvelocity[1]); | |
| for (i = 0; i < 3; i++) | |
| { | |
| if (bits & (SU_PUNCH1 << i)) | |
| cl.punchangle[i] = MSG_ReadChar(); | |
| else | |
| cl.punchangle[i] = 0; | |
| if (bits & (SU_VELOCITY1 << i)) | |
| cl.mvelocity[0][i] = MSG_ReadChar() * 16; | |
| else | |
| cl.mvelocity[0][i] = 0; | |
| } | |
| i = MSG_ReadLong(); | |
| if (cl.items != i) | |
| { | |
| Sbar_Changed(); | |
| for (j = 0; j < 32; j++) | |
| if ((i & (1 << j)) && (!(cl.items & (1 << j)))) | |
| cl.item_gettime[j] = cl.time; | |
| cl.items = i; | |
| } | |
| cl.onground = (bits & SU_ONGROUND) != 0; | |
| cl.inwater = (bits & SU_INWATER) != 0; | |
| if (bits & SU_WEAPONFRAME) | |
| cl.stats[STAT_WEAPONFRAME] = MSG_ReadByte(); | |
| else | |
| cl.stats[STAT_WEAPONFRAME] = 0; | |
| if (bits & SU_ARMOR) | |
| i = MSG_ReadByte(); | |
| else | |
| i = 0; | |
| if (cl.stats[STAT_ARMOR] != i) | |
| { | |
| cl.stats[STAT_ARMOR] = i; | |
| Sbar_Changed(); | |
| } | |
| if (bits & SU_WEAPON) | |
| i = MSG_ReadByte(); | |
| else | |
| i = 0; | |
| if (cl.stats[STAT_WEAPON] != i) | |
| { | |
| cl.stats[STAT_WEAPON] = i; | |
| Sbar_Changed(); | |
| } | |
| i = MSG_ReadShort(); | |
| if (cl.stats[STAT_HEALTH] != i) | |
| { | |
| cl.stats[STAT_HEALTH] = i; | |
| Sbar_Changed(); | |
| } | |
| i = MSG_ReadByte(); | |
| if (cl.stats[STAT_AMMO] != i) | |
| { | |
| cl.stats[STAT_AMMO] = i; | |
| Sbar_Changed(); | |
| } | |
| for (i = 0; i < 4; i++) | |
| { | |
| j = MSG_ReadByte(); | |
| if (cl.stats[STAT_SHELLS + i] != j) | |
| { | |
| cl.stats[STAT_SHELLS + i] = j; | |
| Sbar_Changed(); | |
| } | |
| } | |
| i = MSG_ReadByte(); | |
| if (standard_quake) | |
| { | |
| if (cl.stats[STAT_ACTIVEWEAPON] != i) | |
| { | |
| cl.stats[STAT_ACTIVEWEAPON] = i; | |
| Sbar_Changed(); | |
| } | |
| } | |
| else | |
| { | |
| if (cl.stats[STAT_ACTIVEWEAPON] != (1 << i)) | |
| { | |
| cl.stats[STAT_ACTIVEWEAPON] = 1 << i; | |
| Sbar_Changed(); | |
| } | |
| } | |
| } | |
| void CL_NewTranslation(int32_t slot) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| int32_t top; | |
| int32_t bottom; | |
| uint8_t *dest; | |
| uint8_t *source; | |
| if (slot > cl.maxclients) | |
| Sys_Error("CL_NewTranslation: slot > cl.maxclients"); | |
| dest = cl.scores[slot].translations; | |
| source = vid.colormap; | |
| memcpy(dest, vid.colormap, sizeof(cl.scores[slot].translations)); | |
| top = cl.scores[slot].colors & 0xf0; | |
| bottom = (cl.scores[slot].colors & 15) << 4; | |
| for (i = 0; i < VID_GRADES; i++, dest += 256, source += 256) | |
| { | |
| if (top < 128) | |
| memcpy(dest + TOP_RANGE, source + top, 16); | |
| else | |
| for (j = 0; j < 16; j++) | |
| dest[TOP_RANGE + j] = source[(top + 15) - j]; | |
| if (bottom < 128) | |
| memcpy(dest + BOTTOM_RANGE, source + bottom, 16); | |
| else | |
| for (j = 0; j < 16; j++) | |
| dest[BOTTOM_RANGE + j] = source[(bottom + 15) - j]; | |
| } | |
| } | |
| static void CL_ParseStatic(void) | |
| { | |
| entity_t *ent; | |
| int32_t i; | |
| i = cl.num_statics; | |
| if (i >= MAX_STATIC_ENTITIES) | |
| Host_Error("Too many static entities"); | |
| ent = &cl_static_entities[i]; | |
| cl.num_statics++; | |
| CL_ParseBaseline(ent); | |
| ent->model = cl.model_precache[ent->baseline.modelindex]; | |
| ent->frame = ent->baseline.frame; | |
| ent->colormap = vid.colormap; | |
| ent->skinnum = ent->baseline.skin; | |
| ent->effects = ent->baseline.effects; | |
| VectorCopy(ent->baseline.origin, ent->origin); | |
| VectorCopy(ent->baseline.angles, ent->angles); | |
| R_AddEfrags(ent); | |
| } | |
| static void CL_ParseStaticSound(void) | |
| { | |
| vec3_t org; | |
| int32_t sound_num; | |
| int32_t vol; | |
| int32_t atten; | |
| int32_t i; | |
| for (i = 0; i < 3; i++) | |
| org[i] = MSG_ReadCoord(); | |
| sound_num = MSG_ReadByte(); | |
| vol = MSG_ReadByte(); | |
| atten = MSG_ReadByte(); | |
| S_StaticSound(cl.sound_precache[sound_num], org, vol, atten); | |
| } | |
| void CL_ParseServerMessage(void) | |
| { | |
| int32_t cmd; | |
| int32_t i; | |
| if (cl_shownet.value == 1) | |
| Con_Printf("%i ", net_message.cursize); | |
| else | |
| if (cl_shownet.value == 2) | |
| Con_Printf("------------------\n"); | |
| cl.onground = 0; | |
| MSG_BeginReading(); | |
| while (1) | |
| { | |
| if (msg_badread) | |
| Host_Error("CL_ParseServerMessage: Bad server message"); | |
| cmd = MSG_ReadByte(); | |
| if (cmd == (-1)) | |
| { | |
| SHOWNET("END OF MESSAGE"); | |
| return; | |
| } | |
| if (cmd & 128) | |
| { | |
| SHOWNET("fast update"); | |
| CL_ParseUpdate(cmd & 127); | |
| continue; | |
| } | |
| SHOWNET(svc_strings[cmd]); | |
| switch (cmd) | |
| { | |
| default: | |
| Host_Error("CL_ParseServerMessage: Illegible server message\n"); | |
| break; | |
| case svc_nop: | |
| break; | |
| case svc_time: | |
| cl.mtime[1] = cl.mtime[0]; | |
| cl.mtime[0] = MSG_ReadFloat(); | |
| break; | |
| case svc_clientdata: | |
| i = MSG_ReadShort(); | |
| CL_ParseClientdata(i); | |
| break; | |
| case svc_version: | |
| i = MSG_ReadLong(); | |
| if (i != PROTOCOL_VERSION) | |
| Host_Error("CL_ParseServerMessage: Server is protocol %i instead of %i\n", i, PROTOCOL_VERSION); | |
| break; | |
| case svc_disconnect: | |
| Host_EndGame("Server disconnected\n"); | |
| case svc_print: | |
| Con_Printf("%s", MSG_ReadString()); | |
| break; | |
| case svc_centerprint: | |
| SCR_CenterPrint(MSG_ReadString()); | |
| break; | |
| case svc_stufftext: | |
| Cbuf_AddText(MSG_ReadString()); | |
| break; | |
| case svc_damage: | |
| V_ParseDamage(); | |
| break; | |
| case svc_serverinfo: | |
| CL_ParseServerInfo(); | |
| vid.recalc_refdef = 1; | |
| break; | |
| case svc_setangle: | |
| for (i = 0; i < 3; i++) | |
| cl.viewangles[i] = MSG_ReadAngle(); | |
| break; | |
| case svc_setview: | |
| cl.viewentity = MSG_ReadShort(); | |
| break; | |
| case svc_lightstyle: | |
| i = MSG_ReadByte(); | |
| if (i >= MAX_LIGHTSTYLES) | |
| Sys_Error("svc_lightstyle > MAX_LIGHTSTYLES"); | |
| strcpy(cl_lightstyle[i].map, MSG_ReadString()); | |
| cl_lightstyle[i].length = strlen(cl_lightstyle[i].map); | |
| break; | |
| case svc_sound: | |
| CL_ParseStartSoundPacket(); | |
| break; | |
| case svc_stopsound: | |
| i = MSG_ReadShort(); | |
| S_StopSound(i >> 3, i & 7); | |
| break; | |
| case svc_updatename: | |
| Sbar_Changed(); | |
| i = MSG_ReadByte(); | |
| if (i >= cl.maxclients) | |
| Host_Error("CL_ParseServerMessage: svc_updatename > MAX_SCOREBOARD"); | |
| strcpy(cl.scores[i].name, MSG_ReadString()); | |
| break; | |
| case svc_updatefrags: | |
| Sbar_Changed(); | |
| i = MSG_ReadByte(); | |
| if (i >= cl.maxclients) | |
| Host_Error("CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD"); | |
| cl.scores[i].frags = MSG_ReadShort(); | |
| break; | |
| case svc_updatecolors: | |
| Sbar_Changed(); | |
| i = MSG_ReadByte(); | |
| if (i >= cl.maxclients) | |
| Host_Error("CL_ParseServerMessage: svc_updatecolors > MAX_SCOREBOARD"); | |
| cl.scores[i].colors = MSG_ReadByte(); | |
| CL_NewTranslation(i); | |
| break; | |
| case svc_particle: | |
| R_ParseParticleEffect(); | |
| break; | |
| case svc_spawnbaseline: | |
| i = MSG_ReadShort(); | |
| CL_ParseBaseline(CL_EntityNum(i)); | |
| break; | |
| case svc_spawnstatic: | |
| CL_ParseStatic(); | |
| break; | |
| case svc_temp_entity: | |
| CL_ParseTEnt(); | |
| break; | |
| case svc_setpause: | |
| { | |
| cl.paused = MSG_ReadByte(); | |
| if (cl.paused) | |
| { | |
| CDAudio_Pause(); | |
| } | |
| else | |
| { | |
| CDAudio_Resume(); | |
| } | |
| } | |
| break; | |
| case svc_signonnum: | |
| i = MSG_ReadByte(); | |
| if (i <= cls.signon) | |
| Host_Error("Received signon %i when at %i", i, cls.signon); | |
| cls.signon = i; | |
| CL_SignonReply(); | |
| break; | |
| case svc_killedmonster: | |
| cl.stats[STAT_MONSTERS]++; | |
| break; | |
| case svc_foundsecret: | |
| cl.stats[STAT_SECRETS]++; | |
| break; | |
| case svc_updatestat: | |
| i = MSG_ReadByte(); | |
| if ((i < 0) || (i >= MAX_CL_STATS)) | |
| Sys_Error("svc_updatestat: %i is invalid", i); | |
| cl.stats[i] = MSG_ReadLong(); | |
| ; | |
| break; | |
| case svc_spawnstaticsound: | |
| CL_ParseStaticSound(); | |
| break; | |
| case svc_cdtrack: | |
| cl.cdtrack = MSG_ReadByte(); | |
| cl.looptrack = MSG_ReadByte(); | |
| if ((cls.demoplayback || cls.demorecording) && (cls.forcetrack != (-1))) | |
| CDAudio_Play((uint8_t) cls.forcetrack, 1); | |
| else | |
| CDAudio_Play((uint8_t) cl.cdtrack, 1); | |
| break; | |
| case svc_intermission: | |
| cl.intermission = 1; | |
| cl.completed_time = cl.time; | |
| vid.recalc_refdef = 1; | |
| break; | |
| case svc_finale: | |
| cl.intermission = 2; | |
| cl.completed_time = cl.time; | |
| vid.recalc_refdef = 1; | |
| SCR_CenterPrint(MSG_ReadString()); | |
| break; | |
| case svc_cutscene: | |
| cl.intermission = 3; | |
| cl.completed_time = cl.time; | |
| vid.recalc_refdef = 1; | |
| SCR_CenterPrint(MSG_ReadString()); | |
| break; | |
| case svc_sellscreen: | |
| Cmd_ExecuteString("help", src_command); | |
| break; | |
| } | |
| } | |
| } | |
| void CL_InitTEnts(void) | |
| { | |
| cl_sfx_wizhit = S_PrecacheSound("wizard/hit.wav"); | |
| cl_sfx_knighthit = S_PrecacheSound("hknight/hit.wav"); | |
| cl_sfx_tink1 = S_PrecacheSound("weapons/tink1.wav"); | |
| cl_sfx_ric1 = S_PrecacheSound("weapons/ric1.wav"); | |
| cl_sfx_ric2 = S_PrecacheSound("weapons/ric2.wav"); | |
| cl_sfx_ric3 = S_PrecacheSound("weapons/ric3.wav"); | |
| cl_sfx_r_exp3 = S_PrecacheSound("weapons/r_exp3.wav"); | |
| } | |
| static void CL_ParseBeam(model_t *m) | |
| { | |
| int32_t ent; | |
| vec3_t start; | |
| vec3_t end; | |
| beam_t *b; | |
| int32_t i; | |
| ent = MSG_ReadShort(); | |
| start[0] = MSG_ReadCoord(); | |
| start[1] = MSG_ReadCoord(); | |
| start[2] = MSG_ReadCoord(); | |
| end[0] = MSG_ReadCoord(); | |
| end[1] = MSG_ReadCoord(); | |
| end[2] = MSG_ReadCoord(); | |
| for (i = 0, b = cl_beams; i < MAX_BEAMS; i++, b++) | |
| if (b->entity == ent) | |
| { | |
| b->entity = ent; | |
| b->model = m; | |
| b->endtime = cl.time + 0.2; | |
| VectorCopy(start, b->start); | |
| VectorCopy(end, b->end); | |
| return; | |
| } | |
| for (i = 0, b = cl_beams; i < MAX_BEAMS; i++, b++) | |
| { | |
| if ((!b->model) || (b->endtime < cl.time)) | |
| { | |
| b->entity = ent; | |
| b->model = m; | |
| b->endtime = cl.time + 0.2; | |
| VectorCopy(start, b->start); | |
| VectorCopy(end, b->end); | |
| return; | |
| } | |
| } | |
| Con_Printf("beam list overflow!\n"); | |
| } | |
| void CL_ParseTEnt(void) | |
| { | |
| int32_t type; | |
| vec3_t pos; | |
| dlight_t *dl; | |
| int32_t rnd; | |
| int32_t colorStart; | |
| int32_t colorLength; | |
| type = MSG_ReadByte(); | |
| switch (type) | |
| { | |
| case TE_WIZSPIKE: | |
| pos[0] = MSG_ReadCoord(); | |
| pos[1] = MSG_ReadCoord(); | |
| pos[2] = MSG_ReadCoord(); | |
| R_RunParticleEffect(pos, vec3_origin, 20, 30); | |
| S_StartSound(-1, 0, cl_sfx_wizhit, pos, 1, 1); | |
| break; | |
| case TE_KNIGHTSPIKE: | |
| pos[0] = MSG_ReadCoord(); | |
| pos[1] = MSG_ReadCoord(); | |
| pos[2] = MSG_ReadCoord(); | |
| R_RunParticleEffect(pos, vec3_origin, 226, 20); | |
| S_StartSound(-1, 0, cl_sfx_knighthit, pos, 1, 1); | |
| break; | |
| case TE_SPIKE: | |
| pos[0] = MSG_ReadCoord(); | |
| pos[1] = MSG_ReadCoord(); | |
| pos[2] = MSG_ReadCoord(); | |
| R_RunParticleEffect(pos, vec3_origin, 0, 10); | |
| if (rand() % 5) | |
| S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1); | |
| else | |
| { | |
| rnd = rand() & 3; | |
| if (rnd == 1) | |
| S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1); | |
| else | |
| if (rnd == 2) | |
| S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1); | |
| else | |
| S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1); | |
| } | |
| break; | |
| case TE_SUPERSPIKE: | |
| pos[0] = MSG_ReadCoord(); | |
| pos[1] = MSG_ReadCoord(); | |
| pos[2] = MSG_ReadCoord(); | |
| R_RunParticleEffect(pos, vec3_origin, 0, 20); | |
| if (rand() % 5) | |
| S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1); | |
| else | |
| { | |
| rnd = rand() & 3; | |
| if (rnd == 1) | |
| S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1); | |
| else | |
| if (rnd == 2) | |
| S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1); | |
| else | |
| S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1); | |
| } | |
| break; | |
| case TE_GUNSHOT: | |
| pos[0] = MSG_ReadCoord(); | |
| pos[1] = MSG_ReadCoord(); | |
| pos[2] = MSG_ReadCoord(); | |
| R_RunParticleEffect(pos, vec3_origin, 0, 20); | |
| break; | |
| case TE_EXPLOSION: | |
| pos[0] = MSG_ReadCoord(); | |
| pos[1] = MSG_ReadCoord(); | |
| pos[2] = MSG_ReadCoord(); | |
| R_ParticleExplosion(pos); | |
| dl = CL_AllocDlight(0); | |
| VectorCopy(pos, dl->origin); | |
| dl->radius = 350; | |
| dl->die = cl.time + 0.5; | |
| dl->decay = 300; | |
| S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1); | |
| break; | |
| case TE_TAREXPLOSION: | |
| pos[0] = MSG_ReadCoord(); | |
| pos[1] = MSG_ReadCoord(); | |
| pos[2] = MSG_ReadCoord(); | |
| R_BlobExplosion(pos); | |
| S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1); | |
| break; | |
| case TE_LIGHTNING1: | |
| CL_ParseBeam(Mod_ForName("progs/bolt.mdl", 1)); | |
| break; | |
| case TE_LIGHTNING2: | |
| CL_ParseBeam(Mod_ForName("progs/bolt2.mdl", 1)); | |
| break; | |
| case TE_LIGHTNING3: | |
| CL_ParseBeam(Mod_ForName("progs/bolt3.mdl", 1)); | |
| break; | |
| case TE_BEAM: | |
| CL_ParseBeam(Mod_ForName("progs/beam.mdl", 1)); | |
| break; | |
| case TE_LAVASPLASH: | |
| pos[0] = MSG_ReadCoord(); | |
| pos[1] = MSG_ReadCoord(); | |
| pos[2] = MSG_ReadCoord(); | |
| R_LavaSplash(pos); | |
| break; | |
| case TE_TELEPORT: | |
| pos[0] = MSG_ReadCoord(); | |
| pos[1] = MSG_ReadCoord(); | |
| pos[2] = MSG_ReadCoord(); | |
| R_TeleportSplash(pos); | |
| break; | |
| case TE_EXPLOSION2: | |
| pos[0] = MSG_ReadCoord(); | |
| pos[1] = MSG_ReadCoord(); | |
| pos[2] = MSG_ReadCoord(); | |
| colorStart = MSG_ReadByte(); | |
| colorLength = MSG_ReadByte(); | |
| R_ParticleExplosion2(pos, colorStart, colorLength); | |
| dl = CL_AllocDlight(0); | |
| VectorCopy(pos, dl->origin); | |
| dl->radius = 350; | |
| dl->die = cl.time + 0.5; | |
| dl->decay = 300; | |
| S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1); | |
| break; | |
| default: | |
| Sys_Error("CL_ParseTEnt: bad type"); | |
| } | |
| } | |
| static entity_t *CL_NewTempEntity(void) | |
| { | |
| entity_t *ent; | |
| if (cl_numvisedicts == MAX_VISEDICTS) | |
| return 0; | |
| if (num_temp_entities == MAX_TEMP_ENTITIES) | |
| return 0; | |
| ent = &cl_temp_entities[num_temp_entities]; | |
| memset(ent, 0, sizeof(*ent)); | |
| num_temp_entities++; | |
| cl_visedicts[cl_numvisedicts] = ent; | |
| cl_numvisedicts++; | |
| ent->colormap = vid.colormap; | |
| return ent; | |
| } | |
| void CL_UpdateTEnts(void) | |
| { | |
| int32_t i; | |
| beam_t *b; | |
| vec3_t dist; | |
| vec3_t org; | |
| float d; | |
| entity_t *ent; | |
| float yaw; | |
| float pitch; | |
| float forward; | |
| num_temp_entities = 0; | |
| for (i = 0, b = cl_beams; i < MAX_BEAMS; i++, b++) | |
| { | |
| if ((!b->model) || (b->endtime < cl.time)) | |
| continue; | |
| if (b->entity == cl.viewentity) | |
| { | |
| VectorCopy(cl_entities[cl.viewentity].origin, b->start); | |
| } | |
| VectorSubtract(b->end, b->start, dist); | |
| if ((dist[1] == 0) && (dist[0] == 0)) | |
| { | |
| yaw = 0; | |
| if (dist[2] > 0) | |
| pitch = 90; | |
| else | |
| pitch = 270; | |
| } | |
| else | |
| { | |
| yaw = (int32_t) ((atan2(dist[1], dist[0]) * 180) / M_PI); | |
| if (yaw < 0) | |
| yaw += 360; | |
| forward = sqrt((dist[0] * dist[0]) + (dist[1] * dist[1])); | |
| pitch = (int32_t) ((atan2(dist[2], forward) * 180) / M_PI); | |
| if (pitch < 0) | |
| pitch += 360; | |
| } | |
| VectorCopy(b->start, org); | |
| d = VectorNormalize(dist); | |
| while (d > 0) | |
| { | |
| ent = CL_NewTempEntity(); | |
| if (!ent) | |
| return; | |
| VectorCopy(org, ent->origin); | |
| ent->model = b->model; | |
| ent->angles[0] = pitch; | |
| ent->angles[1] = yaw; | |
| ent->angles[2] = rand() % 360; | |
| for (i = 0; i < 3; i++) | |
| org[i] += dist[i] * 30; | |
| d -= 30; | |
| } | |
| } | |
| } | |
| static void Cmd_Wait_f(void) | |
| { | |
| cmd_wait = 1; | |
| } | |
| void Cbuf_Init(void) | |
| { | |
| SZ_Alloc(&cmd_text, 8192); | |
| } | |
| void Cbuf_AddText(char *text) | |
| { | |
| int32_t l; | |
| l = strlen(text); | |
| if ((cmd_text.cursize + l) >= cmd_text.maxsize) | |
| { | |
| Con_Printf("Cbuf_AddText: overflow\n"); | |
| return; | |
| } | |
| SZ_Write(&cmd_text, text, strlen(text)); | |
| } | |
| void Cbuf_InsertText(char *text) | |
| { | |
| char *temp; | |
| int32_t templen; | |
| templen = cmd_text.cursize; | |
| if (templen) | |
| { | |
| temp = Z_Malloc(templen); | |
| memcpy(temp, cmd_text.data, templen); | |
| SZ_Clear(&cmd_text); | |
| } | |
| else | |
| temp = 0; | |
| Cbuf_AddText(text); | |
| if (templen) | |
| { | |
| SZ_Write(&cmd_text, temp, templen); | |
| Z_Free(temp); | |
| } | |
| } | |
| void Cbuf_Execute(void) | |
| { | |
| int32_t i; | |
| char *text; | |
| char line[1024]; | |
| int32_t quotes; | |
| while (cmd_text.cursize) | |
| { | |
| text = (char *) cmd_text.data; | |
| quotes = 0; | |
| for (i = 0; i < cmd_text.cursize; i++) | |
| { | |
| if (text[i] == '"') | |
| quotes++; | |
| if ((!(quotes & 1)) && (text[i] == ';')) | |
| break; | |
| if (text[i] == '\n') | |
| break; | |
| } | |
| memcpy(line, text, i); | |
| line[i] = 0; | |
| if (i == cmd_text.cursize) | |
| cmd_text.cursize = 0; | |
| else | |
| { | |
| i++; | |
| cmd_text.cursize -= i; | |
| memcpy(text, text + i, cmd_text.cursize); | |
| } | |
| Cmd_ExecuteString(line, src_command); | |
| if (cmd_wait) | |
| { | |
| cmd_wait = 0; | |
| break; | |
| } | |
| } | |
| } | |
| static void Cmd_StuffCmds_f(void) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| int32_t s; | |
| char *text; | |
| char *build; | |
| char c; | |
| if (Cmd_Argc() != 1) | |
| { | |
| Con_Printf("stuffcmds : execute command line parameters\n"); | |
| return; | |
| } | |
| s = 0; | |
| for (i = 1; i < com_argc; i++) | |
| { | |
| if (!com_argv[i]) | |
| continue; | |
| s += strlen(com_argv[i]) + 1; | |
| } | |
| if (!s) | |
| return; | |
| text = Z_Malloc(s + 1); | |
| text[0] = 0; | |
| for (i = 1; i < com_argc; i++) | |
| { | |
| if (!com_argv[i]) | |
| continue; | |
| strcat(text, com_argv[i]); | |
| if (i != (com_argc - 1)) | |
| strcat(text, " "); | |
| } | |
| build = Z_Malloc(s + 1); | |
| build[0] = 0; | |
| for (i = 0; i < (s - 1); i++) | |
| { | |
| if (text[i] == '+') | |
| { | |
| i++; | |
| for (j = i; ((text[j] != '+') && (text[j] != '-')) && (text[j] != 0); j++) | |
| ; | |
| c = text[j]; | |
| text[j] = 0; | |
| strcat(build, text + i); | |
| strcat(build, "\n"); | |
| text[j] = c; | |
| i = j - 1; | |
| } | |
| } | |
| if (build[0]) | |
| Cbuf_InsertText(build); | |
| Z_Free(text); | |
| Z_Free(build); | |
| } | |
| static void Cmd_Exec_f(void) | |
| { | |
| char *f; | |
| int32_t mark; | |
| if (Cmd_Argc() != 2) | |
| { | |
| Con_Printf("exec <filename> : execute a script file\n"); | |
| return; | |
| } | |
| mark = Hunk_LowMark(); | |
| f = (char *) COM_LoadHunkFile(Cmd_Argv(1)); | |
| if (!f) | |
| { | |
| Con_Printf("couldn't exec %s\n", Cmd_Argv(1)); | |
| return; | |
| } | |
| Con_Printf("execing %s\n", Cmd_Argv(1)); | |
| Cbuf_InsertText(f); | |
| Hunk_FreeToLowMark(mark); | |
| } | |
| static void Cmd_Echo_f(void) | |
| { | |
| int32_t i; | |
| for (i = 1; i < Cmd_Argc(); i++) | |
| Con_Printf("%s ", Cmd_Argv(i)); | |
| Con_Printf("\n"); | |
| } | |
| static char *CopyString(char *in) | |
| { | |
| char *out; | |
| out = Z_Malloc(strlen(in) + 1); | |
| strcpy(out, in); | |
| return out; | |
| } | |
| static void Cmd_Alias_f(void) | |
| { | |
| cmdalias_t *a; | |
| char cmd[1024]; | |
| int32_t i; | |
| int32_t c; | |
| char *s; | |
| if (Cmd_Argc() == 1) | |
| { | |
| Con_Printf("Current alias commands:\n"); | |
| for (a = cmd_alias; a; a = a->next) | |
| Con_Printf("%s : %s\n", a->name, a->value); | |
| return; | |
| } | |
| s = Cmd_Argv(1); | |
| if (strlen(s) >= MAX_ALIAS_NAME) | |
| { | |
| Con_Printf("Alias name is too int32_t\n"); | |
| return; | |
| } | |
| for (a = cmd_alias; a; a = a->next) | |
| { | |
| if (!strcmp(s, a->name)) | |
| { | |
| Z_Free(a->value); | |
| break; | |
| } | |
| } | |
| if (!a) | |
| { | |
| a = Z_Malloc(sizeof(cmdalias_t)); | |
| a->next = cmd_alias; | |
| cmd_alias = a; | |
| } | |
| strcpy(a->name, s); | |
| cmd[0] = 0; | |
| c = Cmd_Argc(); | |
| for (i = 2; i < c; i++) | |
| { | |
| strcat(cmd, Cmd_Argv(i)); | |
| if (i != c) | |
| strcat(cmd, " "); | |
| } | |
| strcat(cmd, "\n"); | |
| a->value = CopyString(cmd); | |
| } | |
| void Cmd_Init(void) | |
| { | |
| Cmd_AddCommand("stuffcmds", Cmd_StuffCmds_f); | |
| Cmd_AddCommand("exec", Cmd_Exec_f); | |
| Cmd_AddCommand("echo", Cmd_Echo_f); | |
| Cmd_AddCommand("alias", Cmd_Alias_f); | |
| Cmd_AddCommand("cmd", Cmd_ForwardToServer); | |
| Cmd_AddCommand("wait", Cmd_Wait_f); | |
| } | |
| int32_t Cmd_Argc(void) | |
| { | |
| return cmd_argc; | |
| } | |
| char *Cmd_Argv(int32_t arg) | |
| { | |
| if (((uint32_t) arg) >= cmd_argc) | |
| return cmd_null_string; | |
| return cmd_argv[arg]; | |
| } | |
| char *Cmd_Args(void) | |
| { | |
| return cmd_args; | |
| } | |
| void Cmd_TokenizeString(char *text) | |
| { | |
| int32_t i; | |
| for (i = 0; i < cmd_argc; i++) | |
| Z_Free(cmd_argv[i]); | |
| cmd_argc = 0; | |
| cmd_args = 0; | |
| while (1) | |
| { | |
| while (((*text) && ((*text) <= ' ')) && ((*text) != '\n')) | |
| { | |
| text++; | |
| } | |
| if ((*text) == '\n') | |
| { | |
| text++; | |
| break; | |
| } | |
| if (!(*text)) | |
| return; | |
| if (cmd_argc == 1) | |
| cmd_args = text; | |
| text = COM_Parse(text); | |
| if (!text) | |
| return; | |
| if (cmd_argc < MAX_ARGS) | |
| { | |
| cmd_argv[cmd_argc] = Z_Malloc(strlen(com_token) + 1); | |
| strcpy(cmd_argv[cmd_argc], com_token); | |
| cmd_argc++; | |
| } | |
| } | |
| } | |
| void Cmd_AddCommand(char *cmd_name, xcommand_t function) | |
| { | |
| cmd_function_t *cmd; | |
| if (host_initialized) | |
| Sys_Error("Cmd_AddCommand after host_initialized"); | |
| if (Cvar_VariableString(cmd_name)[0]) | |
| { | |
| Con_Printf("Cmd_AddCommand: %s already defined as a var\n", cmd_name); | |
| return; | |
| } | |
| for (cmd = cmd_functions; cmd; cmd = cmd->next) | |
| { | |
| if (!strcmp(cmd_name, cmd->name)) | |
| { | |
| Con_Printf("Cmd_AddCommand: %s already defined\n", cmd_name); | |
| return; | |
| } | |
| } | |
| cmd = Hunk_Alloc(sizeof(cmd_function_t)); | |
| cmd->name = cmd_name; | |
| cmd->function = function; | |
| cmd->next = cmd_functions; | |
| cmd_functions = cmd; | |
| } | |
| bool Cmd_Exists(char *cmd_name) | |
| { | |
| cmd_function_t *cmd; | |
| for (cmd = cmd_functions; cmd; cmd = cmd->next) | |
| { | |
| if (!strcmp(cmd_name, cmd->name)) | |
| return 1; | |
| } | |
| return 0; | |
| } | |
| char *Cmd_CompleteCommand(char *partial) | |
| { | |
| cmd_function_t *cmd; | |
| int32_t len; | |
| len = strlen(partial); | |
| if (!len) | |
| return 0; | |
| for (cmd = cmd_functions; cmd; cmd = cmd->next) | |
| if (!strncmp(partial, cmd->name, len)) | |
| return cmd->name; | |
| return 0; | |
| } | |
| void Cmd_ExecuteString(char *text, cmd_source_t src) | |
| { | |
| cmd_function_t *cmd; | |
| cmdalias_t *a; | |
| cmd_source = src; | |
| Cmd_TokenizeString(text); | |
| if (!Cmd_Argc()) | |
| return; | |
| for (cmd = cmd_functions; cmd; cmd = cmd->next) | |
| { | |
| if (!strcasecmp(cmd_argv[0], cmd->name)) | |
| { | |
| cmd->function(); | |
| return; | |
| } | |
| } | |
| for (a = cmd_alias; a; a = a->next) | |
| { | |
| if (!strcasecmp(cmd_argv[0], a->name)) | |
| { | |
| Cbuf_InsertText(a->value); | |
| return; | |
| } | |
| } | |
| if (!Cvar_Command()) | |
| Con_Printf("Unknown command \"%s\"\n", Cmd_Argv(0)); | |
| } | |
| void Cmd_ForwardToServer(void) | |
| { | |
| if (cls.state != ca_connected) | |
| { | |
| Con_Printf("Can't \"%s\", not connected\n", Cmd_Argv(0)); | |
| return; | |
| } | |
| if (cls.demoplayback) | |
| return; | |
| MSG_WriteByte(&cls.message, clc_stringcmd); | |
| if (strcasecmp(Cmd_Argv(0), "cmd") != 0) | |
| { | |
| SZ_Print(&cls.message, Cmd_Argv(0)); | |
| SZ_Print(&cls.message, " "); | |
| } | |
| if (Cmd_Argc() > 1) | |
| SZ_Print(&cls.message, Cmd_Args()); | |
| else | |
| SZ_Print(&cls.message, "\n"); | |
| } | |
| int32_t Cmd_CheckParm(char *parm) | |
| { | |
| int32_t i; | |
| if (!parm) | |
| Sys_Error("Cmd_CheckParm: NULL"); | |
| for (i = 1; i < Cmd_Argc(); i++) | |
| if (!strcasecmp(parm, Cmd_Argv(i))) | |
| return i; | |
| return 0; | |
| } | |
| void ClearLink(link_t *l) | |
| { | |
| l->prev = (l->next = l); | |
| } | |
| void RemoveLink(link_t *l) | |
| { | |
| l->next->prev = l->prev; | |
| l->prev->next = l->next; | |
| } | |
| void InsertLinkBefore(link_t *l, link_t *before) | |
| { | |
| l->next = before; | |
| l->prev = before->prev; | |
| l->prev->next = l; | |
| l->next->prev = l; | |
| } | |
| void InsertLinkAfter(link_t *l, link_t *after) | |
| { | |
| l->next = after->next; | |
| l->prev = after; | |
| l->prev->next = l; | |
| l->next->prev = l; | |
| } | |
| void MSG_WriteChar(sizebuf_t *sb, int32_t c) | |
| { | |
| uint8_t *buf; | |
| buf = SZ_GetSpace(sb, 1); | |
| buf[0] = c; | |
| } | |
| void MSG_WriteByte(sizebuf_t *sb, int32_t c) | |
| { | |
| uint8_t *buf; | |
| buf = SZ_GetSpace(sb, 1); | |
| buf[0] = c; | |
| } | |
| void MSG_WriteShort(sizebuf_t *sb, int32_t c) | |
| { | |
| uint8_t *buf; | |
| buf = SZ_GetSpace(sb, 2); | |
| buf[0] = c & 0xff; | |
| buf[1] = c >> 8; | |
| } | |
| void MSG_WriteLong(sizebuf_t *sb, int32_t c) | |
| { | |
| uint8_t *buf; | |
| buf = SZ_GetSpace(sb, 4); | |
| buf[0] = c & 0xff; | |
| buf[1] = (c >> 8) & 0xff; | |
| buf[2] = (c >> 16) & 0xff; | |
| buf[3] = c >> 24; | |
| } | |
| void MSG_WriteFloat(sizebuf_t *sb, float f) | |
| { | |
| union | |
| { | |
| float f; | |
| int32_t l; | |
| } dat; | |
| dat.f = f; | |
| dat.l = dat.l; | |
| SZ_Write(sb, &dat.l, 4); | |
| } | |
| void MSG_WriteString(sizebuf_t *sb, char *s) | |
| { | |
| if (!s) | |
| SZ_Write(sb, "", 1); | |
| else | |
| SZ_Write(sb, s, strlen(s) + 1); | |
| } | |
| void MSG_WriteCoord(sizebuf_t *sb, float f) | |
| { | |
| MSG_WriteShort(sb, (int32_t) (f * 8)); | |
| } | |
| void MSG_WriteAngle(sizebuf_t *sb, float f) | |
| { | |
| MSG_WriteByte(sb, ((((int32_t) f) * 256) / 360) & 255); | |
| } | |
| void MSG_BeginReading(void) | |
| { | |
| msg_readcount = 0; | |
| msg_badread = 0; | |
| } | |
| int32_t MSG_ReadChar(void) | |
| { | |
| int32_t c; | |
| if ((msg_readcount + 1) > net_message.cursize) | |
| { | |
| msg_badread = 1; | |
| return -1; | |
| } | |
| c = (signed char) net_message.data[msg_readcount]; | |
| msg_readcount++; | |
| return c; | |
| } | |
| int32_t MSG_ReadByte(void) | |
| { | |
| int32_t c; | |
| if ((msg_readcount + 1) > net_message.cursize) | |
| { | |
| msg_badread = 1; | |
| return -1; | |
| } | |
| c = (unsigned char) net_message.data[msg_readcount]; | |
| msg_readcount++; | |
| return c; | |
| } | |
| int32_t MSG_ReadShort(void) | |
| { | |
| int32_t c; | |
| if ((msg_readcount + 2) > net_message.cursize) | |
| { | |
| msg_badread = 1; | |
| return -1; | |
| } | |
| c = (int16_t) (net_message.data[msg_readcount] + (net_message.data[msg_readcount + 1] << 8)); | |
| msg_readcount += 2; | |
| return c; | |
| } | |
| int32_t MSG_ReadLong(void) | |
| { | |
| int32_t c; | |
| if ((msg_readcount + 4) > net_message.cursize) | |
| { | |
| msg_badread = 1; | |
| return -1; | |
| } | |
| c = ((net_message.data[msg_readcount] + (net_message.data[msg_readcount + 1] << 8)) + (net_message.data[msg_readcount + 2] << 16)) + (net_message.data[msg_readcount + 3] << 24); | |
| msg_readcount += 4; | |
| return c; | |
| } | |
| float MSG_ReadFloat(void) | |
| { | |
| union | |
| { | |
| uint8_t b[4]; | |
| float f; | |
| int32_t l; | |
| } dat; | |
| dat.b[0] = net_message.data[msg_readcount]; | |
| dat.b[1] = net_message.data[msg_readcount + 1]; | |
| dat.b[2] = net_message.data[msg_readcount + 2]; | |
| dat.b[3] = net_message.data[msg_readcount + 3]; | |
| msg_readcount += 4; | |
| dat.l = dat.l; | |
| return dat.f; | |
| } | |
| char *MSG_ReadString(void) | |
| { | |
| static char string[2048]; | |
| int32_t l; | |
| int32_t c; | |
| l = 0; | |
| do | |
| { | |
| c = MSG_ReadChar(); | |
| if ((c == (-1)) || (c == 0)) | |
| break; | |
| string[l] = c; | |
| l++; | |
| } | |
| while (l < ((sizeof(string)) - 1)); | |
| string[l] = 0; | |
| return string; | |
| } | |
| float MSG_ReadCoord(void) | |
| { | |
| return MSG_ReadShort() * (1.0 / 8); | |
| } | |
| float MSG_ReadAngle(void) | |
| { | |
| return MSG_ReadChar() * (360.0 / 256); | |
| } | |
| void SZ_Alloc(sizebuf_t *buf, int32_t startsize) | |
| { | |
| if (startsize < 256) | |
| startsize = 256; | |
| buf->data = Hunk_AllocName(startsize, "sizebuf"); | |
| buf->maxsize = startsize; | |
| buf->cursize = 0; | |
| } | |
| void SZ_Free(sizebuf_t *buf) | |
| { | |
| buf->cursize = 0; | |
| } | |
| void SZ_Clear(sizebuf_t *buf) | |
| { | |
| buf->cursize = 0; | |
| } | |
| void *SZ_GetSpace(sizebuf_t *buf, int32_t length) | |
| { | |
| void *data; | |
| if ((buf->cursize + length) > buf->maxsize) | |
| { | |
| if (!buf->allowoverflow) | |
| Sys_Error("SZ_GetSpace: overflow without allowoverflow set"); | |
| if (length > buf->maxsize) | |
| Sys_Error("SZ_GetSpace: %i is > full buffer size", length); | |
| buf->overflowed = 1; | |
| Con_Printf("SZ_GetSpace: overflow"); | |
| SZ_Clear(buf); | |
| } | |
| data = buf->data + buf->cursize; | |
| buf->cursize += length; | |
| return data; | |
| } | |
| void SZ_Write(sizebuf_t *buf, void *data, int32_t length) | |
| { | |
| memcpy(SZ_GetSpace(buf, length), data, length); | |
| } | |
| void SZ_Print(sizebuf_t *buf, char *data) | |
| { | |
| int32_t len; | |
| len = strlen(data) + 1; | |
| if (buf->data[buf->cursize - 1]) | |
| memcpy((uint8_t *) SZ_GetSpace(buf, len), data, len); | |
| else | |
| memcpy(((uint8_t *) SZ_GetSpace(buf, len - 1)) - 1, data, len); | |
| } | |
| char *COM_SkipPath(char *pathname) | |
| { | |
| char *p = strrchr(pathname, '/'); | |
| return (p) ? (p + 1) : (pathname); | |
| } | |
| void COM_StripExtension(char *in, char *out) | |
| { | |
| size_t n = strcspn(in, "."); | |
| memcpy(out, in, n); | |
| out[n] = '\0'; | |
| } | |
| static char *COM_FileExtension(char *in) | |
| { | |
| static char exten[8]; | |
| const char *dot = strchr(in, '.'); | |
| if ((!dot) || (!(*(dot + 1)))) | |
| return ""; | |
| dot++; | |
| size_t i = 0; | |
| while ((i < ((sizeof(exten)) - 1)) && (dot[i] != '\0')) | |
| { | |
| exten[i] = dot[i]; | |
| i++; | |
| } | |
| exten[i] = '\0'; | |
| return exten; | |
| } | |
| void COM_FileBase(char *in, char *out) | |
| { | |
| const char *dot = strrchr(in, '.'); | |
| if (!dot) | |
| { | |
| strcpy(out, "?model?"); | |
| return; | |
| } | |
| const char *slash = dot; | |
| while ((slash > in) && ((*slash) != '/')) | |
| slash--; | |
| if ((*slash) == '/') | |
| slash++; | |
| else | |
| slash = in; | |
| if (dot <= slash) | |
| { | |
| strcpy(out, "?model?"); | |
| return; | |
| } | |
| size_t len = (size_t) (dot - slash); | |
| memcpy(out, slash, len); | |
| out[len] = '\0'; | |
| } | |
| void COM_DefaultExtension(char *path, char *extension) | |
| { | |
| char *base = strrchr(path, '/'); | |
| base = (base) ? (base + 1) : (path); | |
| if (!strchr(base, '.')) | |
| strcat(path, extension); | |
| } | |
| char *COM_Parse(char *data) | |
| { | |
| int32_t c; | |
| int32_t len = 0; | |
| com_token[0] = 0; | |
| if (!data) | |
| return 0; | |
| skipwhite: | |
| while ((c = *data) <= ' ') | |
| { | |
| if (c == 0) | |
| return 0; | |
| data++; | |
| } | |
| if ((c == '/') && (data[1] == '/')) | |
| { | |
| data += strcspn(data, "\n"); | |
| if ((*data) == '\n') | |
| data++; | |
| goto skipwhite; | |
| } | |
| if (c == '\"') | |
| { | |
| data++; | |
| for (;;) | |
| { | |
| c = *(data++); | |
| if ((c == '\"') || (!c)) | |
| { | |
| com_token[len] = 0; | |
| return data; | |
| } | |
| com_token[len++] = (char) c; | |
| } | |
| } | |
| if ((((((c == '{') || (c == '}')) || (c == ')')) || (c == '(')) || (c == '\'')) || (c == ':')) | |
| { | |
| com_token[len++] = (char) c; | |
| com_token[len] = 0; | |
| return data + 1; | |
| } | |
| do | |
| { | |
| com_token[len++] = (char) c; | |
| data++; | |
| c = *data; | |
| if ((((((c == '{') || (c == '}')) || (c == ')')) || (c == '(')) || (c == '\'')) || (c == ':')) | |
| break; | |
| } | |
| while (c > 32); | |
| com_token[len] = 0; | |
| return data; | |
| } | |
| int32_t COM_CheckParm(char *parm) | |
| { | |
| for (int32_t i = 1; i < com_argc; i++) | |
| { | |
| if (!com_argv[i]) | |
| continue; | |
| if (strcmp(parm, com_argv[i]) == 0) | |
| return i; | |
| } | |
| return 0; | |
| } | |
| void COM_InitArgv(int32_t argc, char **argv) | |
| { | |
| bool safe; | |
| int32_t i; | |
| int32_t j; | |
| int32_t n; | |
| n = 0; | |
| for (j = 0; (j < MAX_NUM_ARGVS) && (j < argc); j++) | |
| { | |
| i = 0; | |
| while ((n < (CMDLINE_LENGTH - 1)) && argv[j][i]) | |
| { | |
| com_cmdline[n++] = argv[j][i++]; | |
| } | |
| if (n < (CMDLINE_LENGTH - 1)) | |
| com_cmdline[n++] = ' '; | |
| else | |
| break; | |
| } | |
| com_cmdline[n] = 0; | |
| safe = 0; | |
| for (com_argc = 0; (com_argc < MAX_NUM_ARGVS) && (com_argc < argc); com_argc++) | |
| { | |
| largv[com_argc] = argv[com_argc]; | |
| if (!strcmp("-safe", argv[com_argc])) | |
| safe = 1; | |
| } | |
| if (safe) | |
| { | |
| for (i = 0; i < NUM_SAFE_ARGVS; i++) | |
| { | |
| largv[com_argc] = safeargvs[i]; | |
| com_argc++; | |
| } | |
| } | |
| largv[com_argc] = argvdummy; | |
| com_argv = largv; | |
| if (COM_CheckParm("-rogue")) | |
| { | |
| rogue = 1; | |
| standard_quake = 0; | |
| } | |
| if (COM_CheckParm("-hipnotic")) | |
| { | |
| hipnotic = 1; | |
| standard_quake = 0; | |
| } | |
| } | |
| void COM_Init(char *basedir) | |
| { | |
| Cvar_RegisterVariable(®istered); | |
| Cvar_RegisterVariable(&cmdline); | |
| Cmd_AddCommand("path", COM_Path_f); | |
| COM_InitFilesystem(); | |
| } | |
| char *va(char *format, ...) | |
| { | |
| va_list argptr; | |
| static char string[1024]; | |
| va_start(argptr, format); | |
| vsprintf(string, format, argptr); | |
| va_end(argptr); | |
| return string; | |
| } | |
| static void COM_Path_f(void) | |
| { | |
| searchpath_t *s; | |
| Con_Printf("Current search path:\n"); | |
| for (s = com_searchpaths; s; s = s->next) | |
| { | |
| if (s->pack) | |
| { | |
| Con_Printf("%s (%i files)\n", s->pack->filename, s->pack->numfiles); | |
| } | |
| else | |
| Con_Printf("%s\n", s->filename); | |
| } | |
| } | |
| void COM_WriteFile(char *filename, void *data, int32_t len) | |
| { | |
| int32_t handle; | |
| char name[MAX_OSPATH]; | |
| sprintf(name, "%s/%s", com_gamedir, filename); | |
| handle = Sys_FileOpenWrite(name); | |
| if (handle == (-1)) | |
| { | |
| Sys_Printf("COM_WriteFile: failed on %s\n", name); | |
| return; | |
| } | |
| Sys_Printf("COM_WriteFile: %s\n", name); | |
| Sys_FileWrite(handle, data, len); | |
| Sys_FileClose(handle); | |
| } | |
| static void COM_CreatePath(char *path) | |
| { | |
| char *ofs; | |
| for (ofs = path + 1; *ofs; ofs++) | |
| { | |
| if ((*ofs) == '/') | |
| { | |
| *ofs = 0; | |
| Sys_mkdir(path); | |
| *ofs = '/'; | |
| } | |
| } | |
| } | |
| static void COM_CopyFile(char *netpath, char *cachepath) | |
| { | |
| int32_t in; | |
| int32_t out; | |
| int32_t remaining; | |
| int32_t count; | |
| char buf[4096]; | |
| remaining = Sys_FileOpenRead(netpath, &in); | |
| COM_CreatePath(cachepath); | |
| out = Sys_FileOpenWrite(cachepath); | |
| while (remaining) | |
| { | |
| if (remaining < (sizeof(buf))) | |
| count = remaining; | |
| else | |
| count = sizeof(buf); | |
| Sys_FileRead(in, buf, count); | |
| Sys_FileWrite(out, buf, count); | |
| remaining -= count; | |
| } | |
| Sys_FileClose(in); | |
| Sys_FileClose(out); | |
| } | |
| static int32_t COM_FindFile(char *filename, int32_t *handle, FILE **file) | |
| { | |
| searchpath_t *search; | |
| char netpath[MAX_OSPATH]; | |
| char cachepath[MAX_OSPATH]; | |
| pack_t *pak; | |
| int32_t i; | |
| int32_t findtime; | |
| int32_t cachetime; | |
| if (file && handle) | |
| Sys_Error("COM_FindFile: both handle and file set"); | |
| if ((!file) && (!handle)) | |
| Sys_Error("COM_FindFile: neither handle or file set"); | |
| search = com_searchpaths; | |
| if (proghack) | |
| { | |
| if (!strcmp(filename, "progs.dat")) | |
| search = search->next; | |
| } | |
| for (; search; search = search->next) | |
| { | |
| if (search->pack) | |
| { | |
| pak = search->pack; | |
| for (i = 0; i < pak->numfiles; i++) | |
| if (!strcmp(pak->files[i].name, filename)) | |
| { | |
| Sys_Printf("PackFile: %s : %s\n", pak->filename, filename); | |
| if (handle) | |
| { | |
| *handle = pak->handle; | |
| Sys_FileSeek(pak->handle, pak->files[i].filepos); | |
| } | |
| else | |
| { | |
| *file = fopen(pak->filename, "rb"); | |
| if (*file) | |
| fseek(*file, pak->files[i].filepos, 0); | |
| } | |
| com_filesize = pak->files[i].filelen; | |
| return com_filesize; | |
| } | |
| } | |
| else | |
| { | |
| if (!static_registered) | |
| { | |
| if (strchr(filename, '/') || strchr(filename, '\\')) | |
| continue; | |
| } | |
| sprintf(netpath, "%s/%s", search->filename, filename); | |
| findtime = Sys_FileTime(netpath); | |
| if (findtime == (-1)) | |
| continue; | |
| if (!com_cachedir[0]) | |
| strcpy(cachepath, netpath); | |
| else | |
| { | |
| sprintf(cachepath, "%s%s", com_cachedir, netpath); | |
| cachetime = Sys_FileTime(cachepath); | |
| if (cachetime < findtime) | |
| COM_CopyFile(netpath, cachepath); | |
| strcpy(netpath, cachepath); | |
| } | |
| Sys_Printf("FindFile: %s\n", netpath); | |
| com_filesize = Sys_FileOpenRead(netpath, &i); | |
| if (handle) | |
| *handle = i; | |
| else | |
| { | |
| Sys_FileClose(i); | |
| *file = fopen(netpath, "rb"); | |
| } | |
| return com_filesize; | |
| } | |
| } | |
| Sys_Printf("FindFile: can't find %s\n", filename); | |
| if (handle) | |
| *handle = -1; | |
| else | |
| *file = 0; | |
| com_filesize = -1; | |
| return -1; | |
| } | |
| int32_t COM_OpenFile(char *filename, int32_t *handle) | |
| { | |
| return COM_FindFile(filename, handle, 0); | |
| } | |
| int32_t COM_FOpenFile(char *filename, FILE **file) | |
| { | |
| return COM_FindFile(filename, 0, file); | |
| } | |
| void COM_CloseFile(int32_t h) | |
| { | |
| searchpath_t *s; | |
| for (s = com_searchpaths; s; s = s->next) | |
| if (s->pack && (s->pack->handle == h)) | |
| return; | |
| Sys_FileClose(h); | |
| } | |
| static uint8_t *COM_LoadFile(char *path, int32_t usehunk) | |
| { | |
| int32_t h; | |
| uint8_t *buf; | |
| char base[32]; | |
| int32_t len; | |
| buf = 0; | |
| len = COM_OpenFile(path, &h); | |
| if (h == (-1)) | |
| return 0; | |
| COM_FileBase(path, base); | |
| if (usehunk == 1) | |
| buf = Hunk_AllocName(len + 1, base); | |
| else | |
| if (usehunk == 2) | |
| buf = Hunk_TempAlloc(len + 1); | |
| else | |
| if (usehunk == 0) | |
| buf = Z_Malloc(len + 1); | |
| else | |
| if (usehunk == 3) | |
| buf = Cache_Alloc(loadcache, len + 1, base); | |
| else | |
| if (usehunk == 4) | |
| { | |
| if ((len + 1) > loadsize) | |
| buf = Hunk_TempAlloc(len + 1); | |
| else | |
| buf = loadbuf; | |
| } | |
| else | |
| Sys_Error("COM_LoadFile: bad usehunk"); | |
| if (!buf) | |
| Sys_Error("COM_LoadFile: not enough space for %s", path); | |
| ((uint8_t *) buf)[len] = 0; | |
| Draw_BeginDisc(); | |
| Sys_FileRead(h, buf, len); | |
| COM_CloseFile(h); | |
| Draw_EndDisc(); | |
| return buf; | |
| } | |
| uint8_t *COM_LoadHunkFile(char *path) | |
| { | |
| return COM_LoadFile(path, 1); | |
| } | |
| uint8_t *COM_LoadTempFile(char *path) | |
| { | |
| return COM_LoadFile(path, 2); | |
| } | |
| void COM_LoadCacheFile(char *path, struct cache_user_s *cu) | |
| { | |
| loadcache = cu; | |
| COM_LoadFile(path, 3); | |
| } | |
| uint8_t *COM_LoadStackFile(char *path, void *buffer, int32_t bufsize) | |
| { | |
| uint8_t *buf; | |
| loadbuf = (uint8_t *) buffer; | |
| loadsize = bufsize; | |
| buf = COM_LoadFile(path, 4); | |
| return buf; | |
| } | |
| static pack_t *COM_LoadPackFile(char *packfile) | |
| { | |
| dpackheader_t header; | |
| int32_t i; | |
| packfile_t *newfiles; | |
| int32_t numpackfiles; | |
| pack_t *pack; | |
| int32_t packhandle; | |
| dpackfile_t info[MAX_FILES_IN_PACK]; | |
| uint16_t crc; | |
| if (Sys_FileOpenRead(packfile, &packhandle) == (-1)) | |
| { | |
| return 0; | |
| } | |
| Sys_FileRead(packhandle, (void *) (&header), sizeof(header)); | |
| if ((((header.id[0] != 'P') || (header.id[1] != 'A')) || (header.id[2] != 'C')) || (header.id[3] != 'K')) | |
| Sys_Error("%s is not a packfile", packfile); | |
| header.dirofs = header.dirofs; | |
| header.dirlen = header.dirlen; | |
| numpackfiles = header.dirlen / (sizeof(dpackfile_t)); | |
| if (numpackfiles > MAX_FILES_IN_PACK) | |
| Sys_Error("%s has %i files", packfile, numpackfiles); | |
| if (numpackfiles != PAK0_COUNT) | |
| com_modified = 1; | |
| newfiles = Hunk_AllocName(numpackfiles * (sizeof(packfile_t)), "packfile"); | |
| Sys_FileSeek(packhandle, header.dirofs); | |
| Sys_FileRead(packhandle, (void *) info, header.dirlen); | |
| CRC_Init(&crc); | |
| for (i = 0; i < header.dirlen; i++) | |
| CRC_ProcessByte(&crc, ((uint8_t *) info)[i]); | |
| if (crc != PAK0_CRC) | |
| com_modified = 1; | |
| for (i = 0; i < numpackfiles; i++) | |
| { | |
| strcpy(newfiles[i].name, info[i].name); | |
| newfiles[i].filepos = info[i].filepos; | |
| newfiles[i].filelen = info[i].filelen; | |
| } | |
| pack = Hunk_Alloc(sizeof(pack_t)); | |
| strcpy(pack->filename, packfile); | |
| pack->handle = packhandle; | |
| pack->numfiles = numpackfiles; | |
| pack->files = newfiles; | |
| Con_Printf("Added packfile %s (%i files)\n", packfile, numpackfiles); | |
| return pack; | |
| } | |
| static void COM_AddGameDirectory(char *dir) | |
| { | |
| int32_t i; | |
| searchpath_t *search; | |
| pack_t *pak; | |
| char pakfile[MAX_OSPATH]; | |
| strcpy(com_gamedir, dir); | |
| search = Hunk_Alloc(sizeof(searchpath_t)); | |
| strcpy(search->filename, dir); | |
| search->next = com_searchpaths; | |
| com_searchpaths = search; | |
| for (i = 0;; i++) | |
| { | |
| sprintf(pakfile, "%s/pak%i.pak", dir, i); | |
| pak = COM_LoadPackFile(pakfile); | |
| if (!pak) | |
| break; | |
| search = Hunk_Alloc(sizeof(searchpath_t)); | |
| search->pack = pak; | |
| search->next = com_searchpaths; | |
| com_searchpaths = search; | |
| } | |
| } | |
| static void COM_InitFilesystem(void) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| char basedir[MAX_OSPATH]; | |
| searchpath_t *search; | |
| i = COM_CheckParm("-basedir"); | |
| if (i && (i < (com_argc - 1))) | |
| strcpy(basedir, com_argv[i + 1]); | |
| else | |
| strcpy(basedir, host_parms.basedir); | |
| j = strlen(basedir); | |
| if (j > 0) | |
| { | |
| if ((basedir[j - 1] == '\\') || (basedir[j - 1] == '/')) | |
| basedir[j - 1] = 0; | |
| } | |
| i = COM_CheckParm("-cachedir"); | |
| if (i && (i < (com_argc - 1))) | |
| { | |
| if (com_argv[i + 1][0] == '-') | |
| com_cachedir[0] = 0; | |
| else | |
| strcpy(com_cachedir, com_argv[i + 1]); | |
| } | |
| else | |
| if (host_parms.cachedir) | |
| strcpy(com_cachedir, host_parms.cachedir); | |
| else | |
| com_cachedir[0] = 0; | |
| COM_AddGameDirectory(va("%s/id1", basedir)); | |
| if (COM_CheckParm("-rogue")) | |
| COM_AddGameDirectory(va("%s/rogue", basedir)); | |
| if (COM_CheckParm("-hipnotic")) | |
| COM_AddGameDirectory(va("%s/hipnotic", basedir)); | |
| i = COM_CheckParm("-game"); | |
| if (i && (i < (com_argc - 1))) | |
| { | |
| com_modified = 1; | |
| COM_AddGameDirectory(va("%s/%s", basedir, com_argv[i + 1])); | |
| } | |
| i = COM_CheckParm("-path"); | |
| if (i) | |
| { | |
| com_modified = 1; | |
| com_searchpaths = 0; | |
| while ((++i) < com_argc) | |
| { | |
| if (((!com_argv[i]) || (com_argv[i][0] == '+')) || (com_argv[i][0] == '-')) | |
| break; | |
| search = Hunk_Alloc(sizeof(searchpath_t)); | |
| if (!strcmp(COM_FileExtension(com_argv[i]), "pak")) | |
| { | |
| search->pack = COM_LoadPackFile(com_argv[i]); | |
| if (!search->pack) | |
| Sys_Error("Couldn't load packfile: %s", com_argv[i]); | |
| } | |
| else | |
| strcpy(search->filename, com_argv[i]); | |
| search->next = com_searchpaths; | |
| com_searchpaths = search; | |
| } | |
| } | |
| if (COM_CheckParm("-proghack")) | |
| proghack = 1; | |
| } | |
| void Con_ToggleConsole_f(void) | |
| { | |
| if (key_dest == key_console) | |
| { | |
| if (cls.state == ca_connected) | |
| { | |
| key_dest = key_game; | |
| key_lines[edit_line][1] = 0; | |
| key_linepos = 1; | |
| } | |
| else | |
| { | |
| M_Menu_Main_f(); | |
| } | |
| } | |
| else | |
| key_dest = key_console; | |
| SCR_EndLoadingPlaque(); | |
| memset(con_times, 0, sizeof(con_times)); | |
| } | |
| void Con_Clear_f(void) | |
| { | |
| if (con_text) | |
| memset(con_text, ' ', CON_TEXTSIZE); | |
| } | |
| void Con_ClearNotify(void) | |
| { | |
| int32_t i; | |
| for (i = 0; i < NUM_CON_TIMES; i++) | |
| con_times[i] = 0; | |
| } | |
| static void Con_MessageMode_f(void) | |
| { | |
| key_dest = key_message; | |
| team_message = 0; | |
| } | |
| static void Con_MessageMode2_f(void) | |
| { | |
| key_dest = key_message; | |
| team_message = 1; | |
| } | |
| void Con_CheckResize(void) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| int32_t width; | |
| int32_t oldwidth; | |
| int32_t oldtotallines; | |
| int32_t numlines; | |
| int32_t numchars; | |
| char tbuf[CON_TEXTSIZE]; | |
| width = (vid.width >> 3) - 2; | |
| if (width == con_linewidth) | |
| return; | |
| if (width < 1) | |
| { | |
| width = 38; | |
| con_linewidth = width; | |
| con_totallines = CON_TEXTSIZE / con_linewidth; | |
| memset(con_text, ' ', CON_TEXTSIZE); | |
| } | |
| else | |
| { | |
| oldwidth = con_linewidth; | |
| con_linewidth = width; | |
| oldtotallines = con_totallines; | |
| con_totallines = CON_TEXTSIZE / con_linewidth; | |
| numlines = oldtotallines; | |
| if (con_totallines < numlines) | |
| numlines = con_totallines; | |
| numchars = oldwidth; | |
| if (con_linewidth < numchars) | |
| numchars = con_linewidth; | |
| memcpy(tbuf, con_text, CON_TEXTSIZE); | |
| memset(con_text, ' ', CON_TEXTSIZE); | |
| for (i = 0; i < numlines; i++) | |
| { | |
| for (j = 0; j < numchars; j++) | |
| { | |
| con_text[(((con_totallines - 1) - i) * con_linewidth) + j] = tbuf[((((con_current - i) + oldtotallines) % oldtotallines) * oldwidth) + j]; | |
| } | |
| } | |
| Con_ClearNotify(); | |
| } | |
| con_backscroll = 0; | |
| con_current = con_totallines - 1; | |
| } | |
| void Con_Init(void) | |
| { | |
| char temp[MAXGAMEDIRLEN + 1]; | |
| char *t2 = "/qconsole.log"; | |
| con_debuglog = COM_CheckParm("-condebug"); | |
| if (con_debuglog) | |
| { | |
| if (strlen(com_gamedir) < (MAXGAMEDIRLEN - strlen(t2))) | |
| { | |
| sprintf(temp, "%s%s", com_gamedir, t2); | |
| unlink(temp); | |
| } | |
| } | |
| con_text = Hunk_AllocName(CON_TEXTSIZE, "context"); | |
| memset(con_text, ' ', CON_TEXTSIZE); | |
| con_linewidth = -1; | |
| Con_CheckResize(); | |
| Con_Printf("Console initialized.\n"); | |
| Cvar_RegisterVariable(&con_notifytime); | |
| Cmd_AddCommand("toggleconsole", Con_ToggleConsole_f); | |
| Cmd_AddCommand("messagemode", Con_MessageMode_f); | |
| Cmd_AddCommand("messagemode2", Con_MessageMode2_f); | |
| Cmd_AddCommand("clear", Con_Clear_f); | |
| con_initialized = 1; | |
| } | |
| static void Con_Linefeed(void) | |
| { | |
| con_x = 0; | |
| con_current++; | |
| memset(&con_text[(con_current % con_totallines) * con_linewidth], ' ', con_linewidth); | |
| } | |
| void Con_Print(char *txt) | |
| { | |
| int32_t y; | |
| int32_t c; | |
| int32_t l; | |
| static int32_t cr; | |
| int32_t mask; | |
| con_backscroll = 0; | |
| if (txt[0] == 1) | |
| { | |
| mask = 128; | |
| S_LocalSound("misc/talk.wav"); | |
| txt++; | |
| } | |
| else | |
| if (txt[0] == 2) | |
| { | |
| mask = 128; | |
| txt++; | |
| } | |
| else | |
| mask = 0; | |
| while (c = *txt) | |
| { | |
| for (l = 0; l < con_linewidth; l++) | |
| if (txt[l] <= ' ') | |
| break; | |
| if ((l != con_linewidth) && ((con_x + l) > con_linewidth)) | |
| con_x = 0; | |
| txt++; | |
| if (cr) | |
| { | |
| con_current--; | |
| cr = 0; | |
| } | |
| if (!con_x) | |
| { | |
| Con_Linefeed(); | |
| if (con_current >= 0) | |
| con_times[con_current % NUM_CON_TIMES] = realtime; | |
| } | |
| switch (c) | |
| { | |
| case '\n': | |
| con_x = 0; | |
| break; | |
| case '\r': | |
| con_x = 0; | |
| cr = 1; | |
| break; | |
| default: | |
| y = con_current % con_totallines; | |
| con_text[(y * con_linewidth) + con_x] = c | mask; | |
| con_x++; | |
| if (con_x >= con_linewidth) | |
| con_x = 0; | |
| break; | |
| } | |
| } | |
| } | |
| static void Con_DebugLog(char *file, char *fmt, ...) | |
| { | |
| va_list argptr; | |
| static char data[1024]; | |
| int32_t fd; | |
| va_start(argptr, fmt); | |
| vsprintf(data, fmt, argptr); | |
| va_end(argptr); | |
| fd = open(file, (O_WRONLY | O_CREAT) | O_APPEND, 0666); | |
| write(fd, data, strlen(data)); | |
| close(fd); | |
| } | |
| void Con_Printf(char *fmt, ...) | |
| { | |
| va_list argptr; | |
| char msg[MAXPRINTMSG]; | |
| static bool inupdate; | |
| va_start(argptr, fmt); | |
| vsprintf(msg, fmt, argptr); | |
| va_end(argptr); | |
| Sys_Printf("%s", msg); | |
| if (con_debuglog) | |
| Con_DebugLog(va("%s/qconsole.log", com_gamedir), "%s", msg); | |
| if (!con_initialized) | |
| return; | |
| if (cls.state == ca_dedicated) | |
| return; | |
| Con_Print(msg); | |
| if ((cls.signon != SIGNONS) && (!scr_disabled_for_loading)) | |
| { | |
| if (!inupdate) | |
| { | |
| inupdate = 1; | |
| SCR_UpdateScreen(); | |
| inupdate = 0; | |
| } | |
| } | |
| } | |
| void Con_DPrintf(char *fmt, ...) | |
| { | |
| va_list argptr; | |
| char msg[MAXPRINTMSG]; | |
| if (!developer.value) | |
| return; | |
| va_start(argptr, fmt); | |
| vsprintf(msg, fmt, argptr); | |
| va_end(argptr); | |
| Con_Printf("%s", msg); | |
| } | |
| void Con_SafePrintf(char *fmt, ...) | |
| { | |
| va_list argptr; | |
| char msg[1024]; | |
| int32_t temp; | |
| va_start(argptr, fmt); | |
| vsprintf(msg, fmt, argptr); | |
| va_end(argptr); | |
| temp = scr_disabled_for_loading; | |
| scr_disabled_for_loading = 1; | |
| Con_Printf("%s", msg); | |
| scr_disabled_for_loading = temp; | |
| } | |
| static void Con_DrawInput(void) | |
| { | |
| int32_t y; | |
| int32_t i; | |
| char *text; | |
| if ((key_dest != key_console) && (!con_forcedup)) | |
| return; | |
| text = key_lines[edit_line]; | |
| text[key_linepos] = 10 + (((int32_t) (realtime * con_cursorspeed)) & 1); | |
| for (i = key_linepos + 1; i < con_linewidth; i++) | |
| text[i] = ' '; | |
| if (key_linepos >= con_linewidth) | |
| text += (1 + key_linepos) - con_linewidth; | |
| y = con_vislines - 16; | |
| for (i = 0; i < con_linewidth; i++) | |
| Draw_Character((i + 1) << 3, con_vislines - 16, text[i]); | |
| key_lines[edit_line][key_linepos] = 0; | |
| } | |
| void Con_DrawNotify(void) | |
| { | |
| int32_t x; | |
| int32_t v; | |
| char *text; | |
| int32_t i; | |
| float time; | |
| extern char chat_buffer[]; | |
| v = 0; | |
| for (i = (con_current - NUM_CON_TIMES) + 1; i <= con_current; i++) | |
| { | |
| if (i < 0) | |
| continue; | |
| time = con_times[i % NUM_CON_TIMES]; | |
| if (time == 0) | |
| continue; | |
| time = realtime - time; | |
| if (time > con_notifytime.value) | |
| continue; | |
| text = con_text + ((i % con_totallines) * con_linewidth); | |
| clearnotify = 0; | |
| scr_copytop = 1; | |
| for (x = 0; x < con_linewidth; x++) | |
| Draw_Character((x + 1) << 3, v, text[x]); | |
| v += 8; | |
| } | |
| if (key_dest == key_message) | |
| { | |
| clearnotify = 0; | |
| scr_copytop = 1; | |
| x = 0; | |
| Draw_String(8, v, "say:"); | |
| while (chat_buffer[x]) | |
| { | |
| Draw_Character((x + 5) << 3, v, chat_buffer[x]); | |
| x++; | |
| } | |
| Draw_Character((x + 5) << 3, v, 10 + (((int32_t) (realtime * con_cursorspeed)) & 1)); | |
| v += 8; | |
| } | |
| if (v > con_notifylines) | |
| con_notifylines = v; | |
| } | |
| void Con_DrawConsole(int32_t lines, bool drawinput) | |
| { | |
| int32_t i; | |
| int32_t x; | |
| int32_t y; | |
| int32_t rows; | |
| char *text; | |
| int32_t j; | |
| if (lines <= 0) | |
| return; | |
| Draw_ConsoleBackground(lines); | |
| con_vislines = lines; | |
| rows = (lines - 16) >> 3; | |
| y = (lines - 16) - (rows << 3); | |
| for (i = (con_current - rows) + 1; i <= con_current; i++, y += 8) | |
| { | |
| j = i - con_backscroll; | |
| if (j < 0) | |
| j = 0; | |
| text = con_text + ((j % con_totallines) * con_linewidth); | |
| for (x = 0; x < con_linewidth; x++) | |
| Draw_Character((x + 1) << 3, y, text[x]); | |
| } | |
| if (drawinput) | |
| Con_DrawInput(); | |
| } | |
| void Con_NotifyBox(char *text) | |
| { | |
| double t1; | |
| double t2; | |
| Con_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n"); | |
| Con_Printf(text); | |
| Con_Printf("Press a key.\n"); | |
| Con_Printf("\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n"); | |
| key_count = -2; | |
| key_dest = key_console; | |
| do | |
| { | |
| t1 = Sys_FloatTime(); | |
| SCR_UpdateScreen(); | |
| Sys_SendKeyEvents(); | |
| t2 = Sys_FloatTime(); | |
| realtime += t2 - t1; | |
| } | |
| while (key_count < 0); | |
| Con_Printf("\n"); | |
| key_dest = key_game; | |
| realtime = 0; | |
| } | |
| void CRC_Init(uint16_t *crcvalue) | |
| { | |
| *crcvalue = CRC_INIT_VALUE; | |
| } | |
| void CRC_ProcessByte(uint16_t *crcvalue, uint8_t data) | |
| { | |
| *crcvalue = ((*crcvalue) << 8) ^ crctable[((*crcvalue) >> 8) ^ data]; | |
| } | |
| uint16_t CRC_Value(uint16_t crcvalue) | |
| { | |
| return crcvalue ^ CRC_XOR_VALUE; | |
| } | |
| cvar_t *Cvar_FindVar(char *var_name) | |
| { | |
| cvar_t *var; | |
| for (var = cvar_vars; var; var = var->next) | |
| if (!strcmp(var_name, var->name)) | |
| return var; | |
| return 0; | |
| } | |
| float Cvar_VariableValue(char *var_name) | |
| { | |
| cvar_t *var; | |
| var = Cvar_FindVar(var_name); | |
| if (!var) | |
| return 0; | |
| return atof(var->string); | |
| } | |
| char *Cvar_VariableString(char *var_name) | |
| { | |
| cvar_t *var; | |
| var = Cvar_FindVar(var_name); | |
| if (!var) | |
| return cvar_null_string; | |
| return var->string; | |
| } | |
| char *Cvar_CompleteVariable(char *partial) | |
| { | |
| cvar_t *cvar; | |
| int32_t len; | |
| len = strlen(partial); | |
| if (!len) | |
| return 0; | |
| for (cvar = cvar_vars; cvar; cvar = cvar->next) | |
| if (!strncmp(partial, cvar->name, len)) | |
| return cvar->name; | |
| return 0; | |
| } | |
| void Cvar_Set(char *var_name, char *value) | |
| { | |
| cvar_t *var; | |
| bool changed; | |
| var = Cvar_FindVar(var_name); | |
| if (!var) | |
| { | |
| Con_Printf("Cvar_Set: variable %s not found\n", var_name); | |
| return; | |
| } | |
| changed = strcmp(var->string, value); | |
| Z_Free(var->string); | |
| var->string = Z_Malloc(strlen(value) + 1); | |
| strcpy(var->string, value); | |
| var->value = (float) strtod(var->string, 0); | |
| if (var->server && changed) | |
| { | |
| if (sv.active) | |
| SV_BroadcastPrintf("\"%s\" changed to \"%s\"\n", var->name, var->string); | |
| } | |
| } | |
| void Cvar_SetValue(char *var_name, float value) | |
| { | |
| char val[32]; | |
| sprintf(val, "%f", value); | |
| Cvar_Set(var_name, val); | |
| } | |
| void Cvar_RegisterVariable(cvar_t *variable) | |
| { | |
| char *oldstr; | |
| if (Cvar_FindVar(variable->name)) | |
| { | |
| Con_Printf("Can't register variable %s, allready defined\n", variable->name); | |
| return; | |
| } | |
| if (Cmd_Exists(variable->name)) | |
| { | |
| Con_Printf("Cvar_RegisterVariable: %s is a command\n", variable->name); | |
| return; | |
| } | |
| oldstr = variable->string; | |
| variable->string = Z_Malloc(strlen(variable->string) + 1); | |
| strcpy(variable->string, oldstr); | |
| variable->value = (float) strtod(variable->string, 0); | |
| variable->next = cvar_vars; | |
| cvar_vars = variable; | |
| } | |
| bool Cvar_Command(void) | |
| { | |
| cvar_t *v; | |
| v = Cvar_FindVar(Cmd_Argv(0)); | |
| if (!v) | |
| return 0; | |
| if (Cmd_Argc() == 1) | |
| { | |
| Con_Printf("\"%s\" is \"%s\"\n", v->name, v->string); | |
| return 1; | |
| } | |
| Cvar_Set(v->name, Cmd_Argv(1)); | |
| return 1; | |
| } | |
| void Cvar_WriteVariables(FILE *f) | |
| { | |
| cvar_t *var; | |
| for (var = cvar_vars; var; var = var->next) | |
| if (var->archive) | |
| fprintf(f, "%s \"%s\"\n", var->name, var->string); | |
| } | |
| void D_DrawPoly(void) | |
| { | |
| } | |
| int32_t D_MipLevelForScale(float scale) | |
| { | |
| int32_t lmiplevel; | |
| if (scale >= d_scalemip[0]) | |
| lmiplevel = 0; | |
| else | |
| if (scale >= d_scalemip[1]) | |
| lmiplevel = 1; | |
| else | |
| if (scale >= d_scalemip[2]) | |
| lmiplevel = 2; | |
| else | |
| lmiplevel = 3; | |
| if (lmiplevel < d_minmip) | |
| lmiplevel = d_minmip; | |
| return lmiplevel; | |
| } | |
| static void D_DrawSolidSurface(surf_t *surf, int32_t color) | |
| { | |
| espan_t *span; | |
| uint8_t *pdest; | |
| int32_t u; | |
| int32_t u2; | |
| int32_t pix; | |
| pix = (((color << 24) | (color << 16)) | (color << 8)) | color; | |
| for (span = surf->spans; span; span = span->pnext) | |
| { | |
| pdest = ((uint8_t *) d_viewbuffer) + (screenwidth * span->v); | |
| u = span->u; | |
| u2 = (span->u + span->count) - 1; | |
| ((uint8_t *) pdest)[u] = pix; | |
| if ((u2 - u) < 8) | |
| { | |
| for (u++; u <= u2; u++) | |
| ((uint8_t *) pdest)[u] = pix; | |
| } | |
| else | |
| { | |
| for (u++; u & 3; u++) | |
| ((uint8_t *) pdest)[u] = pix; | |
| u2 -= 4; | |
| for (; u <= u2; u += 4) | |
| *((int32_t *) (((uint8_t *) pdest) + u)) = pix; | |
| u2 += 4; | |
| for (; u <= u2; u++) | |
| ((uint8_t *) pdest)[u] = pix; | |
| } | |
| } | |
| } | |
| static void D_CalcGradients(msurface_t *pface) | |
| { | |
| mplane_t *pplane; | |
| float mipscale; | |
| vec3_t p_temp1; | |
| vec3_t p_saxis; | |
| vec3_t p_taxis; | |
| float t; | |
| pplane = pface->plane; | |
| mipscale = 1.0 / ((float) (1 << miplevel)); | |
| TransformVector(pface->texinfo->vecs[0], p_saxis); | |
| TransformVector(pface->texinfo->vecs[1], p_taxis); | |
| t = xscaleinv * mipscale; | |
| d_sdivzstepu = p_saxis[0] * t; | |
| d_tdivzstepu = p_taxis[0] * t; | |
| t = yscaleinv * mipscale; | |
| d_sdivzstepv = (-p_saxis[1]) * t; | |
| d_tdivzstepv = (-p_taxis[1]) * t; | |
| d_sdivzorigin = ((p_saxis[2] * mipscale) - (xcenter * d_sdivzstepu)) - (ycenter * d_sdivzstepv); | |
| d_tdivzorigin = ((p_taxis[2] * mipscale) - (xcenter * d_tdivzstepu)) - (ycenter * d_tdivzstepv); | |
| VectorScale(transformed_modelorg, mipscale, p_temp1); | |
| t = 0x10000 * mipscale; | |
| sadjust = (((fixed16_t) ((DotProduct(p_temp1, p_saxis) * 0x10000) + 0.5)) - ((pface->texturemins[0] << 16) >> miplevel)) + (pface->texinfo->vecs[0][3] * t); | |
| tadjust = (((fixed16_t) ((DotProduct(p_temp1, p_taxis) * 0x10000) + 0.5)) - ((pface->texturemins[1] << 16) >> miplevel)) + (pface->texinfo->vecs[1][3] * t); | |
| bbextents = ((pface->extents[0] << 16) >> miplevel) - 1; | |
| bbextentt = ((pface->extents[1] << 16) >> miplevel) - 1; | |
| } | |
| void D_DrawSurfaces(void) | |
| { | |
| surf_t *s; | |
| msurface_t *pface; | |
| surfcache_t *pcurrentcache; | |
| vec3_t world_transformed_modelorg; | |
| vec3_t local_modelorg; | |
| currententity = &cl_entities[0]; | |
| TransformVector(modelorg, transformed_modelorg); | |
| VectorCopy(transformed_modelorg, world_transformed_modelorg); | |
| if (r_drawflat.value) | |
| { | |
| for (s = &surfaces[1]; s < surface_p; s++) | |
| { | |
| if (!s->spans) | |
| continue; | |
| d_zistepu = s->d_zistepu; | |
| d_zistepv = s->d_zistepv; | |
| d_ziorigin = s->d_ziorigin; | |
| D_DrawSolidSurface(s, ((int32_t) s->data) & 0xFF); | |
| D_DrawZSpans(s->spans); | |
| } | |
| } | |
| else | |
| { | |
| for (s = &surfaces[1]; s < surface_p; s++) | |
| { | |
| if (!s->spans) | |
| continue; | |
| r_drawnpolycount++; | |
| d_zistepu = s->d_zistepu; | |
| d_zistepv = s->d_zistepv; | |
| d_ziorigin = s->d_ziorigin; | |
| if (s->flags & SURF_DRAWSKY) | |
| { | |
| if (!r_skymade) | |
| { | |
| R_MakeSky(); | |
| } | |
| D_DrawSkyScans8(s->spans); | |
| D_DrawZSpans(s->spans); | |
| } | |
| else | |
| if (s->flags & SURF_DRAWBACKGROUND) | |
| { | |
| d_zistepu = 0; | |
| d_zistepv = 0; | |
| d_ziorigin = -0.9; | |
| D_DrawSolidSurface(s, ((int32_t) r_clearcolor.value) & 0xFF); | |
| D_DrawZSpans(s->spans); | |
| } | |
| else | |
| if (s->flags & SURF_DRAWTURB) | |
| { | |
| pface = s->data; | |
| miplevel = 0; | |
| cacheblock = (pixel_t *) (((uint8_t *) pface->texinfo->texture) + pface->texinfo->texture->offsets[0]); | |
| cachewidth = 64; | |
| if (s->insubmodel) | |
| { | |
| currententity = s->entity; | |
| VectorSubtract(r_origin, currententity->origin, local_modelorg); | |
| TransformVector(local_modelorg, transformed_modelorg); | |
| R_RotateBmodel(); | |
| } | |
| D_CalcGradients(pface); | |
| Turbulent8(s->spans); | |
| D_DrawZSpans(s->spans); | |
| if (s->insubmodel) | |
| { | |
| currententity = &cl_entities[0]; | |
| VectorCopy(world_transformed_modelorg, transformed_modelorg); | |
| VectorCopy(base_vpn, vpn); | |
| VectorCopy(base_vup, vup); | |
| VectorCopy(base_vright, vright); | |
| VectorCopy(base_modelorg, modelorg); | |
| R_TransformFrustum(); | |
| } | |
| } | |
| else | |
| { | |
| if (s->insubmodel) | |
| { | |
| currententity = s->entity; | |
| VectorSubtract(r_origin, currententity->origin, local_modelorg); | |
| TransformVector(local_modelorg, transformed_modelorg); | |
| R_RotateBmodel(); | |
| } | |
| pface = s->data; | |
| miplevel = D_MipLevelForScale((s->nearzi * scale_for_mip) * pface->texinfo->mipadjust); | |
| pcurrentcache = D_CacheSurface(pface, miplevel); | |
| cacheblock = (pixel_t *) pcurrentcache->data; | |
| cachewidth = pcurrentcache->width; | |
| D_CalcGradients(pface); | |
| (*d_drawspans)(s->spans); | |
| D_DrawZSpans(s->spans); | |
| if (s->insubmodel) | |
| { | |
| currententity = &cl_entities[0]; | |
| VectorCopy(world_transformed_modelorg, transformed_modelorg); | |
| VectorCopy(base_vpn, vpn); | |
| VectorCopy(base_vup, vup); | |
| VectorCopy(base_vright, vright); | |
| VectorCopy(base_modelorg, modelorg); | |
| R_TransformFrustum(); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| void D_FillRect(const vrect_t *vrect, const int32_t color) | |
| { | |
| int32_t rx = vrect->x; | |
| int32_t ry = vrect->y; | |
| int32_t rwidth = vrect->width; | |
| int32_t rheight = vrect->height; | |
| if (rx < 0) | |
| { | |
| rwidth += rx; | |
| rx = 0; | |
| } | |
| if (ry < 0) | |
| { | |
| rheight += ry; | |
| ry = 0; | |
| } | |
| const int32_t vwidth = (vid.width > ((uint32_t) INT32_MAX)) ? (INT32_MAX) : ((int32_t) vid.width); | |
| const int32_t vheight = (vid.height > ((uint32_t) INT32_MAX)) ? (INT32_MAX) : ((int32_t) vid.height); | |
| if (rx > vwidth) | |
| rwidth = 0; | |
| else | |
| if (rwidth > (vwidth - rx)) | |
| rwidth = vwidth - rx; | |
| if (ry > vheight) | |
| rheight = 0; | |
| else | |
| if (rheight > (vheight - ry)) | |
| rheight = vheight - ry; | |
| if ((rwidth < 1) || (rheight < 1)) | |
| return; | |
| uint8_t *dest = (vid.buffer + (((size_t) ry) * vid.rowbytes)) + rx; | |
| if ((((rwidth & 3) == 0) && ((((uintptr_t) dest) & 3u) == 0)) && ((vid.rowbytes & 3) == 0)) | |
| { | |
| uint32_t *ldest = (uint32_t *) dest; | |
| const uint32_t fill32 = 0x01010101u * ((uint8_t) color); | |
| const int32_t words = rwidth >> 2; | |
| for (int32_t y = 0; y < rheight; y++) | |
| { | |
| for (int32_t x = 0; x < words; x++) | |
| ldest[x] = fill32; | |
| ldest = (uint32_t *) (((uint8_t *) ldest) + vid.rowbytes); | |
| } | |
| } | |
| else | |
| { | |
| const uint8_t fill8 = (uint8_t) color; | |
| for (int32_t y = 0; y < rheight; y++) | |
| { | |
| for (int32_t x = 0; x < rwidth; x++) | |
| dest[x] = fill8; | |
| dest += vid.rowbytes; | |
| } | |
| } | |
| } | |
| void D_Init(void) | |
| { | |
| r_skydirect = 1; | |
| Cvar_RegisterVariable(&d_subdiv16); | |
| Cvar_RegisterVariable(&d_mipcap); | |
| Cvar_RegisterVariable(&d_mipscale); | |
| r_drawpolys = 0; | |
| r_worldpolysbacktofront = 0; | |
| r_recursiveaffinetriangles = 1; | |
| r_pixbytes = 1; | |
| r_aliasuvscale = 1.0; | |
| } | |
| void D_EnableBackBufferAccess(void) | |
| { | |
| VID_LockBuffer(); | |
| } | |
| void D_TurnZOn(void) | |
| { | |
| } | |
| void D_DisableBackBufferAccess(void) | |
| { | |
| VID_UnlockBuffer(); | |
| } | |
| void D_SetupFrame(void) | |
| { | |
| int32_t i; | |
| if (r_dowarp) | |
| d_viewbuffer = r_warpbuffer; | |
| else | |
| d_viewbuffer = (void *) ((uint8_t *) vid.buffer); | |
| if (r_dowarp) | |
| screenwidth = WARP_WIDTH; | |
| else | |
| screenwidth = vid.rowbytes; | |
| d_roverwrapped = 0; | |
| d_initial_rover = sc_rover; | |
| d_minmip = d_mipcap.value; | |
| if (d_minmip > 3) | |
| d_minmip = 3; | |
| else | |
| if (d_minmip < 0) | |
| d_minmip = 0; | |
| for (i = 0; i < (NUM_MIPS - 1); i++) | |
| d_scalemip[i] = basemip[i] * d_mipscale.value; | |
| d_drawspans = D_DrawSpans8; | |
| d_aflatcolor = 0; | |
| } | |
| void D_UpdateRects(vrect_t *prect) | |
| { | |
| UNUSED(prect); | |
| } | |
| void D_ViewChanged(void) | |
| { | |
| int32_t rowbytes; | |
| if (r_dowarp) | |
| rowbytes = WARP_WIDTH; | |
| else | |
| rowbytes = vid.rowbytes; | |
| scale_for_mip = xscale; | |
| if (yscale > xscale) | |
| scale_for_mip = yscale; | |
| d_zrowbytes = vid.width * 2; | |
| d_zwidth = vid.width; | |
| d_pix_min = r_refdef.vrect.width / 320; | |
| if (d_pix_min < 1) | |
| d_pix_min = 1; | |
| d_pix_max = (int32_t) ((((float) r_refdef.vrect.width) / (320.0 / 4.0)) + 0.5); | |
| d_pix_shift = 8 - ((int32_t) ((((float) r_refdef.vrect.width) / 320.0) + 0.5)); | |
| if (d_pix_max < 1) | |
| d_pix_max = 1; | |
| if (pixelAspect > 1.4) | |
| d_y_aspect_shift = 1; | |
| else | |
| d_y_aspect_shift = 0; | |
| d_vrectx = r_refdef.vrect.x; | |
| d_vrecty = r_refdef.vrect.y; | |
| d_vrectright_particle = r_refdef.vrectright - d_pix_max; | |
| d_vrectbottom_particle = r_refdef.vrectbottom - (d_pix_max << d_y_aspect_shift); | |
| { | |
| int32_t i; | |
| for (i = 0; i < vid.height; i++) | |
| { | |
| d_scantable[i] = i * rowbytes; | |
| zspantable[i] = d_pzbuffer + (i * d_zwidth); | |
| } | |
| } | |
| } | |
| void D_EndParticles(void) | |
| { | |
| } | |
| void D_StartParticles(void) | |
| { | |
| } | |
| void D_DrawParticle(particle_t *pparticle) | |
| { | |
| vec3_t local; | |
| vec3_t transformed; | |
| float zi; | |
| uint8_t *pdest; | |
| int16_t *pz; | |
| int32_t i; | |
| int32_t izi; | |
| int32_t pix; | |
| int32_t count; | |
| int32_t u; | |
| int32_t v; | |
| VectorSubtract(pparticle->org, r_origin, local); | |
| transformed[0] = DotProduct(local, r_pright); | |
| transformed[1] = DotProduct(local, r_pup); | |
| transformed[2] = DotProduct(local, r_ppn); | |
| if (transformed[2] < PARTICLE_Z_CLIP) | |
| return; | |
| zi = 1.0 / transformed[2]; | |
| u = (int32_t) ((xcenter + (zi * transformed[0])) + 0.5); | |
| v = (int32_t) ((ycenter - (zi * transformed[1])) + 0.5); | |
| if ((((v > d_vrectbottom_particle) || (u > d_vrectright_particle)) || (v < d_vrecty)) || (u < d_vrectx)) | |
| { | |
| return; | |
| } | |
| pz = (d_pzbuffer + (d_zwidth * v)) + u; | |
| pdest = (d_viewbuffer + d_scantable[v]) + u; | |
| izi = (int32_t) (zi * 0x8000); | |
| pix = izi >> d_pix_shift; | |
| if (pix < d_pix_min) | |
| pix = d_pix_min; | |
| else | |
| if (pix > d_pix_max) | |
| pix = d_pix_max; | |
| switch (pix) | |
| { | |
| case 1: | |
| count = 1 << d_y_aspect_shift; | |
| for (; count; count--, pz += d_zwidth, pdest += screenwidth) | |
| { | |
| if (pz[0] <= izi) | |
| { | |
| pz[0] = izi; | |
| pdest[0] = pparticle->color; | |
| } | |
| } | |
| break; | |
| case 2: | |
| count = 2 << d_y_aspect_shift; | |
| for (; count; count--, pz += d_zwidth, pdest += screenwidth) | |
| { | |
| if (pz[0] <= izi) | |
| { | |
| pz[0] = izi; | |
| pdest[0] = pparticle->color; | |
| } | |
| if (pz[1] <= izi) | |
| { | |
| pz[1] = izi; | |
| pdest[1] = pparticle->color; | |
| } | |
| } | |
| break; | |
| case 3: | |
| count = 3 << d_y_aspect_shift; | |
| for (; count; count--, pz += d_zwidth, pdest += screenwidth) | |
| { | |
| if (pz[0] <= izi) | |
| { | |
| pz[0] = izi; | |
| pdest[0] = pparticle->color; | |
| } | |
| if (pz[1] <= izi) | |
| { | |
| pz[1] = izi; | |
| pdest[1] = pparticle->color; | |
| } | |
| if (pz[2] <= izi) | |
| { | |
| pz[2] = izi; | |
| pdest[2] = pparticle->color; | |
| } | |
| } | |
| break; | |
| case 4: | |
| count = 4 << d_y_aspect_shift; | |
| for (; count; count--, pz += d_zwidth, pdest += screenwidth) | |
| { | |
| if (pz[0] <= izi) | |
| { | |
| pz[0] = izi; | |
| pdest[0] = pparticle->color; | |
| } | |
| if (pz[1] <= izi) | |
| { | |
| pz[1] = izi; | |
| pdest[1] = pparticle->color; | |
| } | |
| if (pz[2] <= izi) | |
| { | |
| pz[2] = izi; | |
| pdest[2] = pparticle->color; | |
| } | |
| if (pz[3] <= izi) | |
| { | |
| pz[3] = izi; | |
| pdest[3] = pparticle->color; | |
| } | |
| } | |
| break; | |
| default: | |
| count = pix << d_y_aspect_shift; | |
| for (; count; count--, pz += d_zwidth, pdest += screenwidth) | |
| { | |
| for (i = 0; i < pix; i++) | |
| { | |
| if (pz[i] <= izi) | |
| { | |
| pz[i] = izi; | |
| pdest[i] = pparticle->color; | |
| } | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| void D_PolysetDraw(void) | |
| { | |
| spanpackage_t spans[((DPS_MAXSPANS + 1) + ((CACHE_SIZE - 1) / (sizeof(spanpackage_t)))) + 1]; | |
| a_spans = (spanpackage_t *) ALIGN_PTR(&spans[0], CACHE_SIZE); | |
| if (r_affinetridesc.drawtype) | |
| { | |
| D_DrawSubdiv(); | |
| } | |
| else | |
| { | |
| D_DrawNonSubdiv(); | |
| } | |
| } | |
| void D_PolysetDrawFinalVerts(finalvert_t *fv, int32_t numverts) | |
| { | |
| int32_t i; | |
| int32_t z; | |
| int16_t *zbuf; | |
| for (i = 0; i < numverts; i++, fv++) | |
| { | |
| if ((fv->v[0] < r_refdef.vrectright) && (fv->v[1] < r_refdef.vrectbottom)) | |
| { | |
| z = fv->v[5] >> 16; | |
| if (z > 0x7FFF) | |
| z = 0x7FFF; | |
| if (z < 0) | |
| z = 0; | |
| zbuf = zspantable[fv->v[1]] + fv->v[0]; | |
| if (z >= (*zbuf)) | |
| { | |
| int32_t pix; | |
| *zbuf = z; | |
| int s = fv->v[2] >> 16; | |
| int t = fv->v[3] >> 16; | |
| if (((unsigned) s) >= ((unsigned) skinwidth)) | |
| s = skinwidth - 1; | |
| if (((unsigned) t) >= ((unsigned) MAX_LBM_HEIGHT)) | |
| t = MAX_LBM_HEIGHT - 1; | |
| pix = skintable[t][s]; | |
| pix = ((uint8_t *) acolormap)[pix + (fv->v[4] & 0xFF00)]; | |
| d_viewbuffer[d_scantable[fv->v[1]] + fv->v[0]] = pix; | |
| } | |
| } | |
| } | |
| } | |
| static void D_DrawSubdiv(void) | |
| { | |
| mtriangle_t *ptri; | |
| finalvert_t *pfv; | |
| finalvert_t *index0; | |
| finalvert_t *index1; | |
| finalvert_t *index2; | |
| int32_t i; | |
| int32_t lnumtriangles; | |
| pfv = r_affinetridesc.pfinalverts; | |
| ptri = r_affinetridesc.ptriangles; | |
| lnumtriangles = r_affinetridesc.numtriangles; | |
| for (i = 0; i < lnumtriangles; i++) | |
| { | |
| index0 = pfv + ptri[i].vertindex[0]; | |
| index1 = pfv + ptri[i].vertindex[1]; | |
| index2 = pfv + ptri[i].vertindex[2]; | |
| if ((((index0->v[1] - index1->v[1]) * (index0->v[0] - index2->v[0])) - ((index0->v[0] - index1->v[0]) * (index0->v[1] - index2->v[1]))) >= 0) | |
| { | |
| continue; | |
| } | |
| d_pcolormap = &((uint8_t *) acolormap)[index0->v[4] & 0xFF00]; | |
| if (ptri[i].facesfront) | |
| { | |
| D_PolysetRecursiveTriangle(index0->v, index1->v, index2->v); | |
| } | |
| else | |
| { | |
| int32_t s0; | |
| int32_t s1; | |
| int32_t s2; | |
| s0 = index0->v[2]; | |
| s1 = index1->v[2]; | |
| s2 = index2->v[2]; | |
| if (index0->flags & ALIAS_ONSEAM) | |
| index0->v[2] += r_affinetridesc.seamfixupX16; | |
| if (index1->flags & ALIAS_ONSEAM) | |
| index1->v[2] += r_affinetridesc.seamfixupX16; | |
| if (index2->flags & ALIAS_ONSEAM) | |
| index2->v[2] += r_affinetridesc.seamfixupX16; | |
| D_PolysetRecursiveTriangle(index0->v, index1->v, index2->v); | |
| index0->v[2] = s0; | |
| index1->v[2] = s1; | |
| index2->v[2] = s2; | |
| } | |
| } | |
| } | |
| static void D_DrawNonSubdiv(void) | |
| { | |
| mtriangle_t *ptri; | |
| finalvert_t *pfv; | |
| finalvert_t *index0; | |
| finalvert_t *index1; | |
| finalvert_t *index2; | |
| int32_t i; | |
| int32_t lnumtriangles; | |
| pfv = r_affinetridesc.pfinalverts; | |
| ptri = r_affinetridesc.ptriangles; | |
| lnumtriangles = r_affinetridesc.numtriangles; | |
| for (i = 0; i < lnumtriangles; i++, ptri++) | |
| { | |
| index0 = pfv + ptri->vertindex[0]; | |
| index1 = pfv + ptri->vertindex[1]; | |
| index2 = pfv + ptri->vertindex[2]; | |
| d_xdenom = ((index0->v[1] - index1->v[1]) * (index0->v[0] - index2->v[0])) - ((index0->v[0] - index1->v[0]) * (index0->v[1] - index2->v[1])); | |
| if (d_xdenom >= 0) | |
| { | |
| continue; | |
| } | |
| r_p0[0] = index0->v[0]; | |
| r_p0[1] = index0->v[1]; | |
| r_p0[2] = index0->v[2]; | |
| r_p0[3] = index0->v[3]; | |
| r_p0[4] = index0->v[4]; | |
| r_p0[5] = index0->v[5]; | |
| r_p1[0] = index1->v[0]; | |
| r_p1[1] = index1->v[1]; | |
| r_p1[2] = index1->v[2]; | |
| r_p1[3] = index1->v[3]; | |
| r_p1[4] = index1->v[4]; | |
| r_p1[5] = index1->v[5]; | |
| r_p2[0] = index2->v[0]; | |
| r_p2[1] = index2->v[1]; | |
| r_p2[2] = index2->v[2]; | |
| r_p2[3] = index2->v[3]; | |
| r_p2[4] = index2->v[4]; | |
| r_p2[5] = index2->v[5]; | |
| if (!ptri->facesfront) | |
| { | |
| if (index0->flags & ALIAS_ONSEAM) | |
| r_p0[2] += r_affinetridesc.seamfixupX16; | |
| if (index1->flags & ALIAS_ONSEAM) | |
| r_p1[2] += r_affinetridesc.seamfixupX16; | |
| if (index2->flags & ALIAS_ONSEAM) | |
| r_p2[2] += r_affinetridesc.seamfixupX16; | |
| } | |
| D_PolysetSetEdgeTable(); | |
| D_RasterizeAliasPolySmooth(); | |
| } | |
| } | |
| static void D_PolysetRecursiveTriangle(int32_t *lp1, int32_t *lp2, int32_t *lp3) | |
| { | |
| int32_t *temp; | |
| int32_t d; | |
| int32_t new[6]; | |
| int32_t z; | |
| int16_t *zbuf; | |
| d = lp2[0] - lp1[0]; | |
| if ((d < (-1)) || (d > 1)) | |
| goto split; | |
| d = lp2[1] - lp1[1]; | |
| if ((d < (-1)) || (d > 1)) | |
| goto split; | |
| d = lp3[0] - lp2[0]; | |
| if ((d < (-1)) || (d > 1)) | |
| goto split2; | |
| d = lp3[1] - lp2[1]; | |
| if ((d < (-1)) || (d > 1)) | |
| goto split2; | |
| d = lp1[0] - lp3[0]; | |
| if ((d < (-1)) || (d > 1)) | |
| goto split3; | |
| d = lp1[1] - lp3[1]; | |
| if ((d < (-1)) || (d > 1)) | |
| { | |
| split3: | |
| temp = lp1; | |
| lp1 = lp3; | |
| lp3 = lp2; | |
| lp2 = temp; | |
| goto split; | |
| } | |
| return; | |
| split2: | |
| temp = lp1; | |
| lp1 = lp2; | |
| lp2 = lp3; | |
| lp3 = temp; | |
| split: | |
| new[0] = (lp1[0] + lp2[0]) >> 1; | |
| new[1] = (lp1[1] + lp2[1]) >> 1; | |
| new[2] = (lp1[2] + lp2[2]) >> 1; | |
| new[3] = (lp1[3] + lp2[3]) >> 1; | |
| new[5] = (lp1[5] + lp2[5]) >> 1; | |
| if (lp2[1] > lp1[1]) | |
| goto nodraw; | |
| if ((lp2[1] == lp1[1]) && (lp2[0] < lp1[0])) | |
| goto nodraw; | |
| z = new[5] >> 16; | |
| zbuf = zspantable[new[1]] + new[0]; | |
| if (z >= (*zbuf)) | |
| { | |
| int32_t pix; | |
| *zbuf = z; | |
| pix = d_pcolormap[skintable[new[3] >> 16][new[2] >> 16]]; | |
| d_viewbuffer[d_scantable[new[1]] + new[0]] = pix; | |
| } | |
| nodraw: | |
| D_PolysetRecursiveTriangle(lp3, lp1, new); | |
| D_PolysetRecursiveTriangle(lp3, new, lp2); | |
| } | |
| void D_PolysetUpdateTables(void) | |
| { | |
| int32_t i; | |
| uint8_t *s; | |
| if ((r_affinetridesc.skinwidth != skinwidth) || (r_affinetridesc.pskin != skinstart)) | |
| { | |
| skinwidth = r_affinetridesc.skinwidth; | |
| skinstart = r_affinetridesc.pskin; | |
| s = skinstart; | |
| for (i = 0; i < MAX_LBM_HEIGHT; i++, s += skinwidth) | |
| skintable[i] = s; | |
| } | |
| } | |
| static void D_PolysetScanLeftEdge(int32_t height) | |
| { | |
| do | |
| { | |
| d_pedgespanpackage->pdest = d_pdest; | |
| d_pedgespanpackage->pz = d_pz; | |
| d_pedgespanpackage->count = d_aspancount; | |
| d_pedgespanpackage->ptex = d_ptex; | |
| d_pedgespanpackage->sfrac = d_sfrac; | |
| d_pedgespanpackage->tfrac = d_tfrac; | |
| d_pedgespanpackage->light = d_light; | |
| d_pedgespanpackage->zi = d_zi; | |
| d_pedgespanpackage++; | |
| errorterm += erroradjustup; | |
| if (errorterm >= 0) | |
| { | |
| d_pdest += d_pdestextrastep; | |
| d_pz += d_pzextrastep; | |
| d_aspancount += d_countextrastep; | |
| d_ptex += d_ptexextrastep; | |
| d_sfrac += d_sfracextrastep; | |
| d_ptex += d_sfrac >> 16; | |
| d_sfrac &= 0xFFFF; | |
| d_tfrac += d_tfracextrastep; | |
| if (d_tfrac & 0x10000) | |
| { | |
| d_ptex += r_affinetridesc.skinwidth; | |
| d_tfrac &= 0xFFFF; | |
| } | |
| d_light += d_lightextrastep; | |
| d_zi += d_ziextrastep; | |
| errorterm -= erroradjustdown; | |
| } | |
| else | |
| { | |
| d_pdest += d_pdestbasestep; | |
| d_pz += d_pzbasestep; | |
| d_aspancount += ubasestep; | |
| d_ptex += d_ptexbasestep; | |
| d_sfrac += d_sfracbasestep; | |
| d_ptex += d_sfrac >> 16; | |
| d_sfrac &= 0xFFFF; | |
| d_tfrac += d_tfracbasestep; | |
| if (d_tfrac & 0x10000) | |
| { | |
| d_ptex += r_affinetridesc.skinwidth; | |
| d_tfrac &= 0xFFFF; | |
| } | |
| d_light += d_lightbasestep; | |
| d_zi += d_zibasestep; | |
| } | |
| } | |
| while (--height); | |
| } | |
| static void D_PolysetSetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv, fixed8_t endvertu, fixed8_t endvertv) | |
| { | |
| double dm; | |
| double dn; | |
| int32_t tm; | |
| int32_t tn; | |
| adivtab_t *ptemp; | |
| errorterm = -1; | |
| tm = endvertu - startvertu; | |
| tn = endvertv - startvertv; | |
| if (((tm <= 16) && (tm >= (-15))) && ((tn <= 16) && (tn >= (-15)))) | |
| { | |
| ptemp = &adivtab[((tm + 15) << 5) + (tn + 15)]; | |
| ubasestep = ptemp->quotient; | |
| erroradjustup = ptemp->remainder; | |
| erroradjustdown = tn; | |
| } | |
| else | |
| { | |
| dm = (double) tm; | |
| dn = (double) tn; | |
| FloorDivMod(dm, dn, &ubasestep, &erroradjustup); | |
| erroradjustdown = dn; | |
| } | |
| } | |
| static void D_PolysetCalcGradients(int32_t skinwidth) | |
| { | |
| float xstepdenominv; | |
| float ystepdenominv; | |
| float t0; | |
| float t1; | |
| float p01_minus_p21; | |
| float p11_minus_p21; | |
| float p00_minus_p20; | |
| float p10_minus_p20; | |
| p00_minus_p20 = r_p0[0] - r_p2[0]; | |
| p01_minus_p21 = r_p0[1] - r_p2[1]; | |
| p10_minus_p20 = r_p1[0] - r_p2[0]; | |
| p11_minus_p21 = r_p1[1] - r_p2[1]; | |
| xstepdenominv = 1.0 / ((float) d_xdenom); | |
| ystepdenominv = -xstepdenominv; | |
| t0 = r_p0[4] - r_p2[4]; | |
| t1 = r_p1[4] - r_p2[4]; | |
| r_lstepx = (int32_t) ceil(((t1 * p01_minus_p21) - (t0 * p11_minus_p21)) * xstepdenominv); | |
| r_lstepy = (int32_t) ceil(((t1 * p00_minus_p20) - (t0 * p10_minus_p20)) * ystepdenominv); | |
| t0 = r_p0[2] - r_p2[2]; | |
| t1 = r_p1[2] - r_p2[2]; | |
| r_sstepx = (int32_t) (((t1 * p01_minus_p21) - (t0 * p11_minus_p21)) * xstepdenominv); | |
| r_sstepy = (int32_t) (((t1 * p00_minus_p20) - (t0 * p10_minus_p20)) * ystepdenominv); | |
| t0 = r_p0[3] - r_p2[3]; | |
| t1 = r_p1[3] - r_p2[3]; | |
| r_tstepx = (int32_t) (((t1 * p01_minus_p21) - (t0 * p11_minus_p21)) * xstepdenominv); | |
| r_tstepy = (int32_t) (((t1 * p00_minus_p20) - (t0 * p10_minus_p20)) * ystepdenominv); | |
| t0 = r_p0[5] - r_p2[5]; | |
| t1 = r_p1[5] - r_p2[5]; | |
| r_zistepx = (int32_t) (((t1 * p01_minus_p21) - (t0 * p11_minus_p21)) * xstepdenominv); | |
| r_zistepy = (int32_t) (((t1 * p00_minus_p20) - (t0 * p10_minus_p20)) * ystepdenominv); | |
| a_sstepxfrac = r_sstepx & 0xFFFF; | |
| a_tstepxfrac = r_tstepx & 0xFFFF; | |
| a_ststepxwhole = (skinwidth * (r_tstepx >> 16)) + (r_sstepx >> 16); | |
| } | |
| static void D_PolysetDrawSpans8(spanpackage_t *pspanpackage) | |
| { | |
| int32_t lcount; | |
| uint8_t *lpdest; | |
| uint8_t *lptex; | |
| int32_t lsfrac; | |
| int32_t ltfrac; | |
| int32_t llight; | |
| int32_t lzi; | |
| int16_t *lpz; | |
| do | |
| { | |
| lcount = d_aspancount - pspanpackage->count; | |
| errorterm += erroradjustup; | |
| if (errorterm >= 0) | |
| { | |
| d_aspancount += d_countextrastep; | |
| errorterm -= erroradjustdown; | |
| } | |
| else | |
| { | |
| d_aspancount += ubasestep; | |
| } | |
| if (lcount) | |
| { | |
| lpdest = pspanpackage->pdest; | |
| lptex = pspanpackage->ptex; | |
| lpz = pspanpackage->pz; | |
| lsfrac = pspanpackage->sfrac; | |
| ltfrac = pspanpackage->tfrac; | |
| llight = pspanpackage->light; | |
| lzi = pspanpackage->zi; | |
| do | |
| { | |
| if ((lzi >> 16) >= (*lpz)) | |
| { | |
| *lpdest = ((uint8_t *) acolormap)[(*lptex) + (llight & 0xFF00)]; | |
| *lpz = lzi >> 16; | |
| } | |
| lpdest++; | |
| lzi += r_zistepx; | |
| lpz++; | |
| llight += r_lstepx; | |
| lptex += a_ststepxwhole; | |
| lsfrac += a_sstepxfrac; | |
| lptex += lsfrac >> 16; | |
| lsfrac &= 0xFFFF; | |
| ltfrac += a_tstepxfrac; | |
| if (ltfrac & 0x10000) | |
| { | |
| lptex += r_affinetridesc.skinwidth; | |
| ltfrac &= 0xFFFF; | |
| } | |
| } | |
| while (--lcount); | |
| } | |
| pspanpackage++; | |
| } | |
| while (pspanpackage->count != (-999999)); | |
| } | |
| static void D_PolysetFillSpans8(spanpackage_t *pspanpackage) | |
| { | |
| int32_t color; | |
| color = d_aflatcolor++; | |
| while (1) | |
| { | |
| int32_t lcount; | |
| uint8_t *lpdest; | |
| lcount = pspanpackage->count; | |
| if (lcount == (-1)) | |
| return; | |
| if (lcount) | |
| { | |
| lpdest = pspanpackage->pdest; | |
| do | |
| { | |
| *(lpdest++) = color; | |
| } | |
| while (--lcount); | |
| } | |
| pspanpackage++; | |
| } | |
| } | |
| static void D_RasterizeAliasPolySmooth(void) | |
| { | |
| int32_t initialleftheight; | |
| int32_t initialrightheight; | |
| int32_t *plefttop; | |
| int32_t *prighttop; | |
| int32_t *pleftbottom; | |
| int32_t *prightbottom; | |
| int32_t working_lstepx; | |
| int32_t originalcount; | |
| plefttop = pedgetable->pleftedgevert0; | |
| prighttop = pedgetable->prightedgevert0; | |
| pleftbottom = pedgetable->pleftedgevert1; | |
| prightbottom = pedgetable->prightedgevert1; | |
| initialleftheight = pleftbottom[1] - plefttop[1]; | |
| initialrightheight = prightbottom[1] - prighttop[1]; | |
| D_PolysetCalcGradients(r_affinetridesc.skinwidth); | |
| d_pedgespanpackage = a_spans; | |
| ystart = plefttop[1]; | |
| d_aspancount = plefttop[0] - prighttop[0]; | |
| d_ptex = (((uint8_t *) r_affinetridesc.pskin) + (plefttop[2] >> 16)) + ((plefttop[3] >> 16) * r_affinetridesc.skinwidth); | |
| d_sfrac = plefttop[2] & 0xFFFF; | |
| d_tfrac = plefttop[3] & 0xFFFF; | |
| d_light = plefttop[4]; | |
| d_zi = plefttop[5]; | |
| d_pdest = (((uint8_t *) d_viewbuffer) + (ystart * screenwidth)) + plefttop[0]; | |
| d_pz = (d_pzbuffer + (ystart * d_zwidth)) + plefttop[0]; | |
| if (initialleftheight == 1) | |
| { | |
| d_pedgespanpackage->pdest = d_pdest; | |
| d_pedgespanpackage->pz = d_pz; | |
| d_pedgespanpackage->count = d_aspancount; | |
| d_pedgespanpackage->ptex = d_ptex; | |
| d_pedgespanpackage->sfrac = d_sfrac; | |
| d_pedgespanpackage->tfrac = d_tfrac; | |
| d_pedgespanpackage->light = d_light; | |
| d_pedgespanpackage->zi = d_zi; | |
| d_pedgespanpackage++; | |
| } | |
| else | |
| { | |
| D_PolysetSetUpForLineScan(plefttop[0], plefttop[1], pleftbottom[0], pleftbottom[1]); | |
| d_pzbasestep = d_zwidth + ubasestep; | |
| d_pzextrastep = d_pzbasestep + 1; | |
| d_pdestbasestep = screenwidth + ubasestep; | |
| d_pdestextrastep = d_pdestbasestep + 1; | |
| if (ubasestep < 0) | |
| working_lstepx = r_lstepx - 1; | |
| else | |
| working_lstepx = r_lstepx; | |
| d_countextrastep = ubasestep + 1; | |
| d_ptexbasestep = ((r_sstepy + (r_sstepx * ubasestep)) >> 16) + (((r_tstepy + (r_tstepx * ubasestep)) >> 16) * r_affinetridesc.skinwidth); | |
| d_sfracbasestep = (r_sstepy + (r_sstepx * ubasestep)) & 0xFFFF; | |
| d_tfracbasestep = (r_tstepy + (r_tstepx * ubasestep)) & 0xFFFF; | |
| d_lightbasestep = r_lstepy + (working_lstepx * ubasestep); | |
| d_zibasestep = r_zistepy + (r_zistepx * ubasestep); | |
| d_ptexextrastep = ((r_sstepy + (r_sstepx * d_countextrastep)) >> 16) + (((r_tstepy + (r_tstepx * d_countextrastep)) >> 16) * r_affinetridesc.skinwidth); | |
| d_sfracextrastep = (r_sstepy + (r_sstepx * d_countextrastep)) & 0xFFFF; | |
| d_tfracextrastep = (r_tstepy + (r_tstepx * d_countextrastep)) & 0xFFFF; | |
| d_lightextrastep = d_lightbasestep + working_lstepx; | |
| d_ziextrastep = d_zibasestep + r_zistepx; | |
| D_PolysetScanLeftEdge(initialleftheight); | |
| } | |
| if (pedgetable->numleftedges == 2) | |
| { | |
| int32_t height; | |
| plefttop = pleftbottom; | |
| pleftbottom = pedgetable->pleftedgevert2; | |
| height = pleftbottom[1] - plefttop[1]; | |
| ystart = plefttop[1]; | |
| d_aspancount = plefttop[0] - prighttop[0]; | |
| d_ptex = (((uint8_t *) r_affinetridesc.pskin) + (plefttop[2] >> 16)) + ((plefttop[3] >> 16) * r_affinetridesc.skinwidth); | |
| d_sfrac = 0; | |
| d_tfrac = 0; | |
| d_light = plefttop[4]; | |
| d_zi = plefttop[5]; | |
| d_pdest = (((uint8_t *) d_viewbuffer) + (ystart * screenwidth)) + plefttop[0]; | |
| d_pz = (d_pzbuffer + (ystart * d_zwidth)) + plefttop[0]; | |
| if (height == 1) | |
| { | |
| d_pedgespanpackage->pdest = d_pdest; | |
| d_pedgespanpackage->pz = d_pz; | |
| d_pedgespanpackage->count = d_aspancount; | |
| d_pedgespanpackage->ptex = d_ptex; | |
| d_pedgespanpackage->sfrac = d_sfrac; | |
| d_pedgespanpackage->tfrac = d_tfrac; | |
| d_pedgespanpackage->light = d_light; | |
| d_pedgespanpackage->zi = d_zi; | |
| d_pedgespanpackage++; | |
| } | |
| else | |
| { | |
| D_PolysetSetUpForLineScan(plefttop[0], plefttop[1], pleftbottom[0], pleftbottom[1]); | |
| d_pdestbasestep = screenwidth + ubasestep; | |
| d_pdestextrastep = d_pdestbasestep + 1; | |
| d_pzbasestep = d_zwidth + ubasestep; | |
| d_pzextrastep = d_pzbasestep + 1; | |
| if (ubasestep < 0) | |
| working_lstepx = r_lstepx - 1; | |
| else | |
| working_lstepx = r_lstepx; | |
| d_countextrastep = ubasestep + 1; | |
| d_ptexbasestep = ((r_sstepy + (r_sstepx * ubasestep)) >> 16) + (((r_tstepy + (r_tstepx * ubasestep)) >> 16) * r_affinetridesc.skinwidth); | |
| d_sfracbasestep = (r_sstepy + (r_sstepx * ubasestep)) & 0xFFFF; | |
| d_tfracbasestep = (r_tstepy + (r_tstepx * ubasestep)) & 0xFFFF; | |
| d_lightbasestep = r_lstepy + (working_lstepx * ubasestep); | |
| d_zibasestep = r_zistepy + (r_zistepx * ubasestep); | |
| d_ptexextrastep = ((r_sstepy + (r_sstepx * d_countextrastep)) >> 16) + (((r_tstepy + (r_tstepx * d_countextrastep)) >> 16) * r_affinetridesc.skinwidth); | |
| d_sfracextrastep = (r_sstepy + (r_sstepx * d_countextrastep)) & 0xFFFF; | |
| d_tfracextrastep = (r_tstepy + (r_tstepx * d_countextrastep)) & 0xFFFF; | |
| d_lightextrastep = d_lightbasestep + working_lstepx; | |
| d_ziextrastep = d_zibasestep + r_zistepx; | |
| D_PolysetScanLeftEdge(height); | |
| } | |
| } | |
| d_pedgespanpackage = a_spans; | |
| D_PolysetSetUpForLineScan(prighttop[0], prighttop[1], prightbottom[0], prightbottom[1]); | |
| d_aspancount = 0; | |
| d_countextrastep = ubasestep + 1; | |
| originalcount = a_spans[initialrightheight].count; | |
| a_spans[initialrightheight].count = -999999; | |
| D_PolysetDrawSpans8(a_spans); | |
| if (pedgetable->numrightedges == 2) | |
| { | |
| int32_t height; | |
| spanpackage_t *pstart; | |
| pstart = a_spans + initialrightheight; | |
| pstart->count = originalcount; | |
| d_aspancount = prightbottom[0] - prighttop[0]; | |
| prighttop = prightbottom; | |
| prightbottom = pedgetable->prightedgevert2; | |
| height = prightbottom[1] - prighttop[1]; | |
| D_PolysetSetUpForLineScan(prighttop[0], prighttop[1], prightbottom[0], prightbottom[1]); | |
| d_countextrastep = ubasestep + 1; | |
| a_spans[initialrightheight + height].count = -999999; | |
| D_PolysetDrawSpans8(pstart); | |
| } | |
| } | |
| static void D_PolysetSetEdgeTable(void) | |
| { | |
| int32_t edgetableindex; | |
| edgetableindex = 0; | |
| if (r_p0[1] >= r_p1[1]) | |
| { | |
| if (r_p0[1] == r_p1[1]) | |
| { | |
| if (r_p0[1] < r_p2[1]) | |
| pedgetable = &edgetables[2]; | |
| else | |
| pedgetable = &edgetables[5]; | |
| return; | |
| } | |
| else | |
| { | |
| edgetableindex = 1; | |
| } | |
| } | |
| if (r_p0[1] == r_p2[1]) | |
| { | |
| if (edgetableindex) | |
| pedgetable = &edgetables[8]; | |
| else | |
| pedgetable = &edgetables[9]; | |
| return; | |
| } | |
| else | |
| if (r_p1[1] == r_p2[1]) | |
| { | |
| if (edgetableindex) | |
| pedgetable = &edgetables[10]; | |
| else | |
| pedgetable = &edgetables[11]; | |
| return; | |
| } | |
| if (r_p0[1] > r_p2[1]) | |
| edgetableindex += 2; | |
| if (r_p1[1] > r_p2[1]) | |
| edgetableindex += 4; | |
| pedgetable = &edgetables[edgetableindex]; | |
| } | |
| void D_WarpScreen(void) | |
| { | |
| int32_t w; | |
| int32_t h; | |
| int32_t u; | |
| int32_t v; | |
| uint8_t *dest; | |
| int32_t *turb; | |
| int32_t *col; | |
| uint8_t **row; | |
| uint8_t *rowptr[MAXHEIGHT + (AMP2 * 2)]; | |
| int32_t column[MAXWIDTH + (AMP2 * 2)]; | |
| float wratio; | |
| float hratio; | |
| w = r_refdef.vrect.width; | |
| h = r_refdef.vrect.height; | |
| wratio = w / ((float) scr_vrect.width); | |
| hratio = h / ((float) scr_vrect.height); | |
| for (v = 0; v < (scr_vrect.height + (AMP2 * 2)); v++) | |
| { | |
| rowptr[v] = (d_viewbuffer + (r_refdef.vrect.y * screenwidth)) + (screenwidth * ((int32_t) (((((float) v) * hratio) * h) / (h + (AMP2 * 2))))); | |
| } | |
| for (u = 0; u < (scr_vrect.width + (AMP2 * 2)); u++) | |
| { | |
| column[u] = r_refdef.vrect.x + ((int32_t) (((((float) u) * wratio) * w) / (w + (AMP2 * 2)))); | |
| } | |
| turb = intsintable + (((int32_t) (cl.time * SPEED)) & (CYCLE - 1)); | |
| dest = (vid.buffer + (scr_vrect.y * vid.rowbytes)) + scr_vrect.x; | |
| for (v = 0; v < scr_vrect.height; v++, dest += vid.rowbytes) | |
| { | |
| col = &column[turb[v]]; | |
| row = &rowptr[v]; | |
| for (u = 0; u < scr_vrect.width; u += 4) | |
| { | |
| dest[u + 0] = row[turb[u + 0]][col[u + 0]]; | |
| dest[u + 1] = row[turb[u + 1]][col[u + 1]]; | |
| dest[u + 2] = row[turb[u + 2]][col[u + 2]]; | |
| dest[u + 3] = row[turb[u + 3]][col[u + 3]]; | |
| } | |
| } | |
| } | |
| static void D_DrawTurbulent8Span(void) | |
| { | |
| int32_t sturb; | |
| int32_t tturb; | |
| do | |
| { | |
| sturb = ((r_turb_s + r_turb_turb[(r_turb_t >> 16) & (CYCLE - 1)]) >> 16) & 63; | |
| tturb = ((r_turb_t + r_turb_turb[(r_turb_s >> 16) & (CYCLE - 1)]) >> 16) & 63; | |
| *(r_turb_pdest++) = *((r_turb_pbase + (tturb << 6)) + sturb); | |
| r_turb_s += r_turb_sstep; | |
| r_turb_t += r_turb_tstep; | |
| } | |
| while ((--r_turb_spancount) > 0); | |
| } | |
| void Turbulent8(espan_t *pspan) | |
| { | |
| int32_t count; | |
| fixed16_t snext; | |
| fixed16_t tnext; | |
| float sdivz; | |
| float tdivz; | |
| float zi; | |
| float z; | |
| float du; | |
| float dv; | |
| float spancountminus1; | |
| float sdivz16stepu; | |
| float tdivz16stepu; | |
| float zi16stepu; | |
| r_turb_turb = sintable + (((int32_t) (cl.time * SPEED)) & (CYCLE - 1)); | |
| r_turb_sstep = 0; | |
| r_turb_tstep = 0; | |
| r_turb_pbase = (unsigned char *) cacheblock; | |
| sdivz16stepu = d_sdivzstepu * 16; | |
| tdivz16stepu = d_tdivzstepu * 16; | |
| zi16stepu = d_zistepu * 16; | |
| do | |
| { | |
| r_turb_pdest = (unsigned char *) ((((uint8_t *) d_viewbuffer) + (screenwidth * pspan->v)) + pspan->u); | |
| count = pspan->count; | |
| du = (float) pspan->u; | |
| dv = (float) pspan->v; | |
| sdivz = (d_sdivzorigin + (dv * d_sdivzstepv)) + (du * d_sdivzstepu); | |
| tdivz = (d_tdivzorigin + (dv * d_tdivzstepv)) + (du * d_tdivzstepu); | |
| zi = (d_ziorigin + (dv * d_zistepv)) + (du * d_zistepu); | |
| z = ((float) 0x10000) / zi; | |
| r_turb_s = ((int32_t) (sdivz * z)) + sadjust; | |
| if (r_turb_s > bbextents) | |
| r_turb_s = bbextents; | |
| else | |
| if (r_turb_s < 0) | |
| r_turb_s = 0; | |
| r_turb_t = ((int32_t) (tdivz * z)) + tadjust; | |
| if (r_turb_t > bbextentt) | |
| r_turb_t = bbextentt; | |
| else | |
| if (r_turb_t < 0) | |
| r_turb_t = 0; | |
| do | |
| { | |
| if (count >= 16) | |
| r_turb_spancount = 16; | |
| else | |
| r_turb_spancount = count; | |
| count -= r_turb_spancount; | |
| if (count) | |
| { | |
| sdivz += sdivz16stepu; | |
| tdivz += tdivz16stepu; | |
| zi += zi16stepu; | |
| z = ((float) 0x10000) / zi; | |
| snext = ((int32_t) (sdivz * z)) + sadjust; | |
| if (snext > bbextents) | |
| snext = bbextents; | |
| else | |
| if (snext < 16) | |
| snext = 16; | |
| tnext = ((int32_t) (tdivz * z)) + tadjust; | |
| if (tnext > bbextentt) | |
| tnext = bbextentt; | |
| else | |
| if (tnext < 16) | |
| tnext = 16; | |
| r_turb_sstep = (snext - r_turb_s) >> 4; | |
| r_turb_tstep = (tnext - r_turb_t) >> 4; | |
| } | |
| else | |
| { | |
| spancountminus1 = (float) (r_turb_spancount - 1); | |
| sdivz += d_sdivzstepu * spancountminus1; | |
| tdivz += d_tdivzstepu * spancountminus1; | |
| zi += d_zistepu * spancountminus1; | |
| z = ((float) 0x10000) / zi; | |
| snext = ((int32_t) (sdivz * z)) + sadjust; | |
| if (snext > bbextents) | |
| snext = bbextents; | |
| else | |
| if (snext < 16) | |
| snext = 16; | |
| tnext = ((int32_t) (tdivz * z)) + tadjust; | |
| if (tnext > bbextentt) | |
| tnext = bbextentt; | |
| else | |
| if (tnext < 16) | |
| tnext = 16; | |
| if (r_turb_spancount > 1) | |
| { | |
| r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1); | |
| r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1); | |
| } | |
| } | |
| r_turb_s = r_turb_s & ((CYCLE << 16) - 1); | |
| r_turb_t = r_turb_t & ((CYCLE << 16) - 1); | |
| D_DrawTurbulent8Span(); | |
| r_turb_s = snext; | |
| r_turb_t = tnext; | |
| } | |
| while (count > 0); | |
| } | |
| while ((pspan = pspan->pnext) != 0); | |
| } | |
| void D_DrawSpans8(espan_t *pspan) | |
| { | |
| int32_t count; | |
| int32_t spancount; | |
| unsigned char *pbase; | |
| unsigned char *pdest; | |
| fixed16_t s; | |
| fixed16_t t; | |
| fixed16_t snext; | |
| fixed16_t tnext; | |
| fixed16_t sstep; | |
| fixed16_t tstep; | |
| float sdivz; | |
| float tdivz; | |
| float zi; | |
| float z; | |
| float du; | |
| float dv; | |
| float spancountminus1; | |
| float sdivz8stepu; | |
| float tdivz8stepu; | |
| float zi8stepu; | |
| sstep = 0; | |
| tstep = 0; | |
| pbase = (unsigned char *) cacheblock; | |
| sdivz8stepu = d_sdivzstepu * 8; | |
| tdivz8stepu = d_tdivzstepu * 8; | |
| zi8stepu = d_zistepu * 8; | |
| do | |
| { | |
| pdest = (unsigned char *) ((((uint8_t *) d_viewbuffer) + (screenwidth * pspan->v)) + pspan->u); | |
| count = pspan->count; | |
| du = (float) pspan->u; | |
| dv = (float) pspan->v; | |
| sdivz = (d_sdivzorigin + (dv * d_sdivzstepv)) + (du * d_sdivzstepu); | |
| tdivz = (d_tdivzorigin + (dv * d_tdivzstepv)) + (du * d_tdivzstepu); | |
| zi = (d_ziorigin + (dv * d_zistepv)) + (du * d_zistepu); | |
| z = ((float) 0x10000) / zi; | |
| s = ((int32_t) (sdivz * z)) + sadjust; | |
| if (s > bbextents) | |
| s = bbextents; | |
| else | |
| if (s < 0) | |
| s = 0; | |
| t = ((int32_t) (tdivz * z)) + tadjust; | |
| if (t > bbextentt) | |
| t = bbextentt; | |
| else | |
| if (t < 0) | |
| t = 0; | |
| do | |
| { | |
| if (count >= 8) | |
| spancount = 8; | |
| else | |
| spancount = count; | |
| count -= spancount; | |
| if (count) | |
| { | |
| sdivz += sdivz8stepu; | |
| tdivz += tdivz8stepu; | |
| zi += zi8stepu; | |
| z = ((float) 0x10000) / zi; | |
| snext = ((int32_t) (sdivz * z)) + sadjust; | |
| if (snext > bbextents) | |
| snext = bbextents; | |
| else | |
| if (snext < 8) | |
| snext = 8; | |
| tnext = ((int32_t) (tdivz * z)) + tadjust; | |
| if (tnext > bbextentt) | |
| tnext = bbextentt; | |
| else | |
| if (tnext < 8) | |
| tnext = 8; | |
| sstep = (snext - s) >> 3; | |
| tstep = (tnext - t) >> 3; | |
| } | |
| else | |
| { | |
| spancountminus1 = (float) (spancount - 1); | |
| sdivz += d_sdivzstepu * spancountminus1; | |
| tdivz += d_tdivzstepu * spancountminus1; | |
| zi += d_zistepu * spancountminus1; | |
| z = ((float) 0x10000) / zi; | |
| snext = ((int32_t) (sdivz * z)) + sadjust; | |
| if (snext > bbextents) | |
| snext = bbextents; | |
| else | |
| if (snext < 8) | |
| snext = 8; | |
| tnext = ((int32_t) (tdivz * z)) + tadjust; | |
| if (tnext > bbextentt) | |
| tnext = bbextentt; | |
| else | |
| if (tnext < 8) | |
| tnext = 8; | |
| if (spancount > 1) | |
| { | |
| sstep = (snext - s) / (spancount - 1); | |
| tstep = (tnext - t) / (spancount - 1); | |
| } | |
| } | |
| do | |
| { | |
| *(pdest++) = *((pbase + (s >> 16)) + ((t >> 16) * cachewidth)); | |
| s += sstep; | |
| t += tstep; | |
| } | |
| while ((--spancount) > 0); | |
| s = snext; | |
| t = tnext; | |
| } | |
| while (count > 0); | |
| } | |
| while ((pspan = pspan->pnext) != 0); | |
| } | |
| void D_DrawZSpans(espan_t *pspan) | |
| { | |
| int32_t count; | |
| int32_t doublecount; | |
| int32_t izistep; | |
| int32_t izi; | |
| int16_t *pdest; | |
| uint32_t ltemp; | |
| double zi; | |
| float du; | |
| float dv; | |
| izistep = (int32_t) ((d_zistepu * 0x8000) * 0x10000); | |
| do | |
| { | |
| pdest = (d_pzbuffer + (d_zwidth * pspan->v)) + pspan->u; | |
| count = pspan->count; | |
| du = (float) pspan->u; | |
| dv = (float) pspan->v; | |
| zi = (d_ziorigin + (dv * d_zistepv)) + (du * d_zistepu); | |
| izi = (int32_t) ((zi * 0x8000) * 0x10000); | |
| if (((int32_t) pdest) & 0x02) | |
| { | |
| *(pdest++) = (int16_t) (izi >> 16); | |
| izi += izistep; | |
| count--; | |
| } | |
| if ((doublecount = count >> 1) > 0) | |
| { | |
| do | |
| { | |
| ltemp = izi >> 16; | |
| izi += izistep; | |
| ltemp |= izi & 0xFFFF0000; | |
| izi += izistep; | |
| *((int32_t *) pdest) = ltemp; | |
| pdest += 2; | |
| } | |
| while ((--doublecount) > 0); | |
| } | |
| if (count & 1) | |
| *pdest = (int16_t) (izi >> 16); | |
| } | |
| while ((pspan = pspan->pnext) != 0); | |
| } | |
| static void D_Sky_uv_To_st(int32_t u, int32_t v, fixed16_t *s, fixed16_t *t) | |
| { | |
| float wu; | |
| float wv; | |
| float temp; | |
| vec3_t end; | |
| if (r_refdef.vrect.width >= r_refdef.vrect.height) | |
| temp = (float) r_refdef.vrect.width; | |
| else | |
| temp = (float) r_refdef.vrect.height; | |
| wu = (8192.0 * ((float) (u - (((int32_t) vid.width) >> 1)))) / temp; | |
| wv = (8192.0 * ((float) ((((int32_t) vid.height) >> 1) - v))) / temp; | |
| end[0] = ((4096 * vpn[0]) + (wu * vright[0])) + (wv * vup[0]); | |
| end[1] = ((4096 * vpn[1]) + (wu * vright[1])) + (wv * vup[1]); | |
| end[2] = ((4096 * vpn[2]) + (wu * vright[2])) + (wv * vup[2]); | |
| end[2] *= 3; | |
| VectorNormalize(end); | |
| temp = skytime * skyspeed; | |
| *s = (int32_t) ((temp + ((6 * ((SKYSIZE / 2) - 1)) * end[0])) * 0x10000); | |
| *t = (int32_t) ((temp + ((6 * ((SKYSIZE / 2) - 1)) * end[1])) * 0x10000); | |
| } | |
| void D_DrawSkyScans8(espan_t *pspan) | |
| { | |
| int32_t count; | |
| int32_t spancount; | |
| int32_t u; | |
| int32_t v; | |
| unsigned char *pdest; | |
| fixed16_t s; | |
| fixed16_t t; | |
| fixed16_t snext; | |
| fixed16_t tnext; | |
| fixed16_t sstep; | |
| fixed16_t tstep; | |
| int32_t spancountminus1; | |
| sstep = 0; | |
| tstep = 0; | |
| do | |
| { | |
| pdest = (unsigned char *) ((((uint8_t *) d_viewbuffer) + (screenwidth * pspan->v)) + pspan->u); | |
| count = pspan->count; | |
| u = pspan->u; | |
| v = pspan->v; | |
| D_Sky_uv_To_st(u, v, &s, &t); | |
| do | |
| { | |
| if (count >= SKY_SPAN_MAX) | |
| spancount = SKY_SPAN_MAX; | |
| else | |
| spancount = count; | |
| count -= spancount; | |
| if (count) | |
| { | |
| u += spancount; | |
| D_Sky_uv_To_st(u, v, &snext, &tnext); | |
| sstep = (snext - s) >> SKY_SPAN_SHIFT; | |
| tstep = (tnext - t) >> SKY_SPAN_SHIFT; | |
| } | |
| else | |
| { | |
| spancountminus1 = (float) (spancount - 1); | |
| if (spancountminus1 > 0) | |
| { | |
| u += spancountminus1; | |
| D_Sky_uv_To_st(u, v, &snext, &tnext); | |
| sstep = (snext - s) / spancountminus1; | |
| tstep = (tnext - t) / spancountminus1; | |
| } | |
| } | |
| do | |
| { | |
| *(pdest++) = r_skysource[((t & R_SKY_TMASK) >> 8) + ((s & R_SKY_SMASK) >> 16)]; | |
| s += sstep; | |
| t += tstep; | |
| } | |
| while ((--spancount) > 0); | |
| s = snext; | |
| t = tnext; | |
| } | |
| while (count > 0); | |
| } | |
| while ((pspan = pspan->pnext) != 0); | |
| } | |
| void D_SpriteDrawSpans(sspan_t *pspan) | |
| { | |
| int32_t count; | |
| int32_t spancount; | |
| int32_t izistep; | |
| int32_t izi; | |
| uint8_t *pbase; | |
| uint8_t *pdest; | |
| fixed16_t s; | |
| fixed16_t t; | |
| fixed16_t snext; | |
| fixed16_t tnext; | |
| fixed16_t sstep; | |
| fixed16_t tstep; | |
| float sdivz; | |
| float tdivz; | |
| float zi; | |
| float z; | |
| float du; | |
| float dv; | |
| float spancountminus1; | |
| float sdivz8stepu; | |
| float tdivz8stepu; | |
| float zi8stepu; | |
| uint8_t btemp; | |
| int16_t *pz; | |
| sstep = 0; | |
| tstep = 0; | |
| pbase = cacheblock; | |
| sdivz8stepu = d_sdivzstepu * 8; | |
| tdivz8stepu = d_tdivzstepu * 8; | |
| zi8stepu = d_zistepu * 8; | |
| izistep = (int32_t) ((d_zistepu * 0x8000) * 0x10000); | |
| do | |
| { | |
| pdest = (((uint8_t *) d_viewbuffer) + (screenwidth * pspan->v)) + pspan->u; | |
| pz = (d_pzbuffer + (d_zwidth * pspan->v)) + pspan->u; | |
| count = pspan->count; | |
| if (count <= 0) | |
| goto NextSpan; | |
| du = (float) pspan->u; | |
| dv = (float) pspan->v; | |
| sdivz = (d_sdivzorigin + (dv * d_sdivzstepv)) + (du * d_sdivzstepu); | |
| tdivz = (d_tdivzorigin + (dv * d_tdivzstepv)) + (du * d_tdivzstepu); | |
| zi = (d_ziorigin + (dv * d_zistepv)) + (du * d_zistepu); | |
| z = ((float) 0x10000) / zi; | |
| izi = (int32_t) ((zi * 0x8000) * 0x10000); | |
| s = ((int32_t) (sdivz * z)) + sadjust; | |
| if (s > bbextents) | |
| s = bbextents; | |
| else | |
| if (s < 0) | |
| s = 0; | |
| t = ((int32_t) (tdivz * z)) + tadjust; | |
| if (t > bbextentt) | |
| t = bbextentt; | |
| else | |
| if (t < 0) | |
| t = 0; | |
| do | |
| { | |
| if (count >= 8) | |
| spancount = 8; | |
| else | |
| spancount = count; | |
| count -= spancount; | |
| if (count) | |
| { | |
| sdivz += sdivz8stepu; | |
| tdivz += tdivz8stepu; | |
| zi += zi8stepu; | |
| z = ((float) 0x10000) / zi; | |
| snext = ((int32_t) (sdivz * z)) + sadjust; | |
| if (snext > bbextents) | |
| snext = bbextents; | |
| else | |
| if (snext < 8) | |
| snext = 8; | |
| tnext = ((int32_t) (tdivz * z)) + tadjust; | |
| if (tnext > bbextentt) | |
| tnext = bbextentt; | |
| else | |
| if (tnext < 8) | |
| tnext = 8; | |
| sstep = (snext - s) >> 3; | |
| tstep = (tnext - t) >> 3; | |
| } | |
| else | |
| { | |
| spancountminus1 = (float) (spancount - 1); | |
| sdivz += d_sdivzstepu * spancountminus1; | |
| tdivz += d_tdivzstepu * spancountminus1; | |
| zi += d_zistepu * spancountminus1; | |
| z = ((float) 0x10000) / zi; | |
| snext = ((int32_t) (sdivz * z)) + sadjust; | |
| if (snext > bbextents) | |
| snext = bbextents; | |
| else | |
| if (snext < 8) | |
| snext = 8; | |
| tnext = ((int32_t) (tdivz * z)) + tadjust; | |
| if (tnext > bbextentt) | |
| tnext = bbextentt; | |
| else | |
| if (tnext < 8) | |
| tnext = 8; | |
| if (spancount > 1) | |
| { | |
| sstep = (snext - s) / (spancount - 1); | |
| tstep = (tnext - t) / (spancount - 1); | |
| } | |
| } | |
| do | |
| { | |
| btemp = *((pbase + (s >> 16)) + ((t >> 16) * cachewidth)); | |
| if (btemp != 255) | |
| { | |
| if ((*pz) <= (izi >> 16)) | |
| { | |
| *pz = izi >> 16; | |
| *pdest = btemp; | |
| } | |
| } | |
| izi += izistep; | |
| pdest++; | |
| pz++; | |
| s += sstep; | |
| t += tstep; | |
| } | |
| while ((--spancount) > 0); | |
| s = snext; | |
| t = tnext; | |
| } | |
| while (count > 0); | |
| NextSpan: | |
| pspan++; | |
| } | |
| while (pspan->count != DS_SPAN_LIST_END); | |
| } | |
| static void D_SpriteScanLeftEdge(void) | |
| { | |
| int32_t i; | |
| int32_t v; | |
| int32_t itop; | |
| int32_t ibottom; | |
| int32_t lmaxindex; | |
| emitpoint_t *pvert; | |
| emitpoint_t *pnext; | |
| sspan_t *pspan; | |
| float du; | |
| float dv; | |
| float vtop; | |
| float vbottom; | |
| float slope; | |
| fixed16_t u; | |
| fixed16_t u_step; | |
| pspan = sprite_spans; | |
| i = minindex; | |
| if (i == 0) | |
| i = r_spritedesc.nump; | |
| lmaxindex = maxindex; | |
| if (lmaxindex == 0) | |
| lmaxindex = r_spritedesc.nump; | |
| vtop = ceil(r_spritedesc.pverts[i].v); | |
| do | |
| { | |
| pvert = &r_spritedesc.pverts[i]; | |
| pnext = pvert - 1; | |
| vbottom = ceil(pnext->v); | |
| if (vtop < vbottom) | |
| { | |
| du = pnext->u - pvert->u; | |
| dv = pnext->v - pvert->v; | |
| slope = du / dv; | |
| u_step = (int32_t) (slope * 0x10000); | |
| u = ((int32_t) ((pvert->u + (slope * (vtop - pvert->v))) * 0x10000)) + (0x10000 - 1); | |
| itop = (int32_t) vtop; | |
| ibottom = (int32_t) vbottom; | |
| for (v = itop; v < ibottom; v++) | |
| { | |
| pspan->u = u >> 16; | |
| pspan->v = v; | |
| u += u_step; | |
| pspan++; | |
| } | |
| } | |
| vtop = vbottom; | |
| i--; | |
| if (i == 0) | |
| i = r_spritedesc.nump; | |
| } | |
| while (i != lmaxindex); | |
| } | |
| static void D_SpriteScanRightEdge(void) | |
| { | |
| int32_t i; | |
| int32_t v; | |
| int32_t itop; | |
| int32_t ibottom; | |
| emitpoint_t *pvert; | |
| emitpoint_t *pnext; | |
| sspan_t *pspan; | |
| float du; | |
| float dv; | |
| float vtop; | |
| float vbottom; | |
| float slope; | |
| float uvert; | |
| float unext; | |
| float vvert; | |
| float vnext; | |
| fixed16_t u; | |
| fixed16_t u_step; | |
| pspan = sprite_spans; | |
| i = minindex; | |
| vvert = r_spritedesc.pverts[i].v; | |
| if (vvert < r_refdef.fvrecty_adj) | |
| vvert = r_refdef.fvrecty_adj; | |
| if (vvert > r_refdef.fvrectbottom_adj) | |
| vvert = r_refdef.fvrectbottom_adj; | |
| vtop = ceil(vvert); | |
| do | |
| { | |
| pvert = &r_spritedesc.pverts[i]; | |
| pnext = pvert + 1; | |
| vnext = pnext->v; | |
| if (vnext < r_refdef.fvrecty_adj) | |
| vnext = r_refdef.fvrecty_adj; | |
| if (vnext > r_refdef.fvrectbottom_adj) | |
| vnext = r_refdef.fvrectbottom_adj; | |
| vbottom = ceil(vnext); | |
| if (vtop < vbottom) | |
| { | |
| uvert = pvert->u; | |
| if (uvert < r_refdef.fvrectx_adj) | |
| uvert = r_refdef.fvrectx_adj; | |
| if (uvert > r_refdef.fvrectright_adj) | |
| uvert = r_refdef.fvrectright_adj; | |
| unext = pnext->u; | |
| if (unext < r_refdef.fvrectx_adj) | |
| unext = r_refdef.fvrectx_adj; | |
| if (unext > r_refdef.fvrectright_adj) | |
| unext = r_refdef.fvrectright_adj; | |
| du = unext - uvert; | |
| dv = vnext - vvert; | |
| slope = du / dv; | |
| u_step = (int32_t) (slope * 0x10000); | |
| u = ((int32_t) ((uvert + (slope * (vtop - vvert))) * 0x10000)) + (0x10000 - 1); | |
| itop = (int32_t) vtop; | |
| ibottom = (int32_t) vbottom; | |
| for (v = itop; v < ibottom; v++) | |
| { | |
| pspan->count = (u >> 16) - pspan->u; | |
| u += u_step; | |
| pspan++; | |
| } | |
| } | |
| vtop = vbottom; | |
| vvert = vnext; | |
| i++; | |
| if (i == r_spritedesc.nump) | |
| i = 0; | |
| } | |
| while (i != maxindex); | |
| pspan->count = DS_SPAN_LIST_END; | |
| } | |
| static void D_SpriteCalculateGradients(void) | |
| { | |
| vec3_t p_normal; | |
| vec3_t p_saxis; | |
| vec3_t p_taxis; | |
| vec3_t p_temp1; | |
| float distinv; | |
| TransformVector(r_spritedesc.vpn, p_normal); | |
| TransformVector(r_spritedesc.vright, p_saxis); | |
| TransformVector(r_spritedesc.vup, p_taxis); | |
| VectorInverse(p_taxis); | |
| distinv = 1.0 / (-DotProduct(modelorg, r_spritedesc.vpn)); | |
| d_sdivzstepu = p_saxis[0] * xscaleinv; | |
| d_tdivzstepu = p_taxis[0] * xscaleinv; | |
| d_sdivzstepv = (-p_saxis[1]) * yscaleinv; | |
| d_tdivzstepv = (-p_taxis[1]) * yscaleinv; | |
| d_zistepu = (p_normal[0] * xscaleinv) * distinv; | |
| d_zistepv = ((-p_normal[1]) * yscaleinv) * distinv; | |
| d_sdivzorigin = (p_saxis[2] - (xcenter * d_sdivzstepu)) - (ycenter * d_sdivzstepv); | |
| d_tdivzorigin = (p_taxis[2] - (xcenter * d_tdivzstepu)) - (ycenter * d_tdivzstepv); | |
| d_ziorigin = ((p_normal[2] * distinv) - (xcenter * d_zistepu)) - (ycenter * d_zistepv); | |
| TransformVector(modelorg, p_temp1); | |
| sadjust = ((fixed16_t) ((DotProduct(p_temp1, p_saxis) * 0x10000) + 0.5)) - ((-(cachewidth >> 1)) << 16); | |
| tadjust = ((fixed16_t) ((DotProduct(p_temp1, p_taxis) * 0x10000) + 0.5)) - ((-(sprite_height >> 1)) << 16); | |
| bbextents = (cachewidth << 16) - 1; | |
| bbextentt = (sprite_height << 16) - 1; | |
| } | |
| void D_DrawSprite(void) | |
| { | |
| int32_t i; | |
| int32_t nump; | |
| float ymin; | |
| float ymax; | |
| emitpoint_t *pverts; | |
| sspan_t spans[MAXHEIGHT + 1]; | |
| sprite_spans = spans; | |
| ymin = 999999.9; | |
| ymax = -999999.9; | |
| pverts = r_spritedesc.pverts; | |
| for (i = 0; i < r_spritedesc.nump; i++) | |
| { | |
| if (pverts->v < ymin) | |
| { | |
| ymin = pverts->v; | |
| minindex = i; | |
| } | |
| if (pverts->v > ymax) | |
| { | |
| ymax = pverts->v; | |
| maxindex = i; | |
| } | |
| pverts++; | |
| } | |
| ymin = ceil(ymin); | |
| ymax = ceil(ymax); | |
| if (ymin >= ymax) | |
| return; | |
| cachewidth = r_spritedesc.pspriteframe->width; | |
| sprite_height = r_spritedesc.pspriteframe->height; | |
| cacheblock = (uint8_t *) (&r_spritedesc.pspriteframe->pixels[0]); | |
| nump = r_spritedesc.nump; | |
| pverts = r_spritedesc.pverts; | |
| pverts[nump] = pverts[0]; | |
| D_SpriteCalculateGradients(); | |
| D_SpriteScanLeftEdge(); | |
| D_SpriteScanRightEdge(); | |
| D_SpriteDrawSpans(sprite_spans); | |
| } | |
| int32_t D_SurfaceCacheForRes(int32_t width, int32_t height) | |
| { | |
| int32_t size; | |
| int32_t pix; | |
| if (COM_CheckParm("-surfcachesize")) | |
| { | |
| size = ((int32_t) strtol(com_argv[COM_CheckParm("-surfcachesize") + 1], 0, 0)) * 1024; | |
| return size; | |
| } | |
| size = SURFCACHE_SIZE_AT_320X200; | |
| pix = width * height; | |
| if (pix > 64000) | |
| size += (pix - 64000) * 3; | |
| return size; | |
| } | |
| void D_CheckCacheGuard(void) | |
| { | |
| uint8_t *s; | |
| int32_t i; | |
| s = ((uint8_t *) sc_base) + sc_size; | |
| for (i = 0; i < GUARDSIZE; i++) | |
| if (s[i] != ((uint8_t) i)) | |
| Sys_Error("D_CheckCacheGuard: failed"); | |
| } | |
| void D_ClearCacheGuard(void) | |
| { | |
| uint8_t *s; | |
| int32_t i; | |
| s = ((uint8_t *) sc_base) + sc_size; | |
| for (i = 0; i < GUARDSIZE; i++) | |
| s[i] = (uint8_t) i; | |
| } | |
| void D_InitCaches(void *buffer, int32_t size) | |
| { | |
| if (!msg_suppress_1) | |
| Con_Printf("%ik surface cache\n", size / 1024); | |
| sc_size = size - GUARDSIZE; | |
| sc_base = (surfcache_t *) buffer; | |
| sc_rover = sc_base; | |
| sc_base->next = 0; | |
| sc_base->owner = 0; | |
| sc_base->size = sc_size; | |
| D_ClearCacheGuard(); | |
| } | |
| void D_FlushCaches(void) | |
| { | |
| surfcache_t *c; | |
| if (!sc_base) | |
| return; | |
| for (c = sc_base; c; c = c->next) | |
| { | |
| if (c->owner) | |
| *c->owner = 0; | |
| } | |
| sc_rover = sc_base; | |
| sc_base->next = 0; | |
| sc_base->owner = 0; | |
| sc_base->size = sc_size; | |
| } | |
| surfcache_t *D_SCAlloc(int32_t width, int32_t size) | |
| { | |
| surfcache_t *new; | |
| bool wrapped_this_time; | |
| if ((width < 0) || (width > 256)) | |
| Sys_Error("D_SCAlloc: bad cache width %d\n", width); | |
| if ((size <= 0) || (size > 0x10000)) | |
| Sys_Error("D_SCAlloc: bad cache size %d\n", size); | |
| size = (int32_t) (&((surfcache_t *) 0)->data[size]); | |
| size = (size + 3) & (~3); | |
| if (size > sc_size) | |
| Sys_Error("D_SCAlloc: %i > cache size", size); | |
| wrapped_this_time = 0; | |
| if ((!sc_rover) || ((((uint8_t *) sc_rover) - ((uint8_t *) sc_base)) > (sc_size - size))) | |
| { | |
| if (sc_rover) | |
| { | |
| wrapped_this_time = 1; | |
| } | |
| sc_rover = sc_base; | |
| } | |
| new = sc_rover; | |
| if (sc_rover->owner) | |
| *sc_rover->owner = 0; | |
| while (new->size < size) | |
| { | |
| sc_rover = sc_rover->next; | |
| if (!sc_rover) | |
| Sys_Error("D_SCAlloc: hit the end of memory"); | |
| if (sc_rover->owner) | |
| *sc_rover->owner = 0; | |
| new->size += sc_rover->size; | |
| new->next = sc_rover->next; | |
| } | |
| if ((new->size - size) > 256) | |
| { | |
| sc_rover = (surfcache_t *) (((uint8_t *) new) + size); | |
| sc_rover->size = new->size - size; | |
| sc_rover->next = new->next; | |
| sc_rover->width = 0; | |
| sc_rover->owner = 0; | |
| new->next = sc_rover; | |
| new->size = size; | |
| } | |
| else | |
| sc_rover = new->next; | |
| new->width = width; | |
| if (width > 0) | |
| new->height = ((size - (sizeof(*new))) + (sizeof(new->data))) / width; | |
| new->owner = 0; | |
| if (d_roverwrapped) | |
| { | |
| if (wrapped_this_time || (sc_rover >= d_initial_rover)) | |
| r_cache_thrash = 1; | |
| } | |
| else | |
| if (wrapped_this_time) | |
| { | |
| d_roverwrapped = 1; | |
| } | |
| D_CheckCacheGuard(); | |
| return new; | |
| } | |
| void D_SCDump(void) | |
| { | |
| surfcache_t *test; | |
| for (test = sc_base; test; test = test->next) | |
| { | |
| if (test == sc_rover) | |
| Sys_Printf("ROVER:\n"); | |
| printf("%p : %i bytes %i width\n", test, test->size, test->width); | |
| } | |
| } | |
| int32_t MaskForNum(int32_t num) | |
| { | |
| if (num == 128) | |
| return 127; | |
| if (num == 64) | |
| return 63; | |
| if (num == 32) | |
| return 31; | |
| if (num == 16) | |
| return 15; | |
| return 255; | |
| } | |
| int32_t D_log2(int32_t num) | |
| { | |
| int32_t c; | |
| c = 0; | |
| while (num >>= 1) | |
| c++; | |
| return c; | |
| } | |
| surfcache_t *D_CacheSurface(msurface_t *surface, int32_t miplevel) | |
| { | |
| surfcache_t *cache; | |
| r_drawsurf.texture = R_TextureAnimation(surface->texinfo->texture); | |
| r_drawsurf.lightadj[0] = d_lightstylevalue[surface->styles[0]]; | |
| r_drawsurf.lightadj[1] = d_lightstylevalue[surface->styles[1]]; | |
| r_drawsurf.lightadj[2] = d_lightstylevalue[surface->styles[2]]; | |
| r_drawsurf.lightadj[3] = d_lightstylevalue[surface->styles[3]]; | |
| cache = surface->cachespots[miplevel]; | |
| if (((((((cache && (!cache->dlight)) && (surface->dlightframe != r_framecount)) && (cache->texture == r_drawsurf.texture)) && (cache->lightadj[0] == r_drawsurf.lightadj[0])) && (cache->lightadj[1] == r_drawsurf.lightadj[1])) && (cache->lightadj[2] == r_drawsurf.lightadj[2])) && (cache->lightadj[3] == r_drawsurf.lightadj[3])) | |
| return cache; | |
| surfscale = 1.0 / (1 << miplevel); | |
| r_drawsurf.surfmip = miplevel; | |
| r_drawsurf.surfwidth = surface->extents[0] >> miplevel; | |
| r_drawsurf.rowbytes = r_drawsurf.surfwidth; | |
| r_drawsurf.surfheight = surface->extents[1] >> miplevel; | |
| if (!cache) | |
| { | |
| cache = D_SCAlloc(r_drawsurf.surfwidth, r_drawsurf.surfwidth * r_drawsurf.surfheight); | |
| surface->cachespots[miplevel] = cache; | |
| cache->owner = &surface->cachespots[miplevel]; | |
| cache->mipscale = surfscale; | |
| } | |
| if (surface->dlightframe == r_framecount) | |
| cache->dlight = 1; | |
| else | |
| cache->dlight = 0; | |
| r_drawsurf.surfdat = (pixel_t *) cache->data; | |
| cache->texture = r_drawsurf.texture; | |
| cache->lightadj[0] = r_drawsurf.lightadj[0]; | |
| cache->lightadj[1] = r_drawsurf.lightadj[1]; | |
| cache->lightadj[2] = r_drawsurf.lightadj[2]; | |
| cache->lightadj[3] = r_drawsurf.lightadj[3]; | |
| r_drawsurf.surf = surface; | |
| c_surf++; | |
| R_DrawSurface(); | |
| return surface->cachespots[miplevel]; | |
| } | |
| void D_DrawZPoint(void) | |
| { | |
| uint8_t *pdest; | |
| int16_t *pz; | |
| int32_t izi; | |
| pz = (d_pzbuffer + (d_zwidth * r_zpointdesc.v)) + r_zpointdesc.u; | |
| pdest = (d_viewbuffer + d_scantable[r_zpointdesc.v]) + r_zpointdesc.u; | |
| izi = (int32_t) (r_zpointdesc.zi * 0x8000); | |
| if ((*pz) <= izi) | |
| { | |
| *pz = izi; | |
| *pdest = r_zpointdesc.color; | |
| } | |
| } | |
| qpic_t *Draw_PicFromWad(char *name) | |
| { | |
| return W_GetLumpName(name); | |
| } | |
| qpic_t *Draw_CachePic(char *path) | |
| { | |
| cachepic_t *pic; | |
| int32_t i; | |
| qpic_t *dat; | |
| for (pic = menu_cachepics, i = 0; i < menu_numcachepics; pic++, i++) | |
| if (!strcmp(path, pic->name)) | |
| break; | |
| if (i == menu_numcachepics) | |
| { | |
| if (menu_numcachepics == MAX_CACHED_PICS) | |
| Sys_Error("menu_numcachepics == MAX_CACHED_PICS"); | |
| menu_numcachepics++; | |
| strcpy(pic->name, path); | |
| } | |
| dat = Cache_Check(&pic->cache); | |
| if (dat) | |
| return dat; | |
| COM_LoadCacheFile(path, &pic->cache); | |
| dat = (qpic_t *) pic->cache.data; | |
| if (!dat) | |
| { | |
| Sys_Error("Draw_CachePic: failed to load %s", path); | |
| } | |
| SwapPic(dat); | |
| return dat; | |
| } | |
| void Draw_Init(void) | |
| { | |
| int32_t i; | |
| draw_chars = W_GetLumpName("conchars"); | |
| draw_disc = W_GetLumpName("disc"); | |
| draw_backtile = W_GetLumpName("backtile"); | |
| r_rectdesc.width = draw_backtile->width; | |
| r_rectdesc.height = draw_backtile->height; | |
| r_rectdesc.ptexbytes = draw_backtile->data; | |
| r_rectdesc.rowbytes = draw_backtile->width; | |
| } | |
| void Draw_Character(int32_t x, int32_t y, int32_t num) | |
| { | |
| uint8_t *dest; | |
| uint8_t *source; | |
| uint16_t *pusdest; | |
| int32_t drawline; | |
| int32_t row; | |
| int32_t col; | |
| num &= 255; | |
| if (y <= (-8)) | |
| return; | |
| row = num >> 4; | |
| col = num & 15; | |
| source = (draw_chars + (row << 10)) + (col << 3); | |
| if (y < 0) | |
| { | |
| drawline = 8 + y; | |
| source -= 128 * y; | |
| y = 0; | |
| } | |
| else | |
| drawline = 8; | |
| if (r_pixbytes == 1) | |
| { | |
| dest = (vid.conbuffer + (y * vid.conrowbytes)) + x; | |
| while (drawline--) | |
| { | |
| if (source[0]) | |
| dest[0] = source[0]; | |
| if (source[1]) | |
| dest[1] = source[1]; | |
| if (source[2]) | |
| dest[2] = source[2]; | |
| if (source[3]) | |
| dest[3] = source[3]; | |
| if (source[4]) | |
| dest[4] = source[4]; | |
| if (source[5]) | |
| dest[5] = source[5]; | |
| if (source[6]) | |
| dest[6] = source[6]; | |
| if (source[7]) | |
| dest[7] = source[7]; | |
| source += 128; | |
| dest += vid.conrowbytes; | |
| } | |
| } | |
| else | |
| { | |
| pusdest = (uint16_t *) ((((uint8_t *) vid.conbuffer) + (y * vid.conrowbytes)) + (x << 1)); | |
| while (drawline--) | |
| { | |
| if (source[0]) | |
| pusdest[0] = d_8to16table[source[0]]; | |
| if (source[1]) | |
| pusdest[1] = d_8to16table[source[1]]; | |
| if (source[2]) | |
| pusdest[2] = d_8to16table[source[2]]; | |
| if (source[3]) | |
| pusdest[3] = d_8to16table[source[3]]; | |
| if (source[4]) | |
| pusdest[4] = d_8to16table[source[4]]; | |
| if (source[5]) | |
| pusdest[5] = d_8to16table[source[5]]; | |
| if (source[6]) | |
| pusdest[6] = d_8to16table[source[6]]; | |
| if (source[7]) | |
| pusdest[7] = d_8to16table[source[7]]; | |
| source += 128; | |
| pusdest += vid.conrowbytes >> 1; | |
| } | |
| } | |
| } | |
| void Draw_String(int32_t x, int32_t y, char *str) | |
| { | |
| while (*str) | |
| { | |
| Draw_Character(x, y, *str); | |
| str++; | |
| x += 8; | |
| } | |
| } | |
| void Draw_DebugChar(char num) | |
| { | |
| uint8_t *dest; | |
| uint8_t *source; | |
| int32_t drawline; | |
| extern uint8_t *draw_chars; | |
| int32_t row; | |
| int32_t col; | |
| if (!vid.direct) | |
| return; | |
| drawline = 8; | |
| row = num >> 4; | |
| col = num & 15; | |
| source = (draw_chars + (row << 10)) + (col << 3); | |
| dest = vid.direct + 312; | |
| while (drawline--) | |
| { | |
| dest[0] = source[0]; | |
| dest[1] = source[1]; | |
| dest[2] = source[2]; | |
| dest[3] = source[3]; | |
| dest[4] = source[4]; | |
| dest[5] = source[5]; | |
| dest[6] = source[6]; | |
| dest[7] = source[7]; | |
| source += 128; | |
| dest += 320; | |
| } | |
| } | |
| void Draw_Pic(int32_t x, int32_t y, qpic_t *pic) | |
| { | |
| uint8_t *dest; | |
| uint8_t *source; | |
| uint16_t *pusdest; | |
| int32_t v; | |
| int32_t u; | |
| if ((((x < 0) || ((x + pic->width) > vid.width)) || (y < 0)) || ((y + pic->height) > vid.height)) | |
| { | |
| Sys_Error("Draw_Pic: bad coordinates"); | |
| } | |
| source = pic->data; | |
| if (r_pixbytes == 1) | |
| { | |
| dest = (vid.buffer + (y * vid.rowbytes)) + x; | |
| for (v = 0; v < pic->height; v++) | |
| { | |
| memcpy(dest, source, pic->width); | |
| dest += vid.rowbytes; | |
| source += pic->width; | |
| } | |
| } | |
| else | |
| { | |
| pusdest = (((uint16_t *) vid.buffer) + (y * (vid.rowbytes >> 1))) + x; | |
| for (v = 0; v < pic->height; v++) | |
| { | |
| for (u = 0; u < pic->width; u++) | |
| { | |
| pusdest[u] = d_8to16table[source[u]]; | |
| } | |
| pusdest += vid.rowbytes >> 1; | |
| source += pic->width; | |
| } | |
| } | |
| } | |
| void Draw_TransPic(int32_t x, int32_t y, qpic_t *pic) | |
| { | |
| uint8_t *dest; | |
| uint8_t *source; | |
| uint8_t tbyte; | |
| uint16_t *pusdest; | |
| int32_t v; | |
| int32_t u; | |
| if ((((x < 0) || (((uint32_t) (x + pic->width)) > vid.width)) || (y < 0)) || (((uint32_t) (y + pic->height)) > vid.height)) | |
| { | |
| Sys_Error("Draw_TransPic: bad coordinates"); | |
| } | |
| source = pic->data; | |
| if (r_pixbytes == 1) | |
| { | |
| dest = (vid.buffer + (y * vid.rowbytes)) + x; | |
| if (pic->width & 7) | |
| { | |
| for (v = 0; v < pic->height; v++) | |
| { | |
| for (u = 0; u < pic->width; u++) | |
| if ((tbyte = source[u]) != TRANSPARENT_COLOR) | |
| dest[u] = tbyte; | |
| dest += vid.rowbytes; | |
| source += pic->width; | |
| } | |
| } | |
| else | |
| { | |
| for (v = 0; v < pic->height; v++) | |
| { | |
| for (u = 0; u < pic->width; u += 8) | |
| { | |
| if ((tbyte = source[u]) != TRANSPARENT_COLOR) | |
| dest[u] = tbyte; | |
| if ((tbyte = source[u + 1]) != TRANSPARENT_COLOR) | |
| dest[u + 1] = tbyte; | |
| if ((tbyte = source[u + 2]) != TRANSPARENT_COLOR) | |
| dest[u + 2] = tbyte; | |
| if ((tbyte = source[u + 3]) != TRANSPARENT_COLOR) | |
| dest[u + 3] = tbyte; | |
| if ((tbyte = source[u + 4]) != TRANSPARENT_COLOR) | |
| dest[u + 4] = tbyte; | |
| if ((tbyte = source[u + 5]) != TRANSPARENT_COLOR) | |
| dest[u + 5] = tbyte; | |
| if ((tbyte = source[u + 6]) != TRANSPARENT_COLOR) | |
| dest[u + 6] = tbyte; | |
| if ((tbyte = source[u + 7]) != TRANSPARENT_COLOR) | |
| dest[u + 7] = tbyte; | |
| } | |
| dest += vid.rowbytes; | |
| source += pic->width; | |
| } | |
| } | |
| } | |
| else | |
| { | |
| pusdest = (((uint16_t *) vid.buffer) + (y * (vid.rowbytes >> 1))) + x; | |
| for (v = 0; v < pic->height; v++) | |
| { | |
| for (u = 0; u < pic->width; u++) | |
| { | |
| tbyte = source[u]; | |
| if (tbyte != TRANSPARENT_COLOR) | |
| { | |
| pusdest[u] = d_8to16table[tbyte]; | |
| } | |
| } | |
| pusdest += vid.rowbytes >> 1; | |
| source += pic->width; | |
| } | |
| } | |
| } | |
| void Draw_TransPicTranslate(int32_t x, int32_t y, qpic_t *pic, uint8_t *translation) | |
| { | |
| uint8_t *dest; | |
| uint8_t *source; | |
| uint8_t tbyte; | |
| uint16_t *pusdest; | |
| int32_t v; | |
| int32_t u; | |
| if ((((x < 0) || (((uint32_t) (x + pic->width)) > vid.width)) || (y < 0)) || (((uint32_t) (y + pic->height)) > vid.height)) | |
| { | |
| Sys_Error("Draw_TransPic: bad coordinates"); | |
| } | |
| source = pic->data; | |
| if (r_pixbytes == 1) | |
| { | |
| dest = (vid.buffer + (y * vid.rowbytes)) + x; | |
| if (pic->width & 7) | |
| { | |
| for (v = 0; v < pic->height; v++) | |
| { | |
| for (u = 0; u < pic->width; u++) | |
| if ((tbyte = source[u]) != TRANSPARENT_COLOR) | |
| dest[u] = translation[tbyte]; | |
| dest += vid.rowbytes; | |
| source += pic->width; | |
| } | |
| } | |
| else | |
| { | |
| for (v = 0; v < pic->height; v++) | |
| { | |
| for (u = 0; u < pic->width; u += 8) | |
| { | |
| if ((tbyte = source[u]) != TRANSPARENT_COLOR) | |
| dest[u] = translation[tbyte]; | |
| if ((tbyte = source[u + 1]) != TRANSPARENT_COLOR) | |
| dest[u + 1] = translation[tbyte]; | |
| if ((tbyte = source[u + 2]) != TRANSPARENT_COLOR) | |
| dest[u + 2] = translation[tbyte]; | |
| if ((tbyte = source[u + 3]) != TRANSPARENT_COLOR) | |
| dest[u + 3] = translation[tbyte]; | |
| if ((tbyte = source[u + 4]) != TRANSPARENT_COLOR) | |
| dest[u + 4] = translation[tbyte]; | |
| if ((tbyte = source[u + 5]) != TRANSPARENT_COLOR) | |
| dest[u + 5] = translation[tbyte]; | |
| if ((tbyte = source[u + 6]) != TRANSPARENT_COLOR) | |
| dest[u + 6] = translation[tbyte]; | |
| if ((tbyte = source[u + 7]) != TRANSPARENT_COLOR) | |
| dest[u + 7] = translation[tbyte]; | |
| } | |
| dest += vid.rowbytes; | |
| source += pic->width; | |
| } | |
| } | |
| } | |
| else | |
| { | |
| pusdest = (((uint16_t *) vid.buffer) + (y * (vid.rowbytes >> 1))) + x; | |
| for (v = 0; v < pic->height; v++) | |
| { | |
| for (u = 0; u < pic->width; u++) | |
| { | |
| tbyte = source[u]; | |
| if (tbyte != TRANSPARENT_COLOR) | |
| { | |
| pusdest[u] = d_8to16table[tbyte]; | |
| } | |
| } | |
| pusdest += vid.rowbytes >> 1; | |
| source += pic->width; | |
| } | |
| } | |
| } | |
| void Draw_CharToConback(int32_t num, uint8_t *dest) | |
| { | |
| int32_t row; | |
| int32_t col; | |
| uint8_t *source; | |
| int32_t drawline; | |
| int32_t x; | |
| row = num >> 4; | |
| col = num & 15; | |
| source = (draw_chars + (row << 10)) + (col << 3); | |
| drawline = 8; | |
| while (drawline--) | |
| { | |
| for (x = 0; x < 8; x++) | |
| if (source[x]) | |
| dest[x] = 0x60 + source[x]; | |
| source += 128; | |
| dest += 320; | |
| } | |
| } | |
| void Draw_ConsoleBackground(int32_t lines) | |
| { | |
| int32_t x; | |
| int32_t y; | |
| int32_t v; | |
| uint8_t *src; | |
| uint8_t *dest; | |
| uint16_t *pusdest; | |
| int32_t f; | |
| int32_t fstep; | |
| qpic_t *conback; | |
| char ver[100]; | |
| conback = Draw_CachePic("gfx/conback.lmp"); | |
| dest = ((conback->data + 320) - 43) + (320 * 186); | |
| sprintf(ver, "%4.2f", VERSION); | |
| for (x = 0; x < strlen(ver); x++) | |
| Draw_CharToConback(ver[x], dest + (x << 3)); | |
| if (r_pixbytes == 1) | |
| { | |
| dest = vid.conbuffer; | |
| for (y = 0; y < lines; y++, dest += vid.conrowbytes) | |
| { | |
| v = (((vid.conheight - lines) + y) * 200) / vid.conheight; | |
| src = conback->data + (v * 320); | |
| if (vid.conwidth == 320) | |
| memcpy(dest, src, vid.conwidth); | |
| else | |
| { | |
| f = 0; | |
| fstep = (320 * 0x10000) / vid.conwidth; | |
| for (x = 0; x < vid.conwidth; x += 4) | |
| { | |
| dest[x] = src[f >> 16]; | |
| f += fstep; | |
| dest[x + 1] = src[f >> 16]; | |
| f += fstep; | |
| dest[x + 2] = src[f >> 16]; | |
| f += fstep; | |
| dest[x + 3] = src[f >> 16]; | |
| f += fstep; | |
| } | |
| } | |
| } | |
| } | |
| else | |
| { | |
| pusdest = (uint16_t *) vid.conbuffer; | |
| for (y = 0; y < lines; y++, pusdest += vid.conrowbytes >> 1) | |
| { | |
| v = (((vid.conheight - lines) + y) * 200) / vid.conheight; | |
| src = conback->data + (v * 320); | |
| f = 0; | |
| fstep = (320 * 0x10000) / vid.conwidth; | |
| for (x = 0; x < vid.conwidth; x += 4) | |
| { | |
| pusdest[x] = d_8to16table[src[f >> 16]]; | |
| f += fstep; | |
| pusdest[x + 1] = d_8to16table[src[f >> 16]]; | |
| f += fstep; | |
| pusdest[x + 2] = d_8to16table[src[f >> 16]]; | |
| f += fstep; | |
| pusdest[x + 3] = d_8to16table[src[f >> 16]]; | |
| f += fstep; | |
| } | |
| } | |
| } | |
| } | |
| void R_DrawRect8(vrect_t *prect, int32_t rowbytes, uint8_t *psrc, int32_t transparent) | |
| { | |
| uint8_t t; | |
| int32_t i; | |
| int32_t j; | |
| int32_t srcdelta; | |
| int32_t destdelta; | |
| uint8_t *pdest; | |
| pdest = (vid.buffer + (prect->y * vid.rowbytes)) + prect->x; | |
| srcdelta = rowbytes - prect->width; | |
| destdelta = vid.rowbytes - prect->width; | |
| if (transparent) | |
| { | |
| for (i = 0; i < prect->height; i++) | |
| { | |
| for (j = 0; j < prect->width; j++) | |
| { | |
| t = *psrc; | |
| if (t != TRANSPARENT_COLOR) | |
| { | |
| *pdest = t; | |
| } | |
| psrc++; | |
| pdest++; | |
| } | |
| psrc += srcdelta; | |
| pdest += destdelta; | |
| } | |
| } | |
| else | |
| { | |
| for (i = 0; i < prect->height; i++) | |
| { | |
| memcpy(pdest, psrc, prect->width); | |
| psrc += rowbytes; | |
| pdest += vid.rowbytes; | |
| } | |
| } | |
| } | |
| void R_DrawRect16(vrect_t *prect, int32_t rowbytes, uint8_t *psrc, int32_t transparent) | |
| { | |
| uint8_t t; | |
| int32_t i; | |
| int32_t j; | |
| int32_t srcdelta; | |
| int32_t destdelta; | |
| uint16_t *pdest; | |
| pdest = (((uint16_t *) vid.buffer) + (prect->y * (vid.rowbytes >> 1))) + prect->x; | |
| srcdelta = rowbytes - prect->width; | |
| destdelta = (vid.rowbytes >> 1) - prect->width; | |
| if (transparent) | |
| { | |
| for (i = 0; i < prect->height; i++) | |
| { | |
| for (j = 0; j < prect->width; j++) | |
| { | |
| t = *psrc; | |
| if (t != TRANSPARENT_COLOR) | |
| { | |
| *pdest = d_8to16table[t]; | |
| } | |
| psrc++; | |
| pdest++; | |
| } | |
| psrc += srcdelta; | |
| pdest += destdelta; | |
| } | |
| } | |
| else | |
| { | |
| for (i = 0; i < prect->height; i++) | |
| { | |
| for (j = 0; j < prect->width; j++) | |
| { | |
| *pdest = d_8to16table[*psrc]; | |
| psrc++; | |
| pdest++; | |
| } | |
| psrc += srcdelta; | |
| pdest += destdelta; | |
| } | |
| } | |
| } | |
| void Draw_TileClear(int32_t x, int32_t y, int32_t w, int32_t h) | |
| { | |
| int32_t width; | |
| int32_t height; | |
| int32_t tileoffsetx; | |
| int32_t tileoffsety; | |
| uint8_t *psrc; | |
| vrect_t vr; | |
| r_rectdesc.rect.x = x; | |
| r_rectdesc.rect.y = y; | |
| r_rectdesc.rect.width = w; | |
| r_rectdesc.rect.height = h; | |
| vr.y = r_rectdesc.rect.y; | |
| height = r_rectdesc.rect.height; | |
| tileoffsety = vr.y % r_rectdesc.height; | |
| while (height > 0) | |
| { | |
| vr.x = r_rectdesc.rect.x; | |
| width = r_rectdesc.rect.width; | |
| if (tileoffsety != 0) | |
| vr.height = r_rectdesc.height - tileoffsety; | |
| else | |
| vr.height = r_rectdesc.height; | |
| if (vr.height > height) | |
| vr.height = height; | |
| tileoffsetx = vr.x % r_rectdesc.width; | |
| while (width > 0) | |
| { | |
| if (tileoffsetx != 0) | |
| vr.width = r_rectdesc.width - tileoffsetx; | |
| else | |
| vr.width = r_rectdesc.width; | |
| if (vr.width > width) | |
| vr.width = width; | |
| psrc = (r_rectdesc.ptexbytes + (tileoffsety * r_rectdesc.rowbytes)) + tileoffsetx; | |
| if (r_pixbytes == 1) | |
| { | |
| R_DrawRect8(&vr, r_rectdesc.rowbytes, psrc, 0); | |
| } | |
| else | |
| { | |
| R_DrawRect16(&vr, r_rectdesc.rowbytes, psrc, 0); | |
| } | |
| vr.x += vr.width; | |
| width -= vr.width; | |
| tileoffsetx = 0; | |
| } | |
| vr.y += vr.height; | |
| height -= vr.height; | |
| tileoffsety = 0; | |
| } | |
| } | |
| void Draw_Fill(int32_t x, int32_t y, int32_t w, int32_t h, int32_t c) | |
| { | |
| uint8_t *dest; | |
| uint16_t *pusdest; | |
| uint32_t uc; | |
| int32_t u; | |
| int32_t v; | |
| if (r_pixbytes == 1) | |
| { | |
| dest = (vid.buffer + (y * vid.rowbytes)) + x; | |
| for (v = 0; v < h; v++, dest += vid.rowbytes) | |
| for (u = 0; u < w; u++) | |
| dest[u] = c; | |
| } | |
| else | |
| { | |
| uc = d_8to16table[c]; | |
| pusdest = (((uint16_t *) vid.buffer) + (y * (vid.rowbytes >> 1))) + x; | |
| for (v = 0; v < h; v++, pusdest += vid.rowbytes >> 1) | |
| for (u = 0; u < w; u++) | |
| pusdest[u] = uc; | |
| } | |
| } | |
| void Draw_FadeScreen(void) | |
| { | |
| int32_t x; | |
| int32_t y; | |
| uint8_t *pbuf; | |
| VID_UnlockBuffer(); | |
| S_ExtraUpdate(); | |
| VID_LockBuffer(); | |
| for (y = 0; y < vid.height; y++) | |
| { | |
| int32_t t; | |
| pbuf = (uint8_t *) (vid.buffer + (vid.rowbytes * y)); | |
| t = (y & 1) << 1; | |
| for (x = 0; x < vid.width; x++) | |
| { | |
| if ((x & 3) != t) | |
| pbuf[x] = 0; | |
| } | |
| } | |
| VID_UnlockBuffer(); | |
| S_ExtraUpdate(); | |
| VID_LockBuffer(); | |
| } | |
| void Draw_BeginDisc(void) | |
| { | |
| } | |
| void Draw_EndDisc(void) | |
| { | |
| } | |
| void Host_EndGame(char *message, ...) | |
| { | |
| va_list argptr; | |
| char string[1024]; | |
| va_start(argptr, message); | |
| vsprintf(string, message, argptr); | |
| va_end(argptr); | |
| Con_DPrintf("Host_EndGame: %s\n", string); | |
| if (sv.active) | |
| Host_ShutdownServer(0); | |
| if (cls.state == ca_dedicated) | |
| Sys_Error("Host_EndGame: %s\n", string); | |
| if (cls.demonum != (-1)) | |
| CL_NextDemo(); | |
| else | |
| CL_Disconnect(); | |
| longjmp(host_abortserver, 1); | |
| } | |
| void Host_Error(char *error, ...) | |
| { | |
| va_list argptr; | |
| char string[1024]; | |
| static bool inerror = 0; | |
| if (inerror) | |
| Sys_Error("Host_Error: recursively entered"); | |
| inerror = 1; | |
| SCR_EndLoadingPlaque(); | |
| va_start(argptr, error); | |
| vsprintf(string, error, argptr); | |
| va_end(argptr); | |
| Con_Printf("Host_Error: %s\n", string); | |
| if (sv.active) | |
| Host_ShutdownServer(0); | |
| if (cls.state == ca_dedicated) | |
| Sys_Error("Host_Error: %s\n", string); | |
| CL_Disconnect(); | |
| cls.demonum = -1; | |
| inerror = 0; | |
| longjmp(host_abortserver, 1); | |
| } | |
| void Host_FindMaxClients(void) | |
| { | |
| int32_t i; | |
| svs.maxclients = 1; | |
| i = COM_CheckParm("-dedicated"); | |
| if (i) | |
| { | |
| cls.state = ca_dedicated; | |
| if (i != (com_argc - 1)) | |
| { | |
| svs.maxclients = (int32_t) strtol(com_argv[i + 1], 0, 0); | |
| } | |
| else | |
| svs.maxclients = 8; | |
| } | |
| else | |
| cls.state = ca_disconnected; | |
| i = COM_CheckParm("-listen"); | |
| if (i) | |
| { | |
| if (cls.state == ca_dedicated) | |
| Sys_Error("Only one of -dedicated or -listen can be specified"); | |
| if (i != (com_argc - 1)) | |
| svs.maxclients = (int32_t) strtol(com_argv[i + 1], 0, 0); | |
| else | |
| svs.maxclients = 8; | |
| } | |
| if (svs.maxclients < 1) | |
| svs.maxclients = 8; | |
| else | |
| if (svs.maxclients > MAX_SCOREBOARD) | |
| svs.maxclients = MAX_SCOREBOARD; | |
| svs.maxclientslimit = svs.maxclients; | |
| if (svs.maxclientslimit < 4) | |
| svs.maxclientslimit = 4; | |
| svs.clients = Hunk_AllocName(svs.maxclientslimit * (sizeof(client_t)), "clients"); | |
| if (svs.maxclients > 1) | |
| Cvar_SetValue("deathmatch", 1.0); | |
| else | |
| Cvar_SetValue("deathmatch", 0.0); | |
| } | |
| void Host_InitLocal(void) | |
| { | |
| Host_InitCommands(); | |
| Cvar_RegisterVariable(&host_framerate); | |
| Cvar_RegisterVariable(&host_speeds); | |
| Cvar_RegisterVariable(&sys_ticrate); | |
| Cvar_RegisterVariable(&serverprofile); | |
| Cvar_RegisterVariable(&fraglimit); | |
| Cvar_RegisterVariable(&timelimit); | |
| Cvar_RegisterVariable(&teamplay); | |
| Cvar_RegisterVariable(&samelevel); | |
| Cvar_RegisterVariable(&noexit); | |
| Cvar_RegisterVariable(&skill); | |
| Cvar_RegisterVariable(&developer); | |
| Cvar_RegisterVariable(&deathmatch); | |
| Cvar_RegisterVariable(&coop); | |
| Cvar_RegisterVariable(&pausable); | |
| Cvar_RegisterVariable(&temp1); | |
| Host_FindMaxClients(); | |
| host_time = 1.0; | |
| } | |
| void Host_WriteConfiguration(void) | |
| { | |
| FILE *f; | |
| if (host_initialized & (!isDedicated)) | |
| { | |
| f = fopen(va("%s/config.cfg", com_gamedir), "w"); | |
| if (!f) | |
| { | |
| Con_Printf("Couldn't write config.cfg.\n"); | |
| return; | |
| } | |
| Key_WriteBindings(f); | |
| Cvar_WriteVariables(f); | |
| fclose(f); | |
| } | |
| } | |
| void SV_ClientPrintf(char *fmt, ...) | |
| { | |
| va_list argptr; | |
| char string[1024]; | |
| va_start(argptr, fmt); | |
| vsprintf(string, fmt, argptr); | |
| va_end(argptr); | |
| MSG_WriteByte(&host_client->message, svc_print); | |
| MSG_WriteString(&host_client->message, string); | |
| } | |
| void SV_BroadcastPrintf(char *fmt, ...) | |
| { | |
| va_list argptr; | |
| char string[1024]; | |
| int32_t i; | |
| va_start(argptr, fmt); | |
| vsprintf(string, fmt, argptr); | |
| va_end(argptr); | |
| for (i = 0; i < svs.maxclients; i++) | |
| if (svs.clients[i].active && svs.clients[i].spawned) | |
| { | |
| MSG_WriteByte(&svs.clients[i].message, svc_print); | |
| MSG_WriteString(&svs.clients[i].message, string); | |
| } | |
| } | |
| void Host_ClientCommands(char *fmt, ...) | |
| { | |
| va_list argptr; | |
| char string[1024]; | |
| va_start(argptr, fmt); | |
| vsprintf(string, fmt, argptr); | |
| va_end(argptr); | |
| MSG_WriteByte(&host_client->message, svc_stufftext); | |
| MSG_WriteString(&host_client->message, string); | |
| } | |
| void SV_DropClient(bool crash) | |
| { | |
| int32_t saveSelf; | |
| int32_t i; | |
| client_t *client; | |
| if (!crash) | |
| { | |
| if (NET_CanSendMessage(host_client->netconnection)) | |
| { | |
| MSG_WriteByte(&host_client->message, svc_disconnect); | |
| NET_SendMessage(host_client->netconnection, &host_client->message); | |
| } | |
| if (host_client->edict && host_client->spawned) | |
| { | |
| saveSelf = pr_global_struct->self; | |
| pr_global_struct->self = EDICT_TO_PROG(host_client->edict); | |
| PR_ExecuteProgram(pr_global_struct->ClientDisconnect); | |
| pr_global_struct->self = saveSelf; | |
| } | |
| Sys_Printf("Client %s removed\n", host_client->name); | |
| } | |
| NET_Close(host_client->netconnection); | |
| host_client->netconnection = 0; | |
| host_client->active = 0; | |
| host_client->name[0] = 0; | |
| host_client->old_frags = -999999; | |
| net_activeconnections--; | |
| for (i = 0, client = svs.clients; i < svs.maxclients; i++, client++) | |
| { | |
| if (!client->active) | |
| continue; | |
| MSG_WriteByte(&client->message, svc_updatename); | |
| MSG_WriteByte(&client->message, host_client - svs.clients); | |
| MSG_WriteString(&client->message, ""); | |
| MSG_WriteByte(&client->message, svc_updatefrags); | |
| MSG_WriteByte(&client->message, host_client - svs.clients); | |
| MSG_WriteShort(&client->message, 0); | |
| MSG_WriteByte(&client->message, svc_updatecolors); | |
| MSG_WriteByte(&client->message, host_client - svs.clients); | |
| MSG_WriteByte(&client->message, 0); | |
| } | |
| } | |
| void Host_ShutdownServer(bool crash) | |
| { | |
| int32_t i; | |
| int32_t count; | |
| sizebuf_t buf; | |
| char message[4]; | |
| double start; | |
| if (!sv.active) | |
| return; | |
| sv.active = 0; | |
| if (cls.state == ca_connected) | |
| CL_Disconnect(); | |
| start = Sys_FloatTime(); | |
| do | |
| { | |
| count = 0; | |
| for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++) | |
| { | |
| if (host_client->active && host_client->message.cursize) | |
| { | |
| if (NET_CanSendMessage(host_client->netconnection)) | |
| { | |
| NET_SendMessage(host_client->netconnection, &host_client->message); | |
| SZ_Clear(&host_client->message); | |
| } | |
| else | |
| { | |
| NET_GetMessage(host_client->netconnection); | |
| count++; | |
| } | |
| } | |
| } | |
| if ((Sys_FloatTime() - start) > 3.0) | |
| break; | |
| } | |
| while (count); | |
| buf.data = message; | |
| buf.maxsize = 4; | |
| buf.cursize = 0; | |
| MSG_WriteByte(&buf, svc_disconnect); | |
| count = NET_SendToAll(&buf, 5); | |
| if (count) | |
| Con_Printf("Host_ShutdownServer: NET_SendToAll failed for %u clients\n", count); | |
| for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++) | |
| if (host_client->active) | |
| SV_DropClient(crash); | |
| memset(&sv, 0, sizeof(sv)); | |
| memset(svs.clients, 0, svs.maxclientslimit * (sizeof(client_t))); | |
| } | |
| void Host_ClearMemory(void) | |
| { | |
| Con_DPrintf("Clearing memory\n"); | |
| D_FlushCaches(); | |
| Mod_ClearAll(); | |
| if (host_hunklevel) | |
| Hunk_FreeToLowMark(host_hunklevel); | |
| cls.signon = 0; | |
| memset(&sv, 0, sizeof(sv)); | |
| memset(&cl, 0, sizeof(cl)); | |
| } | |
| bool Host_FilterTime(float time) | |
| { | |
| realtime += time; | |
| if ((!cls.timedemo) && ((realtime - oldrealtime) < (1.0 / 72.0))) | |
| return 0; | |
| host_frametime = realtime - oldrealtime; | |
| oldrealtime = realtime; | |
| if (host_framerate.value > 0) | |
| host_frametime = host_framerate.value; | |
| else | |
| { | |
| if (host_frametime > 0.1) | |
| host_frametime = 0.1; | |
| if (host_frametime < 0.001) | |
| host_frametime = 0.001; | |
| } | |
| return 1; | |
| } | |
| void Host_GetConsoleCommands(void) | |
| { | |
| char *cmd; | |
| while (1) | |
| { | |
| cmd = Sys_ConsoleInput(); | |
| if (!cmd) | |
| break; | |
| Cbuf_AddText(cmd); | |
| } | |
| } | |
| void Host_ServerFrame(void) | |
| { | |
| pr_global_struct->frametime = host_frametime; | |
| SV_ClearDatagram(); | |
| SV_CheckForNewClients(); | |
| SV_RunClients(); | |
| if ((!sv.paused) && ((svs.maxclients > 1) || (key_dest == key_game))) | |
| SV_Physics(); | |
| SV_SendClientMessages(); | |
| } | |
| void _Host_Frame(float time) | |
| { | |
| static double time1 = 0; | |
| static double time2 = 0; | |
| static double time3 = 0; | |
| int32_t pass1; | |
| int32_t pass2; | |
| int32_t pass3; | |
| if (setjmp(host_abortserver)) | |
| return; | |
| rand(); | |
| if (!Host_FilterTime(time)) | |
| return; | |
| Sys_SendKeyEvents(); | |
| IN_Commands(); | |
| Cbuf_Execute(); | |
| NET_Poll(); | |
| if (sv.active) | |
| CL_SendCmd(); | |
| Host_GetConsoleCommands(); | |
| if (sv.active) | |
| Host_ServerFrame(); | |
| if (!sv.active) | |
| CL_SendCmd(); | |
| host_time += host_frametime; | |
| if (cls.state == ca_connected) | |
| { | |
| CL_ReadFromServer(); | |
| } | |
| if (host_speeds.value) | |
| time1 = Sys_FloatTime(); | |
| SCR_UpdateScreen(); | |
| if (host_speeds.value) | |
| time2 = Sys_FloatTime(); | |
| if (cls.signon == SIGNONS) | |
| { | |
| S_Update(r_origin, vpn, vright, vup); | |
| CL_DecayLights(); | |
| } | |
| else | |
| S_Update(vec3_origin, vec3_origin, vec3_origin, vec3_origin); | |
| CDAudio_Update(); | |
| if (host_speeds.value) | |
| { | |
| pass1 = (time1 - time3) * 1000; | |
| time3 = Sys_FloatTime(); | |
| pass2 = (time2 - time1) * 1000; | |
| pass3 = (time3 - time2) * 1000; | |
| Con_Printf("%3i tot %3i server %3i gfx %3i snd\n", (pass1 + pass2) + pass3, pass1, pass2, pass3); | |
| } | |
| host_framecount++; | |
| } | |
| void Host_Frame(float time) | |
| { | |
| double time1; | |
| double time2; | |
| static double timetotal; | |
| static int32_t timecount; | |
| int32_t i; | |
| int32_t c; | |
| int32_t m; | |
| if (!serverprofile.value) | |
| { | |
| _Host_Frame(time); | |
| return; | |
| } | |
| time1 = Sys_FloatTime(); | |
| _Host_Frame(time); | |
| time2 = Sys_FloatTime(); | |
| timetotal += time2 - time1; | |
| timecount++; | |
| if (timecount < 1000) | |
| return; | |
| m = (timetotal * 1000) / timecount; | |
| timecount = 0; | |
| timetotal = 0; | |
| c = 0; | |
| for (i = 0; i < svs.maxclients; i++) | |
| { | |
| if (svs.clients[i].active) | |
| c++; | |
| } | |
| Con_Printf("serverprofile: %2i clients %2i msec\n", c, m); | |
| } | |
| void Host_InitVCR(quakeparms_t *parms) | |
| { | |
| int32_t i; | |
| int32_t len; | |
| int32_t n; | |
| char *p; | |
| if (COM_CheckParm("-playback")) | |
| { | |
| if (com_argc != 2) | |
| Sys_Error("No other parameters allowed with -playback\n"); | |
| Sys_FileOpenRead("quake.vcr", &vcrFile); | |
| if (vcrFile == (-1)) | |
| Sys_Error("playback file not found\n"); | |
| Sys_FileRead(vcrFile, &i, sizeof(int32_t)); | |
| if (i != VCR_SIGNATURE) | |
| Sys_Error("Invalid signature in vcr file\n"); | |
| Sys_FileRead(vcrFile, &com_argc, sizeof(int32_t)); | |
| com_argv = malloc(com_argc * (sizeof(char *))); | |
| com_argv[0] = parms->argv[0]; | |
| for (i = 0; i < com_argc; i++) | |
| { | |
| Sys_FileRead(vcrFile, &len, sizeof(int32_t)); | |
| p = malloc(len); | |
| Sys_FileRead(vcrFile, p, len); | |
| com_argv[i + 1] = p; | |
| } | |
| com_argc++; | |
| parms->argc = com_argc; | |
| parms->argv = com_argv; | |
| } | |
| if ((n = COM_CheckParm("-record")) != 0) | |
| { | |
| vcrFile = Sys_FileOpenWrite("quake.vcr"); | |
| i = VCR_SIGNATURE; | |
| Sys_FileWrite(vcrFile, &i, sizeof(int32_t)); | |
| i = com_argc - 1; | |
| Sys_FileWrite(vcrFile, &i, sizeof(int32_t)); | |
| for (i = 1; i < com_argc; i++) | |
| { | |
| if (i == n) | |
| { | |
| len = 10; | |
| Sys_FileWrite(vcrFile, &len, sizeof(int32_t)); | |
| Sys_FileWrite(vcrFile, "-playback", len); | |
| continue; | |
| } | |
| len = strlen(com_argv[i]) + 1; | |
| Sys_FileWrite(vcrFile, &len, sizeof(int32_t)); | |
| Sys_FileWrite(vcrFile, com_argv[i], len); | |
| } | |
| } | |
| } | |
| void Host_Init(quakeparms_t *parms) | |
| { | |
| if (standard_quake) | |
| minimum_memory = MINIMUM_MEMORY; | |
| else | |
| minimum_memory = MINIMUM_MEMORY_LEVELPAK; | |
| if (COM_CheckParm("-minmemory")) | |
| parms->memsize = minimum_memory; | |
| host_parms = *parms; | |
| if (parms->memsize < minimum_memory) | |
| Sys_Error("Only %4.1f megs of memory available, can't execute game", parms->memsize / ((float) 0x100000)); | |
| com_argc = parms->argc; | |
| com_argv = parms->argv; | |
| Memory_Init(parms->membase, parms->memsize); | |
| Cbuf_Init(); | |
| Cmd_Init(); | |
| V_Init(); | |
| Chase_Init(); | |
| Host_InitVCR(parms); | |
| COM_Init(parms->basedir); | |
| Host_InitLocal(); | |
| W_LoadWadFile("gfx.wad"); | |
| Key_Init(); | |
| Con_Init(); | |
| M_Init(); | |
| PR_Init(); | |
| Mod_Init(); | |
| NET_Init(); | |
| SV_Init(); | |
| Con_Printf("Exe: 15:39:14 Sep 12 2025\n"); | |
| Con_Printf("%4.1f megabyte heap\n", parms->memsize / (1024 * 1024.0)); | |
| R_InitTextures(); | |
| if (cls.state != ca_dedicated) | |
| { | |
| host_basepal = (uint8_t *) COM_LoadHunkFile("gfx/palette.lmp"); | |
| if (!host_basepal) | |
| Sys_Error("Couldn't load gfx/palette.lmp"); | |
| host_colormap = (uint8_t *) COM_LoadHunkFile("gfx/colormap.lmp"); | |
| if (!host_colormap) | |
| Sys_Error("Couldn't load gfx/colormap.lmp"); | |
| IN_Init(); | |
| VID_Init(host_basepal); | |
| Draw_Init(); | |
| SCR_Init(); | |
| R_Init(); | |
| S_Init(); | |
| CDAudio_Init(); | |
| Sbar_Init(); | |
| CL_Init(); | |
| } | |
| Cbuf_InsertText("exec quake.rc\n"); | |
| Hunk_AllocName(0, "-HOST_HUNKLEVEL-"); | |
| host_hunklevel = Hunk_LowMark(); | |
| host_initialized = 1; | |
| Sys_Printf("========Quake Initialized=========\n"); | |
| } | |
| void Host_Shutdown(void) | |
| { | |
| static bool isdown = 0; | |
| if (isdown) | |
| { | |
| printf("recursive shutdown\n"); | |
| return; | |
| } | |
| isdown = 1; | |
| scr_disabled_for_loading = 1; | |
| Host_WriteConfiguration(); | |
| CDAudio_Shutdown(); | |
| NET_Shutdown(); | |
| S_Shutdown(); | |
| IN_Shutdown(); | |
| if (cls.state != ca_dedicated) | |
| { | |
| VID_Shutdown(); | |
| } | |
| } | |
| void Host_Quit_f(void) | |
| { | |
| if ((key_dest != key_console) && (cls.state != ca_dedicated)) | |
| { | |
| M_Menu_Quit_f(); | |
| return; | |
| } | |
| CL_Disconnect(); | |
| Host_ShutdownServer(0); | |
| Sys_Quit(); | |
| } | |
| void Host_Status_f(void) | |
| { | |
| client_t *client; | |
| int32_t seconds; | |
| int32_t minutes; | |
| int32_t hours = 0; | |
| int32_t j; | |
| void (*print)(char *fmt, ...); | |
| if (cmd_source == src_command) | |
| { | |
| if (!sv.active) | |
| { | |
| Cmd_ForwardToServer(); | |
| return; | |
| } | |
| print = Con_Printf; | |
| } | |
| else | |
| print = SV_ClientPrintf; | |
| print("host: %s\n", Cvar_VariableString("hostname")); | |
| print("version: %4.2f\n", VERSION); | |
| if (tcpipAvailable) | |
| print("tcp/ip: %s\n", my_tcpip_address); | |
| if (ipxAvailable) | |
| print("ipx: %s\n", my_ipx_address); | |
| print("map: %s\n", sv.name); | |
| print("players: %i active (%i max)\n\n", net_activeconnections, svs.maxclients); | |
| for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++) | |
| { | |
| if (!client->active) | |
| continue; | |
| seconds = (int32_t) (net_time - client->netconnection->connecttime); | |
| minutes = seconds / 60; | |
| if (minutes) | |
| { | |
| seconds -= minutes * 60; | |
| hours = minutes / 60; | |
| if (hours) | |
| minutes -= hours * 60; | |
| } | |
| else | |
| hours = 0; | |
| print("#%-2u %-16.16s %3i %2i:%02i:%02i\n", j + 1, client->name, (int32_t) client->edict->v.frags, hours, minutes, seconds); | |
| print(" %s\n", client->netconnection->address); | |
| } | |
| } | |
| void Host_God_f(void) | |
| { | |
| if (cmd_source == src_command) | |
| { | |
| Cmd_ForwardToServer(); | |
| return; | |
| } | |
| if (pr_global_struct->deathmatch && (!host_client->privileged)) | |
| return; | |
| sv_player->v.flags = ((int32_t) sv_player->v.flags) ^ FL_GODMODE; | |
| if (!(((int32_t) sv_player->v.flags) & FL_GODMODE)) | |
| SV_ClientPrintf("godmode OFF\n"); | |
| else | |
| SV_ClientPrintf("godmode ON\n"); | |
| } | |
| void Host_Notarget_f(void) | |
| { | |
| if (cmd_source == src_command) | |
| { | |
| Cmd_ForwardToServer(); | |
| return; | |
| } | |
| if (pr_global_struct->deathmatch && (!host_client->privileged)) | |
| return; | |
| sv_player->v.flags = ((int32_t) sv_player->v.flags) ^ FL_NOTARGET; | |
| if (!(((int32_t) sv_player->v.flags) & FL_NOTARGET)) | |
| SV_ClientPrintf("notarget OFF\n"); | |
| else | |
| SV_ClientPrintf("notarget ON\n"); | |
| } | |
| void Host_Noclip_f(void) | |
| { | |
| if (cmd_source == src_command) | |
| { | |
| Cmd_ForwardToServer(); | |
| return; | |
| } | |
| if (pr_global_struct->deathmatch && (!host_client->privileged)) | |
| return; | |
| if (sv_player->v.movetype != MOVETYPE_NOCLIP) | |
| { | |
| noclip_anglehack = 1; | |
| sv_player->v.movetype = MOVETYPE_NOCLIP; | |
| SV_ClientPrintf("noclip ON\n"); | |
| } | |
| else | |
| { | |
| noclip_anglehack = 0; | |
| sv_player->v.movetype = MOVETYPE_WALK; | |
| SV_ClientPrintf("noclip OFF\n"); | |
| } | |
| } | |
| void Host_Fly_f(void) | |
| { | |
| if (cmd_source == src_command) | |
| { | |
| Cmd_ForwardToServer(); | |
| return; | |
| } | |
| if (pr_global_struct->deathmatch && (!host_client->privileged)) | |
| return; | |
| if (sv_player->v.movetype != MOVETYPE_FLY) | |
| { | |
| sv_player->v.movetype = MOVETYPE_FLY; | |
| SV_ClientPrintf("flymode ON\n"); | |
| } | |
| else | |
| { | |
| sv_player->v.movetype = MOVETYPE_WALK; | |
| SV_ClientPrintf("flymode OFF\n"); | |
| } | |
| } | |
| void Host_Ping_f(void) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| float total; | |
| client_t *client; | |
| if (cmd_source == src_command) | |
| { | |
| Cmd_ForwardToServer(); | |
| return; | |
| } | |
| SV_ClientPrintf("Client ping times:\n"); | |
| for (i = 0, client = svs.clients; i < svs.maxclients; i++, client++) | |
| { | |
| if (!client->active) | |
| continue; | |
| total = 0; | |
| for (j = 0; j < NUM_PING_TIMES; j++) | |
| total += client->ping_times[j]; | |
| total /= NUM_PING_TIMES; | |
| SV_ClientPrintf("%4i %s\n", (int32_t) (total * 1000), client->name); | |
| } | |
| } | |
| void Host_Map_f(void) | |
| { | |
| int32_t i; | |
| char name[MAX_QPATH]; | |
| if (cmd_source != src_command) | |
| return; | |
| cls.demonum = -1; | |
| CL_Disconnect(); | |
| Host_ShutdownServer(0); | |
| key_dest = key_game; | |
| SCR_BeginLoadingPlaque(); | |
| cls.mapstring[0] = 0; | |
| for (i = 0; i < Cmd_Argc(); i++) | |
| { | |
| strcat(cls.mapstring, Cmd_Argv(i)); | |
| strcat(cls.mapstring, " "); | |
| } | |
| strcat(cls.mapstring, "\n"); | |
| svs.serverflags = 0; | |
| strcpy(name, Cmd_Argv(1)); | |
| SV_SpawnServer(name); | |
| if (!sv.active) | |
| return; | |
| if (cls.state != ca_dedicated) | |
| { | |
| strcpy(cls.spawnparms, ""); | |
| for (i = 2; i < Cmd_Argc(); i++) | |
| { | |
| strcat(cls.spawnparms, Cmd_Argv(i)); | |
| strcat(cls.spawnparms, " "); | |
| } | |
| Cmd_ExecuteString("connect local", src_command); | |
| } | |
| } | |
| void Host_Changelevel_f(void) | |
| { | |
| char level[MAX_QPATH]; | |
| if (Cmd_Argc() != 2) | |
| { | |
| Con_Printf("changelevel <levelname> : continue game on a new level\n"); | |
| return; | |
| } | |
| if ((!sv.active) || cls.demoplayback) | |
| { | |
| Con_Printf("Only the server may changelevel\n"); | |
| return; | |
| } | |
| SV_SaveSpawnparms(); | |
| strcpy(level, Cmd_Argv(1)); | |
| SV_SpawnServer(level); | |
| } | |
| void Host_Restart_f(void) | |
| { | |
| char mapname[MAX_QPATH]; | |
| if (cls.demoplayback || (!sv.active)) | |
| return; | |
| if (cmd_source != src_command) | |
| return; | |
| strcpy(mapname, sv.name); | |
| SV_SpawnServer(mapname); | |
| } | |
| void Host_Reconnect_f(void) | |
| { | |
| SCR_BeginLoadingPlaque(); | |
| cls.signon = 0; | |
| } | |
| void Host_Connect_f(void) | |
| { | |
| char name[MAX_QPATH]; | |
| cls.demonum = -1; | |
| if (cls.demoplayback) | |
| { | |
| CL_StopPlayback(); | |
| CL_Disconnect(); | |
| } | |
| strcpy(name, Cmd_Argv(1)); | |
| CL_EstablishConnection(name); | |
| Host_Reconnect_f(); | |
| } | |
| void Host_SavegameComment(char *text) | |
| { | |
| int32_t i; | |
| char kills[20]; | |
| for (i = 0; i < SAVEGAME_COMMENT_LENGTH; i++) | |
| text[i] = ' '; | |
| memcpy(text, cl.levelname, strlen(cl.levelname)); | |
| sprintf(kills, "kills:%3i/%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]); | |
| memcpy(text + 22, kills, strlen(kills)); | |
| for (i = 0; i < SAVEGAME_COMMENT_LENGTH; i++) | |
| if (text[i] == ' ') | |
| text[i] = '_'; | |
| text[SAVEGAME_COMMENT_LENGTH] = '\0'; | |
| } | |
| void Host_Savegame_f(void) | |
| { | |
| char name[256]; | |
| FILE *f; | |
| int32_t i; | |
| char comment[SAVEGAME_COMMENT_LENGTH + 1]; | |
| if (cmd_source != src_command) | |
| return; | |
| if (!sv.active) | |
| { | |
| Con_Printf("Not playing a local game.\n"); | |
| return; | |
| } | |
| if (cl.intermission) | |
| { | |
| Con_Printf("Can't save in intermission.\n"); | |
| return; | |
| } | |
| if (svs.maxclients != 1) | |
| { | |
| Con_Printf("Can't save multiplayer games.\n"); | |
| return; | |
| } | |
| if (Cmd_Argc() != 2) | |
| { | |
| Con_Printf("save <savename> : save a game\n"); | |
| return; | |
| } | |
| if (strstr(Cmd_Argv(1), "..")) | |
| { | |
| Con_Printf("Relative pathnames are not allowed.\n"); | |
| return; | |
| } | |
| for (i = 0; i < svs.maxclients; i++) | |
| { | |
| if (svs.clients[i].active && (svs.clients[i].edict->v.health <= 0)) | |
| { | |
| Con_Printf("Can't savegame with a dead player\n"); | |
| return; | |
| } | |
| } | |
| sprintf(name, "%s/%s", com_gamedir, Cmd_Argv(1)); | |
| COM_DefaultExtension(name, ".sav"); | |
| Con_Printf("Saving game to %s...\n", name); | |
| f = fopen(name, "w"); | |
| if (!f) | |
| { | |
| Con_Printf("ERROR: couldn't open.\n"); | |
| return; | |
| } | |
| fprintf(f, "%i\n", SAVEGAME_VERSION); | |
| Host_SavegameComment(comment); | |
| fprintf(f, "%s\n", comment); | |
| for (i = 0; i < NUM_SPAWN_PARMS; i++) | |
| fprintf(f, "%f\n", svs.clients->spawn_parms[i]); | |
| fprintf(f, "%d\n", current_skill); | |
| fprintf(f, "%s\n", sv.name); | |
| fprintf(f, "%f\n", sv.time); | |
| for (i = 0; i < MAX_LIGHTSTYLES; i++) | |
| { | |
| if (sv.lightstyles[i]) | |
| fprintf(f, "%s\n", sv.lightstyles[i]); | |
| else | |
| fprintf(f, "m\n"); | |
| } | |
| ED_WriteGlobals(f); | |
| for (i = 0; i < sv.num_edicts; i++) | |
| { | |
| ED_Write(f, EDICT_NUM(i)); | |
| fflush(f); | |
| } | |
| fclose(f); | |
| Con_Printf("done.\n"); | |
| } | |
| void Host_Loadgame_f(void) | |
| { | |
| char name[MAX_OSPATH]; | |
| FILE *f; | |
| char mapname[MAX_QPATH]; | |
| float time; | |
| float tfloat; | |
| char str[32768]; | |
| char *start; | |
| int32_t i; | |
| int32_t r; | |
| edict_t *ent; | |
| int32_t entnum; | |
| int32_t version; | |
| float spawn_parms[NUM_SPAWN_PARMS]; | |
| if (cmd_source != src_command) | |
| return; | |
| if (Cmd_Argc() != 2) | |
| { | |
| Con_Printf("load <savename> : load a game\n"); | |
| return; | |
| } | |
| cls.demonum = -1; | |
| sprintf(name, "%s/%s", com_gamedir, Cmd_Argv(1)); | |
| COM_DefaultExtension(name, ".sav"); | |
| Con_Printf("Loading game from %s...\n", name); | |
| f = fopen(name, "r"); | |
| if (!f) | |
| { | |
| Con_Printf("ERROR: couldn't open.\n"); | |
| return; | |
| } | |
| fscanf(f, "%i\n", &version); | |
| if (version != SAVEGAME_VERSION) | |
| { | |
| fclose(f); | |
| Con_Printf("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); | |
| return; | |
| } | |
| fscanf(f, "%s\n", str); | |
| for (i = 0; i < NUM_SPAWN_PARMS; i++) | |
| fscanf(f, "%f\n", &spawn_parms[i]); | |
| fscanf(f, "%f\n", &tfloat); | |
| current_skill = (int32_t) (tfloat + 0.1); | |
| Cvar_SetValue("skill", (float) current_skill); | |
| fscanf(f, "%s\n", mapname); | |
| fscanf(f, "%f\n", &time); | |
| CL_Disconnect_f(); | |
| SV_SpawnServer(mapname); | |
| if (!sv.active) | |
| { | |
| Con_Printf("Couldn't load map\n"); | |
| return; | |
| } | |
| sv.paused = 1; | |
| sv.loadgame = 1; | |
| for (i = 0; i < MAX_LIGHTSTYLES; i++) | |
| { | |
| fscanf(f, "%s\n", str); | |
| sv.lightstyles[i] = Hunk_Alloc(strlen(str) + 1); | |
| strcpy(sv.lightstyles[i], str); | |
| } | |
| entnum = -1; | |
| while (!feof(f)) | |
| { | |
| for (i = 0; i < ((sizeof(str)) - 1); i++) | |
| { | |
| r = fgetc(f); | |
| if ((r == EOF) || (!r)) | |
| break; | |
| str[i] = r; | |
| if (r == '}') | |
| { | |
| i++; | |
| break; | |
| } | |
| } | |
| if (i == ((sizeof(str)) - 1)) | |
| Sys_Error("Loadgame buffer overflow"); | |
| str[i] = 0; | |
| start = str; | |
| start = COM_Parse(str); | |
| if (!com_token[0]) | |
| break; | |
| if (strcmp(com_token, "{")) | |
| Sys_Error("First token isn't a brace"); | |
| if (entnum == (-1)) | |
| { | |
| ED_ParseGlobals(start); | |
| } | |
| else | |
| { | |
| ent = EDICT_NUM(entnum); | |
| memset(&ent->v, 0, progs->entityfields * 4); | |
| ent->free = 0; | |
| ED_ParseEdict(start, ent); | |
| if (!ent->free) | |
| SV_LinkEdict(ent, 0); | |
| } | |
| entnum++; | |
| } | |
| sv.num_edicts = entnum; | |
| sv.time = time; | |
| fclose(f); | |
| for (i = 0; i < NUM_SPAWN_PARMS; i++) | |
| svs.clients->spawn_parms[i] = spawn_parms[i]; | |
| if (cls.state != ca_dedicated) | |
| { | |
| CL_EstablishConnection("local"); | |
| Host_Reconnect_f(); | |
| } | |
| } | |
| void Host_Name_f(void) | |
| { | |
| char *newName; | |
| if (Cmd_Argc() == 1) | |
| { | |
| Con_Printf("\"name\" is \"%s\"\n", cl_name.string); | |
| return; | |
| } | |
| if (Cmd_Argc() == 2) | |
| newName = Cmd_Argv(1); | |
| else | |
| newName = Cmd_Args(); | |
| newName[15] = 0; | |
| if (cmd_source == src_command) | |
| { | |
| if (strcmp(cl_name.string, newName) == 0) | |
| return; | |
| Cvar_Set("_cl_name", newName); | |
| if (cls.state == ca_connected) | |
| Cmd_ForwardToServer(); | |
| return; | |
| } | |
| if (host_client->name[0] && strcmp(host_client->name, "unconnected")) | |
| if (strcmp(host_client->name, newName) != 0) | |
| Con_Printf("%s renamed to %s\n", host_client->name, newName); | |
| strcpy(host_client->name, newName); | |
| host_client->edict->v.netname = host_client->name - pr_strings; | |
| MSG_WriteByte(&sv.reliable_datagram, svc_updatename); | |
| MSG_WriteByte(&sv.reliable_datagram, host_client - svs.clients); | |
| MSG_WriteString(&sv.reliable_datagram, host_client->name); | |
| } | |
| void Host_Version_f(void) | |
| { | |
| Con_Printf("Version %4.2f\n", VERSION); | |
| Con_Printf("Exe: 15:39:14 Sep 12 2025\n"); | |
| } | |
| void Host_Say(bool teamonly) | |
| { | |
| client_t *client; | |
| client_t *save; | |
| int32_t j; | |
| char *p; | |
| unsigned char text[64]; | |
| bool fromServer = 0; | |
| if (cmd_source == src_command) | |
| { | |
| if (cls.state == ca_dedicated) | |
| { | |
| fromServer = 1; | |
| teamonly = 0; | |
| } | |
| else | |
| { | |
| Cmd_ForwardToServer(); | |
| return; | |
| } | |
| } | |
| if (Cmd_Argc() < 2) | |
| return; | |
| save = host_client; | |
| p = Cmd_Args(); | |
| if ((*p) == '"') | |
| { | |
| p++; | |
| p[strlen(p) - 1] = 0; | |
| } | |
| if (!fromServer) | |
| sprintf(text, "%c%s: ", 1, save->name); | |
| else | |
| sprintf(text, "%c<%s> ", 1, hostname.string); | |
| j = ((sizeof(text)) - 2) - strlen(text); | |
| if (strlen(p) > j) | |
| p[j] = 0; | |
| strcat(text, p); | |
| strcat(text, "\n"); | |
| for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++) | |
| { | |
| if (((!client) || (!client->active)) || (!client->spawned)) | |
| continue; | |
| if ((teamplay.value && teamonly) && (client->edict->v.team != save->edict->v.team)) | |
| continue; | |
| host_client = client; | |
| SV_ClientPrintf("%s", text); | |
| } | |
| host_client = save; | |
| Sys_Printf("%s", &text[1]); | |
| } | |
| void Host_Say_f(void) | |
| { | |
| Host_Say(0); | |
| } | |
| void Host_Say_Team_f(void) | |
| { | |
| Host_Say(1); | |
| } | |
| void Host_Tell_f(void) | |
| { | |
| client_t *client; | |
| client_t *save; | |
| int32_t j; | |
| char *p; | |
| char text[64]; | |
| if (cmd_source == src_command) | |
| { | |
| Cmd_ForwardToServer(); | |
| return; | |
| } | |
| if (Cmd_Argc() < 3) | |
| return; | |
| strcpy(text, host_client->name); | |
| strcat(text, ": "); | |
| p = Cmd_Args(); | |
| if ((*p) == '"') | |
| { | |
| p++; | |
| p[strlen(p) - 1] = 0; | |
| } | |
| j = ((sizeof(text)) - 2) - strlen(text); | |
| if (strlen(p) > j) | |
| p[j] = 0; | |
| strcat(text, p); | |
| strcat(text, "\n"); | |
| save = host_client; | |
| for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++) | |
| { | |
| if ((!client->active) || (!client->spawned)) | |
| continue; | |
| if (strcasecmp(client->name, Cmd_Argv(1))) | |
| continue; | |
| host_client = client; | |
| SV_ClientPrintf("%s", text); | |
| break; | |
| } | |
| host_client = save; | |
| } | |
| void Host_Color_f(void) | |
| { | |
| int32_t top; | |
| int32_t bottom; | |
| int32_t playercolor; | |
| if (Cmd_Argc() == 1) | |
| { | |
| Con_Printf("\"color\" is \"%i %i\"\n", ((int32_t) cl_color.value) >> 4, ((int32_t) cl_color.value) & 0x0f); | |
| Con_Printf("color <0-13> [0-13]\n"); | |
| return; | |
| } | |
| if (Cmd_Argc() == 2) | |
| top = (bottom = atoi(Cmd_Argv(1))); | |
| else | |
| { | |
| top = atoi(Cmd_Argv(1)); | |
| bottom = atoi(Cmd_Argv(2)); | |
| } | |
| top &= 15; | |
| if (top > 13) | |
| top = 13; | |
| bottom &= 15; | |
| if (bottom > 13) | |
| bottom = 13; | |
| playercolor = (top * 16) + bottom; | |
| if (cmd_source == src_command) | |
| { | |
| Cvar_SetValue("_cl_color", playercolor); | |
| if (cls.state == ca_connected) | |
| Cmd_ForwardToServer(); | |
| return; | |
| } | |
| host_client->colors = playercolor; | |
| host_client->edict->v.team = bottom + 1; | |
| MSG_WriteByte(&sv.reliable_datagram, svc_updatecolors); | |
| MSG_WriteByte(&sv.reliable_datagram, host_client - svs.clients); | |
| MSG_WriteByte(&sv.reliable_datagram, host_client->colors); | |
| } | |
| void Host_Kill_f(void) | |
| { | |
| if (cmd_source == src_command) | |
| { | |
| Cmd_ForwardToServer(); | |
| return; | |
| } | |
| if (sv_player->v.health <= 0) | |
| { | |
| SV_ClientPrintf("Can't suicide -- allready dead!\n"); | |
| return; | |
| } | |
| pr_global_struct->time = sv.time; | |
| pr_global_struct->self = EDICT_TO_PROG(sv_player); | |
| PR_ExecuteProgram(pr_global_struct->ClientKill); | |
| } | |
| void Host_Pause_f(void) | |
| { | |
| if (cmd_source == src_command) | |
| { | |
| Cmd_ForwardToServer(); | |
| return; | |
| } | |
| if (!pausable.value) | |
| SV_ClientPrintf("Pause not allowed.\n"); | |
| else | |
| { | |
| sv.paused ^= 1; | |
| if (sv.paused) | |
| { | |
| SV_BroadcastPrintf("%s paused the game\n", pr_strings + sv_player->v.netname); | |
| } | |
| else | |
| { | |
| SV_BroadcastPrintf("%s unpaused the game\n", pr_strings + sv_player->v.netname); | |
| } | |
| MSG_WriteByte(&sv.reliable_datagram, svc_setpause); | |
| MSG_WriteByte(&sv.reliable_datagram, sv.paused); | |
| } | |
| } | |
| void Host_PreSpawn_f(void) | |
| { | |
| if (cmd_source == src_command) | |
| { | |
| Con_Printf("prespawn is not valid from the console\n"); | |
| return; | |
| } | |
| if (host_client->spawned) | |
| { | |
| Con_Printf("prespawn not valid -- allready spawned\n"); | |
| return; | |
| } | |
| SZ_Write(&host_client->message, sv.signon.data, sv.signon.cursize); | |
| MSG_WriteByte(&host_client->message, svc_signonnum); | |
| MSG_WriteByte(&host_client->message, 2); | |
| host_client->sendsignon = 1; | |
| } | |
| void Host_Spawn_f(void) | |
| { | |
| int32_t i; | |
| client_t *client; | |
| edict_t *ent; | |
| if (cmd_source == src_command) | |
| { | |
| Con_Printf("spawn is not valid from the console\n"); | |
| return; | |
| } | |
| if (host_client->spawned) | |
| { | |
| Con_Printf("Spawn not valid -- allready spawned\n"); | |
| return; | |
| } | |
| if (sv.loadgame) | |
| { | |
| sv.paused = 0; | |
| } | |
| else | |
| { | |
| ent = host_client->edict; | |
| memset(&ent->v, 0, progs->entityfields * 4); | |
| ent->v.colormap = NUM_FOR_EDICT(ent); | |
| ent->v.team = (host_client->colors & 15) + 1; | |
| ent->v.netname = host_client->name - pr_strings; | |
| for (i = 0; i < NUM_SPAWN_PARMS; i++) | |
| (&pr_global_struct->parm1)[i] = host_client->spawn_parms[i]; | |
| pr_global_struct->time = sv.time; | |
| pr_global_struct->self = EDICT_TO_PROG(sv_player); | |
| PR_ExecuteProgram(pr_global_struct->ClientConnect); | |
| if ((Sys_FloatTime() - host_client->netconnection->connecttime) <= sv.time) | |
| Sys_Printf("%s entered the game\n", host_client->name); | |
| PR_ExecuteProgram(pr_global_struct->PutClientInServer); | |
| } | |
| SZ_Clear(&host_client->message); | |
| MSG_WriteByte(&host_client->message, svc_time); | |
| MSG_WriteFloat(&host_client->message, sv.time); | |
| for (i = 0, client = svs.clients; i < svs.maxclients; i++, client++) | |
| { | |
| MSG_WriteByte(&host_client->message, svc_updatename); | |
| MSG_WriteByte(&host_client->message, i); | |
| MSG_WriteString(&host_client->message, client->name); | |
| MSG_WriteByte(&host_client->message, svc_updatefrags); | |
| MSG_WriteByte(&host_client->message, i); | |
| MSG_WriteShort(&host_client->message, client->old_frags); | |
| MSG_WriteByte(&host_client->message, svc_updatecolors); | |
| MSG_WriteByte(&host_client->message, i); | |
| MSG_WriteByte(&host_client->message, client->colors); | |
| } | |
| for (i = 0; i < MAX_LIGHTSTYLES; i++) | |
| { | |
| MSG_WriteByte(&host_client->message, svc_lightstyle); | |
| MSG_WriteByte(&host_client->message, (char) i); | |
| MSG_WriteString(&host_client->message, sv.lightstyles[i]); | |
| } | |
| MSG_WriteByte(&host_client->message, svc_updatestat); | |
| MSG_WriteByte(&host_client->message, STAT_TOTALSECRETS); | |
| MSG_WriteLong(&host_client->message, pr_global_struct->total_secrets); | |
| MSG_WriteByte(&host_client->message, svc_updatestat); | |
| MSG_WriteByte(&host_client->message, STAT_TOTALMONSTERS); | |
| MSG_WriteLong(&host_client->message, pr_global_struct->total_monsters); | |
| MSG_WriteByte(&host_client->message, svc_updatestat); | |
| MSG_WriteByte(&host_client->message, STAT_SECRETS); | |
| MSG_WriteLong(&host_client->message, pr_global_struct->found_secrets); | |
| MSG_WriteByte(&host_client->message, svc_updatestat); | |
| MSG_WriteByte(&host_client->message, STAT_MONSTERS); | |
| MSG_WriteLong(&host_client->message, pr_global_struct->killed_monsters); | |
| ent = EDICT_NUM(1 + (host_client - svs.clients)); | |
| MSG_WriteByte(&host_client->message, svc_setangle); | |
| for (i = 0; i < 2; i++) | |
| MSG_WriteAngle(&host_client->message, ent->v.angles[i]); | |
| MSG_WriteAngle(&host_client->message, 0); | |
| SV_WriteClientdataToMessage(sv_player, &host_client->message); | |
| MSG_WriteByte(&host_client->message, svc_signonnum); | |
| MSG_WriteByte(&host_client->message, 3); | |
| host_client->sendsignon = 1; | |
| } | |
| void Host_Begin_f(void) | |
| { | |
| if (cmd_source == src_command) | |
| { | |
| Con_Printf("begin is not valid from the console\n"); | |
| return; | |
| } | |
| host_client->spawned = 1; | |
| } | |
| void Host_Kick_f(void) | |
| { | |
| char *who; | |
| char *message = 0; | |
| client_t *save; | |
| int32_t i; | |
| bool byNumber = 0; | |
| if (cmd_source == src_command) | |
| { | |
| if (!sv.active) | |
| { | |
| Cmd_ForwardToServer(); | |
| return; | |
| } | |
| } | |
| else | |
| if (pr_global_struct->deathmatch && (!host_client->privileged)) | |
| return; | |
| save = host_client; | |
| if ((Cmd_Argc() > 2) && (strcmp(Cmd_Argv(1), "#") == 0)) | |
| { | |
| i = ((float) strtod(Cmd_Argv(2), 0)) - 1; | |
| if ((i < 0) || (i >= svs.maxclients)) | |
| return; | |
| if (!svs.clients[i].active) | |
| return; | |
| host_client = &svs.clients[i]; | |
| byNumber = 1; | |
| } | |
| else | |
| { | |
| for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++) | |
| { | |
| if (!host_client->active) | |
| continue; | |
| if (strcasecmp(host_client->name, Cmd_Argv(1)) == 0) | |
| break; | |
| } | |
| } | |
| if (i < svs.maxclients) | |
| { | |
| if (cmd_source == src_command) | |
| if (cls.state == ca_dedicated) | |
| who = "Console"; | |
| else | |
| who = cl_name.string; | |
| else | |
| who = save->name; | |
| if (host_client == save) | |
| return; | |
| if (Cmd_Argc() > 2) | |
| { | |
| message = COM_Parse(Cmd_Args()); | |
| if (byNumber) | |
| { | |
| message++; | |
| while ((*message) == ' ') | |
| message++; | |
| message += strlen(Cmd_Argv(2)); | |
| } | |
| while ((*message) && ((*message) == ' ')) | |
| message++; | |
| } | |
| if (message) | |
| SV_ClientPrintf("Kicked by %s: %s\n", who, message); | |
| else | |
| SV_ClientPrintf("Kicked by %s\n", who); | |
| SV_DropClient(0); | |
| } | |
| host_client = save; | |
| } | |
| void Host_Give_f(void) | |
| { | |
| char *t; | |
| int32_t v; | |
| int32_t w; | |
| eval_t *val; | |
| if (cmd_source == src_command) | |
| { | |
| Cmd_ForwardToServer(); | |
| return; | |
| } | |
| if (pr_global_struct->deathmatch && (!host_client->privileged)) | |
| return; | |
| t = Cmd_Argv(1); | |
| v = atoi(Cmd_Argv(2)); | |
| switch (t[0]) | |
| { | |
| case '0': | |
| case '1': | |
| case '2': | |
| case '3': | |
| case '4': | |
| case '5': | |
| case '6': | |
| case '7': | |
| case '8': | |
| case '9': | |
| if (hipnotic) | |
| { | |
| if (t[0] == '6') | |
| { | |
| if (t[1] == 'a') | |
| sv_player->v.items = ((int32_t) sv_player->v.items) | HIT_PROXIMITY_GUN; | |
| else | |
| sv_player->v.items = ((int32_t) sv_player->v.items) | IT_GRENADE_LAUNCHER; | |
| } | |
| else | |
| if (t[0] == '9') | |
| sv_player->v.items = ((int32_t) sv_player->v.items) | HIT_LASER_CANNON; | |
| else | |
| if (t[0] == '0') | |
| sv_player->v.items = ((int32_t) sv_player->v.items) | HIT_MJOLNIR; | |
| else | |
| if (t[0] >= '2') | |
| sv_player->v.items = ((int32_t) sv_player->v.items) | (IT_SHOTGUN << (t[0] - '2')); | |
| } | |
| else | |
| { | |
| if (t[0] >= '2') | |
| sv_player->v.items = ((int32_t) sv_player->v.items) | (IT_SHOTGUN << (t[0] - '2')); | |
| } | |
| break; | |
| case 's': | |
| if (rogue) | |
| { | |
| val = GetEdictFieldValue(sv_player, "ammo_shells1"); | |
| if (val) | |
| val->_float = v; | |
| } | |
| sv_player->v.ammo_shells = v; | |
| break; | |
| case 'n': | |
| if (rogue) | |
| { | |
| val = GetEdictFieldValue(sv_player, "ammo_nails1"); | |
| if (val) | |
| { | |
| val->_float = v; | |
| if (sv_player->v.weapon <= IT_LIGHTNING) | |
| sv_player->v.ammo_nails = v; | |
| } | |
| } | |
| else | |
| { | |
| sv_player->v.ammo_nails = v; | |
| } | |
| break; | |
| case 'l': | |
| if (rogue) | |
| { | |
| val = GetEdictFieldValue(sv_player, "ammo_lava_nails"); | |
| if (val) | |
| { | |
| val->_float = v; | |
| if (sv_player->v.weapon > IT_LIGHTNING) | |
| sv_player->v.ammo_nails = v; | |
| } | |
| } | |
| break; | |
| case 'r': | |
| if (rogue) | |
| { | |
| val = GetEdictFieldValue(sv_player, "ammo_rockets1"); | |
| if (val) | |
| { | |
| val->_float = v; | |
| if (sv_player->v.weapon <= IT_LIGHTNING) | |
| sv_player->v.ammo_rockets = v; | |
| } | |
| } | |
| else | |
| { | |
| sv_player->v.ammo_rockets = v; | |
| } | |
| break; | |
| case 'm': | |
| if (rogue) | |
| { | |
| val = GetEdictFieldValue(sv_player, "ammo_multi_rockets"); | |
| if (val) | |
| { | |
| val->_float = v; | |
| if (sv_player->v.weapon > IT_LIGHTNING) | |
| sv_player->v.ammo_rockets = v; | |
| } | |
| } | |
| break; | |
| case 'h': | |
| sv_player->v.health = v; | |
| break; | |
| case 'c': | |
| if (rogue) | |
| { | |
| val = GetEdictFieldValue(sv_player, "ammo_cells1"); | |
| if (val) | |
| { | |
| val->_float = v; | |
| if (sv_player->v.weapon <= IT_LIGHTNING) | |
| sv_player->v.ammo_cells = v; | |
| } | |
| } | |
| else | |
| { | |
| sv_player->v.ammo_cells = v; | |
| } | |
| break; | |
| case 'p': | |
| if (rogue) | |
| { | |
| val = GetEdictFieldValue(sv_player, "ammo_plasma"); | |
| if (val) | |
| { | |
| val->_float = v; | |
| if (sv_player->v.weapon > IT_LIGHTNING) | |
| sv_player->v.ammo_cells = v; | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| edict_t *FindViewthing(void) | |
| { | |
| int32_t i; | |
| edict_t *e; | |
| for (i = 0; i < sv.num_edicts; i++) | |
| { | |
| e = EDICT_NUM(i); | |
| if (!strcmp(pr_strings + e->v.classname, "viewthing")) | |
| return e; | |
| } | |
| Con_Printf("No viewthing on map\n"); | |
| return 0; | |
| } | |
| void Host_Viewmodel_f(void) | |
| { | |
| edict_t *e; | |
| model_t *m; | |
| e = FindViewthing(); | |
| if (!e) | |
| return; | |
| m = Mod_ForName(Cmd_Argv(1), 0); | |
| if (!m) | |
| { | |
| Con_Printf("Can't load %s\n", Cmd_Argv(1)); | |
| return; | |
| } | |
| e->v.frame = 0; | |
| cl.model_precache[(int32_t) e->v.modelindex] = m; | |
| } | |
| void Host_Viewframe_f(void) | |
| { | |
| edict_t *e; | |
| int32_t f; | |
| model_t *m; | |
| e = FindViewthing(); | |
| if (!e) | |
| return; | |
| m = cl.model_precache[(int32_t) e->v.modelindex]; | |
| f = atoi(Cmd_Argv(1)); | |
| if (f >= m->numframes) | |
| f = m->numframes - 1; | |
| e->v.frame = f; | |
| } | |
| void PrintFrameName(model_t *m, int32_t frame) | |
| { | |
| aliashdr_t *hdr; | |
| maliasframedesc_t *pframedesc; | |
| hdr = (aliashdr_t *) Mod_Extradata(m); | |
| if (!hdr) | |
| return; | |
| pframedesc = &hdr->frames[frame]; | |
| Con_Printf("frame %i: %s\n", frame, pframedesc->name); | |
| } | |
| void Host_Viewnext_f(void) | |
| { | |
| edict_t *e; | |
| model_t *m; | |
| e = FindViewthing(); | |
| if (!e) | |
| return; | |
| m = cl.model_precache[(int32_t) e->v.modelindex]; | |
| e->v.frame = e->v.frame + 1; | |
| if (e->v.frame >= m->numframes) | |
| e->v.frame = m->numframes - 1; | |
| PrintFrameName(m, e->v.frame); | |
| } | |
| void Host_Viewprev_f(void) | |
| { | |
| edict_t *e; | |
| model_t *m; | |
| e = FindViewthing(); | |
| if (!e) | |
| return; | |
| m = cl.model_precache[(int32_t) e->v.modelindex]; | |
| e->v.frame = e->v.frame - 1; | |
| if (e->v.frame < 0) | |
| e->v.frame = 0; | |
| PrintFrameName(m, e->v.frame); | |
| } | |
| void Host_Startdemos_f(void) | |
| { | |
| int32_t i; | |
| int32_t c; | |
| if (cls.state == ca_dedicated) | |
| { | |
| if (!sv.active) | |
| Cbuf_AddText("map start\n"); | |
| return; | |
| } | |
| c = Cmd_Argc() - 1; | |
| if (c > MAX_DEMOS) | |
| { | |
| Con_Printf("Max %i demos in demoloop\n", MAX_DEMOS); | |
| c = MAX_DEMOS; | |
| } | |
| Con_Printf("%i demo(s) in loop\n", c); | |
| for (i = 1; i < (c + 1); i++) | |
| strncpy(cls.demos[i - 1], Cmd_Argv(i), (sizeof(cls.demos[0])) - 1); | |
| if (((!sv.active) && (cls.demonum != (-1))) && (!cls.demoplayback)) | |
| { | |
| cls.demonum = 0; | |
| CL_NextDemo(); | |
| } | |
| else | |
| cls.demonum = -1; | |
| } | |
| void Host_Demos_f(void) | |
| { | |
| if (cls.state == ca_dedicated) | |
| return; | |
| if (cls.demonum == (-1)) | |
| cls.demonum = 1; | |
| CL_Disconnect_f(); | |
| CL_NextDemo(); | |
| } | |
| void Host_Stopdemo_f(void) | |
| { | |
| if (cls.state == ca_dedicated) | |
| return; | |
| if (!cls.demoplayback) | |
| return; | |
| CL_StopPlayback(); | |
| CL_Disconnect(); | |
| } | |
| void Host_InitCommands(void) | |
| { | |
| Cmd_AddCommand("status", Host_Status_f); | |
| Cmd_AddCommand("quit", Host_Quit_f); | |
| Cmd_AddCommand("god", Host_God_f); | |
| Cmd_AddCommand("notarget", Host_Notarget_f); | |
| Cmd_AddCommand("fly", Host_Fly_f); | |
| Cmd_AddCommand("map", Host_Map_f); | |
| Cmd_AddCommand("restart", Host_Restart_f); | |
| Cmd_AddCommand("changelevel", Host_Changelevel_f); | |
| Cmd_AddCommand("connect", Host_Connect_f); | |
| Cmd_AddCommand("reconnect", Host_Reconnect_f); | |
| Cmd_AddCommand("name", Host_Name_f); | |
| Cmd_AddCommand("noclip", Host_Noclip_f); | |
| Cmd_AddCommand("version", Host_Version_f); | |
| Cmd_AddCommand("say", Host_Say_f); | |
| Cmd_AddCommand("say_team", Host_Say_Team_f); | |
| Cmd_AddCommand("tell", Host_Tell_f); | |
| Cmd_AddCommand("color", Host_Color_f); | |
| Cmd_AddCommand("kill", Host_Kill_f); | |
| Cmd_AddCommand("pause", Host_Pause_f); | |
| Cmd_AddCommand("spawn", Host_Spawn_f); | |
| Cmd_AddCommand("begin", Host_Begin_f); | |
| Cmd_AddCommand("prespawn", Host_PreSpawn_f); | |
| Cmd_AddCommand("kick", Host_Kick_f); | |
| Cmd_AddCommand("ping", Host_Ping_f); | |
| Cmd_AddCommand("load", Host_Loadgame_f); | |
| Cmd_AddCommand("save", Host_Savegame_f); | |
| Cmd_AddCommand("give", Host_Give_f); | |
| Cmd_AddCommand("startdemos", Host_Startdemos_f); | |
| Cmd_AddCommand("demos", Host_Demos_f); | |
| Cmd_AddCommand("stopdemo", Host_Stopdemo_f); | |
| Cmd_AddCommand("viewmodel", Host_Viewmodel_f); | |
| Cmd_AddCommand("viewframe", Host_Viewframe_f); | |
| Cmd_AddCommand("viewnext", Host_Viewnext_f); | |
| Cmd_AddCommand("viewprev", Host_Viewprev_f); | |
| Cmd_AddCommand("mcache", Mod_Print); | |
| } | |
| void Key_Console(int32_t key) | |
| { | |
| char *cmd; | |
| if (key == K_ENTER) | |
| { | |
| Cbuf_AddText(key_lines[edit_line] + 1); | |
| Cbuf_AddText("\n"); | |
| Con_Printf("%s\n", key_lines[edit_line]); | |
| edit_line = (edit_line + 1) & 31; | |
| history_line = edit_line; | |
| key_lines[edit_line][0] = ']'; | |
| key_linepos = 1; | |
| if (cls.state == ca_disconnected) | |
| SCR_UpdateScreen(); | |
| return; | |
| } | |
| if (key == K_TAB) | |
| { | |
| cmd = Cmd_CompleteCommand(key_lines[edit_line] + 1); | |
| if (!cmd) | |
| cmd = Cvar_CompleteVariable(key_lines[edit_line] + 1); | |
| if (cmd) | |
| { | |
| strcpy(key_lines[edit_line] + 1, cmd); | |
| key_linepos = strlen(cmd) + 1; | |
| key_lines[edit_line][key_linepos] = ' '; | |
| key_linepos++; | |
| key_lines[edit_line][key_linepos] = 0; | |
| return; | |
| } | |
| } | |
| if ((key == K_BACKSPACE) || (key == K_LEFTARROW)) | |
| { | |
| if (key_linepos > 1) | |
| key_linepos--; | |
| return; | |
| } | |
| if (key == K_UPARROW) | |
| { | |
| do | |
| { | |
| history_line = (history_line - 1) & 31; | |
| } | |
| while ((history_line != edit_line) && (!key_lines[history_line][1])); | |
| if (history_line == edit_line) | |
| history_line = (edit_line + 1) & 31; | |
| strcpy(key_lines[edit_line], key_lines[history_line]); | |
| key_linepos = strlen(key_lines[edit_line]); | |
| return; | |
| } | |
| if (key == K_DOWNARROW) | |
| { | |
| if (history_line == edit_line) | |
| return; | |
| do | |
| { | |
| history_line = (history_line + 1) & 31; | |
| } | |
| while ((history_line != edit_line) && (!key_lines[history_line][1])); | |
| if (history_line == edit_line) | |
| { | |
| key_lines[edit_line][0] = ']'; | |
| key_linepos = 1; | |
| } | |
| else | |
| { | |
| strcpy(key_lines[edit_line], key_lines[history_line]); | |
| key_linepos = strlen(key_lines[edit_line]); | |
| } | |
| return; | |
| } | |
| if ((key == K_PGUP) || (key == K_MWHEELUP)) | |
| { | |
| con_backscroll += 2; | |
| if (con_backscroll > ((con_totallines - (vid.height >> 3)) - 1)) | |
| con_backscroll = (con_totallines - (vid.height >> 3)) - 1; | |
| return; | |
| } | |
| if ((key == K_PGDN) || (key == K_MWHEELDOWN)) | |
| { | |
| con_backscroll -= 2; | |
| if (con_backscroll < 0) | |
| con_backscroll = 0; | |
| return; | |
| } | |
| if (key == K_HOME) | |
| { | |
| con_backscroll = (con_totallines - (vid.height >> 3)) - 1; | |
| return; | |
| } | |
| if (key == K_END) | |
| { | |
| con_backscroll = 0; | |
| return; | |
| } | |
| if ((key < 32) || (key > 127)) | |
| return; | |
| if (key_linepos < (MAXCMDLINE - 1)) | |
| { | |
| key_lines[edit_line][key_linepos] = key; | |
| key_linepos++; | |
| key_lines[edit_line][key_linepos] = 0; | |
| } | |
| } | |
| void Key_Message(int32_t key) | |
| { | |
| static int32_t chat_bufferlen = 0; | |
| if (key == K_ENTER) | |
| { | |
| if (team_message) | |
| Cbuf_AddText("say_team \""); | |
| else | |
| Cbuf_AddText("say \""); | |
| Cbuf_AddText(chat_buffer); | |
| Cbuf_AddText("\"\n"); | |
| key_dest = key_game; | |
| chat_bufferlen = 0; | |
| chat_buffer[0] = 0; | |
| return; | |
| } | |
| if (key == K_ESCAPE) | |
| { | |
| key_dest = key_game; | |
| chat_bufferlen = 0; | |
| chat_buffer[0] = 0; | |
| return; | |
| } | |
| if ((key < 32) || (key > 127)) | |
| return; | |
| if (key == K_BACKSPACE) | |
| { | |
| if (chat_bufferlen) | |
| { | |
| chat_bufferlen--; | |
| chat_buffer[chat_bufferlen] = 0; | |
| } | |
| return; | |
| } | |
| if (chat_bufferlen == 31) | |
| return; | |
| chat_buffer[chat_bufferlen++] = key; | |
| chat_buffer[chat_bufferlen] = 0; | |
| } | |
| int32_t Key_StringToKeynum(char *str) | |
| { | |
| keyname_t *kn; | |
| if ((!str) || (!str[0])) | |
| return -1; | |
| if (!str[1]) | |
| return str[0]; | |
| for (kn = keynames; kn->name; kn++) | |
| { | |
| if (!strcasecmp(str, kn->name)) | |
| return kn->keynum; | |
| } | |
| return -1; | |
| } | |
| char *Key_KeynumToString(int32_t keynum) | |
| { | |
| keyname_t *kn; | |
| static char tinystr[2]; | |
| if (keynum == (-1)) | |
| return "<KEY NOT FOUND>"; | |
| if ((keynum > 32) && (keynum < 127)) | |
| { | |
| tinystr[0] = keynum; | |
| tinystr[1] = 0; | |
| return tinystr; | |
| } | |
| for (kn = keynames; kn->name; kn++) | |
| if (keynum == kn->keynum) | |
| return kn->name; | |
| return "<UNKNOWN KEYNUM>"; | |
| } | |
| void Key_SetBinding(int32_t keynum, char *binding) | |
| { | |
| char *new; | |
| int32_t l; | |
| if (keynum == (-1)) | |
| return; | |
| if (keybindings[keynum]) | |
| { | |
| Z_Free(keybindings[keynum]); | |
| keybindings[keynum] = 0; | |
| } | |
| l = strlen(binding); | |
| new = Z_Malloc(l + 1); | |
| strcpy(new, binding); | |
| new[l] = 0; | |
| keybindings[keynum] = new; | |
| } | |
| void Key_Unbind_f(void) | |
| { | |
| int32_t b; | |
| if (Cmd_Argc() != 2) | |
| { | |
| Con_Printf("unbind <key> : remove commands from a key\n"); | |
| return; | |
| } | |
| b = Key_StringToKeynum(Cmd_Argv(1)); | |
| if (b == (-1)) | |
| { | |
| Con_Printf("\"%s\" isn't a valid key\n", Cmd_Argv(1)); | |
| return; | |
| } | |
| Key_SetBinding(b, ""); | |
| } | |
| void Key_Unbindall_f(void) | |
| { | |
| int32_t i; | |
| for (i = 0; i < 256; i++) | |
| if (keybindings[i]) | |
| Key_SetBinding(i, ""); | |
| } | |
| void Key_Bind_f(void) | |
| { | |
| int32_t i; | |
| int32_t c; | |
| int32_t b; | |
| char cmd[1024]; | |
| c = Cmd_Argc(); | |
| if ((c != 2) && (c != 3)) | |
| { | |
| Con_Printf("bind <key> [command] : attach a command to a key\n"); | |
| return; | |
| } | |
| b = Key_StringToKeynum(Cmd_Argv(1)); | |
| if (b == (-1)) | |
| { | |
| Con_Printf("\"%s\" isn't a valid key\n", Cmd_Argv(1)); | |
| return; | |
| } | |
| if (c == 2) | |
| { | |
| if (keybindings[b]) | |
| Con_Printf("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b]); | |
| else | |
| Con_Printf("\"%s\" is not bound\n", Cmd_Argv(1)); | |
| return; | |
| } | |
| cmd[0] = 0; | |
| for (i = 2; i < c; i++) | |
| { | |
| if (i > 2) | |
| strcat(cmd, " "); | |
| strcat(cmd, Cmd_Argv(i)); | |
| } | |
| Key_SetBinding(b, cmd); | |
| } | |
| void Key_WriteBindings(FILE *f) | |
| { | |
| int32_t i; | |
| for (i = 0; i < 256; i++) | |
| if (keybindings[i]) | |
| if (*keybindings[i]) | |
| fprintf(f, "bind \"%s\" \"%s\"\n", Key_KeynumToString(i), keybindings[i]); | |
| } | |
| void Key_Init(void) | |
| { | |
| int32_t i; | |
| for (i = 0; i < 32; i++) | |
| { | |
| key_lines[i][0] = ']'; | |
| key_lines[i][1] = 0; | |
| } | |
| key_linepos = 1; | |
| for (i = 32; i < 128; i++) | |
| consolekeys[i] = 1; | |
| consolekeys[K_ENTER] = 1; | |
| consolekeys[K_TAB] = 1; | |
| consolekeys[K_LEFTARROW] = 1; | |
| consolekeys[K_RIGHTARROW] = 1; | |
| consolekeys[K_UPARROW] = 1; | |
| consolekeys[K_DOWNARROW] = 1; | |
| consolekeys[K_BACKSPACE] = 1; | |
| consolekeys[K_PGUP] = 1; | |
| consolekeys[K_PGDN] = 1; | |
| consolekeys[K_SHIFT] = 1; | |
| consolekeys[K_MWHEELUP] = 1; | |
| consolekeys[K_MWHEELDOWN] = 1; | |
| consolekeys['`'] = 0; | |
| consolekeys['~'] = 0; | |
| for (i = 0; i < 256; i++) | |
| keyshift[i] = i; | |
| for (i = 'a'; i <= 'z'; i++) | |
| keyshift[i] = (i - 'a') + 'A'; | |
| keyshift['1'] = '!'; | |
| keyshift['2'] = '@'; | |
| keyshift['3'] = '#'; | |
| keyshift['4'] = '$'; | |
| keyshift['5'] = '%'; | |
| keyshift['6'] = '^'; | |
| keyshift['7'] = '&'; | |
| keyshift['8'] = '*'; | |
| keyshift['9'] = '('; | |
| keyshift['0'] = ')'; | |
| keyshift['-'] = '_'; | |
| keyshift['='] = '+'; | |
| keyshift[','] = '<'; | |
| keyshift['.'] = '>'; | |
| keyshift['/'] = '?'; | |
| keyshift[';'] = ':'; | |
| keyshift['\''] = '"'; | |
| keyshift['['] = '{'; | |
| keyshift[']'] = '}'; | |
| keyshift['`'] = '~'; | |
| keyshift['\\'] = '|'; | |
| menubound[K_ESCAPE] = 1; | |
| for (i = 0; i < 12; i++) | |
| menubound[K_F1 + i] = 1; | |
| Cmd_AddCommand("bind", Key_Bind_f); | |
| Cmd_AddCommand("unbind", Key_Unbind_f); | |
| Cmd_AddCommand("unbindall", Key_Unbindall_f); | |
| } | |
| void Key_Event(int32_t key, bool down) | |
| { | |
| char *kb; | |
| char cmd[1024]; | |
| keydown[key] = down; | |
| if (!down) | |
| key_repeats[key] = 0; | |
| key_lastpress = key; | |
| key_count++; | |
| if (key_count <= 0) | |
| { | |
| return; | |
| } | |
| if (down) | |
| { | |
| key_repeats[key]++; | |
| if (((key != K_BACKSPACE) && (key != K_PAUSE)) && (key_repeats[key] > 1)) | |
| { | |
| return; | |
| } | |
| if ((key >= 200) && (!keybindings[key])) | |
| Con_Printf("%s is unbound, hit F4 to set.\n", Key_KeynumToString(key)); | |
| } | |
| if (key == K_SHIFT) | |
| shift_down = down; | |
| if (key == K_ESCAPE) | |
| { | |
| if (!down) | |
| return; | |
| switch (key_dest) | |
| { | |
| case key_message: | |
| Key_Message(key); | |
| break; | |
| case key_menu: | |
| M_Keydown(key); | |
| break; | |
| case key_game: | |
| case key_console: | |
| M_ToggleMenu_f(); | |
| break; | |
| default: | |
| Sys_Error("Bad key_dest"); | |
| } | |
| return; | |
| } | |
| if (!down) | |
| { | |
| kb = keybindings[key]; | |
| if (kb && (kb[0] == '+')) | |
| { | |
| sprintf(cmd, "-%s %i\n", kb + 1, key); | |
| Cbuf_AddText(cmd); | |
| } | |
| if (keyshift[key] != key) | |
| { | |
| kb = keybindings[keyshift[key]]; | |
| if (kb && (kb[0] == '+')) | |
| { | |
| sprintf(cmd, "-%s %i\n", kb + 1, key); | |
| Cbuf_AddText(cmd); | |
| } | |
| } | |
| return; | |
| } | |
| if (((cls.demoplayback && down) && consolekeys[key]) && (key_dest == key_game)) | |
| { | |
| M_ToggleMenu_f(); | |
| return; | |
| } | |
| if ((((key_dest == key_menu) && menubound[key]) || ((key_dest == key_console) && (!consolekeys[key]))) || ((key_dest == key_game) && ((!con_forcedup) || (!consolekeys[key])))) | |
| { | |
| kb = keybindings[key]; | |
| if (kb) | |
| { | |
| if (kb[0] == '+') | |
| { | |
| sprintf(cmd, "%s %i\n", kb, key); | |
| Cbuf_AddText(cmd); | |
| } | |
| else | |
| { | |
| Cbuf_AddText(kb); | |
| Cbuf_AddText("\n"); | |
| } | |
| } | |
| return; | |
| } | |
| if (!down) | |
| return; | |
| if (shift_down) | |
| { | |
| key = keyshift[key]; | |
| } | |
| switch (key_dest) | |
| { | |
| case key_message: | |
| Key_Message(key); | |
| break; | |
| case key_menu: | |
| M_Keydown(key); | |
| break; | |
| case key_game: | |
| case key_console: | |
| Key_Console(key); | |
| break; | |
| default: | |
| Sys_Error("Bad key_dest"); | |
| } | |
| } | |
| void Key_ClearStates(void) | |
| { | |
| int32_t i; | |
| for (i = 0; i < 256; i++) | |
| { | |
| keydown[i] = 0; | |
| key_repeats[i] = 0; | |
| } | |
| } | |
| void ProjectPointOnPlane(vec3_t dst, const vec3_t p, const vec3_t normal) | |
| { | |
| float d; | |
| vec3_t n; | |
| float inv_denom; | |
| inv_denom = 1.0F / DotProduct(normal, normal); | |
| d = DotProduct(normal, p) * inv_denom; | |
| n[0] = normal[0] * inv_denom; | |
| n[1] = normal[1] * inv_denom; | |
| n[2] = normal[2] * inv_denom; | |
| dst[0] = p[0] - (d * n[0]); | |
| dst[1] = p[1] - (d * n[1]); | |
| dst[2] = p[2] - (d * n[2]); | |
| } | |
| void PerpendicularVector(vec3_t dst, const vec3_t src) | |
| { | |
| int32_t pos; | |
| int32_t i; | |
| float minelem = 1.0F; | |
| vec3_t tempvec; | |
| for (pos = 0, i = 0; i < 3; i++) | |
| { | |
| if (fabs(src[i]) < minelem) | |
| { | |
| pos = i; | |
| minelem = fabs(src[i]); | |
| } | |
| } | |
| tempvec[0] = (tempvec[1] = (tempvec[2] = 0.0F)); | |
| tempvec[pos] = 1.0F; | |
| ProjectPointOnPlane(dst, tempvec, src); | |
| VectorNormalize(dst); | |
| } | |
| void RotatePointAroundVector(vec3_t dst, const vec3_t dir, const vec3_t point, float degrees) | |
| { | |
| float m[3][3]; | |
| float im[3][3]; | |
| float zrot[3][3]; | |
| float tmpmat[3][3]; | |
| float rot[3][3]; | |
| int32_t i; | |
| vec3_t vr; | |
| vec3_t vup; | |
| vec3_t vf; | |
| vf[0] = dir[0]; | |
| vf[1] = dir[1]; | |
| vf[2] = dir[2]; | |
| PerpendicularVector(vr, dir); | |
| CrossProduct(vr, vf, vup); | |
| m[0][0] = vr[0]; | |
| m[1][0] = vr[1]; | |
| m[2][0] = vr[2]; | |
| m[0][1] = vup[0]; | |
| m[1][1] = vup[1]; | |
| m[2][1] = vup[2]; | |
| m[0][2] = vf[0]; | |
| m[1][2] = vf[1]; | |
| m[2][2] = vf[2]; | |
| memcpy(im, m, sizeof(im)); | |
| im[0][1] = m[1][0]; | |
| im[0][2] = m[2][0]; | |
| im[1][0] = m[0][1]; | |
| im[1][2] = m[2][1]; | |
| im[2][0] = m[0][2]; | |
| im[2][1] = m[1][2]; | |
| memset(zrot, 0, sizeof(zrot)); | |
| zrot[0][0] = (zrot[1][1] = (zrot[2][2] = 1.0F)); | |
| zrot[0][0] = cos(DEG2RAD(degrees)); | |
| zrot[0][1] = sin(DEG2RAD(degrees)); | |
| zrot[1][0] = -sin(DEG2RAD(degrees)); | |
| zrot[1][1] = cos(DEG2RAD(degrees)); | |
| R_ConcatRotations(m, zrot, tmpmat); | |
| R_ConcatRotations(tmpmat, im, rot); | |
| for (i = 0; i < 3; i++) | |
| { | |
| dst[i] = ((rot[i][0] * point[0]) + (rot[i][1] * point[1])) + (rot[i][2] * point[2]); | |
| } | |
| } | |
| float anglemod(float a) | |
| { | |
| a = (360.0 / 65536) * (((int32_t) (a * (65536 / 360.0))) & 65535); | |
| return a; | |
| } | |
| void BOPS_Error(void) | |
| { | |
| Sys_Error("BoxOnPlaneSide: Bad signbits"); | |
| } | |
| int32_t BoxOnPlaneSide(vec3_t emins, vec3_t emaxs, mplane_t *p) | |
| { | |
| float dist1; | |
| float dist2; | |
| int32_t sides; | |
| switch (p->signbits) | |
| { | |
| case 0: | |
| dist1 = ((p->normal[0] * emaxs[0]) + (p->normal[1] * emaxs[1])) + (p->normal[2] * emaxs[2]); | |
| dist2 = ((p->normal[0] * emins[0]) + (p->normal[1] * emins[1])) + (p->normal[2] * emins[2]); | |
| break; | |
| case 1: | |
| dist1 = ((p->normal[0] * emins[0]) + (p->normal[1] * emaxs[1])) + (p->normal[2] * emaxs[2]); | |
| dist2 = ((p->normal[0] * emaxs[0]) + (p->normal[1] * emins[1])) + (p->normal[2] * emins[2]); | |
| break; | |
| case 2: | |
| dist1 = ((p->normal[0] * emaxs[0]) + (p->normal[1] * emins[1])) + (p->normal[2] * emaxs[2]); | |
| dist2 = ((p->normal[0] * emins[0]) + (p->normal[1] * emaxs[1])) + (p->normal[2] * emins[2]); | |
| break; | |
| case 3: | |
| dist1 = ((p->normal[0] * emins[0]) + (p->normal[1] * emins[1])) + (p->normal[2] * emaxs[2]); | |
| dist2 = ((p->normal[0] * emaxs[0]) + (p->normal[1] * emaxs[1])) + (p->normal[2] * emins[2]); | |
| break; | |
| case 4: | |
| dist1 = ((p->normal[0] * emaxs[0]) + (p->normal[1] * emaxs[1])) + (p->normal[2] * emins[2]); | |
| dist2 = ((p->normal[0] * emins[0]) + (p->normal[1] * emins[1])) + (p->normal[2] * emaxs[2]); | |
| break; | |
| case 5: | |
| dist1 = ((p->normal[0] * emins[0]) + (p->normal[1] * emaxs[1])) + (p->normal[2] * emins[2]); | |
| dist2 = ((p->normal[0] * emaxs[0]) + (p->normal[1] * emins[1])) + (p->normal[2] * emaxs[2]); | |
| break; | |
| case 6: | |
| dist1 = ((p->normal[0] * emaxs[0]) + (p->normal[1] * emins[1])) + (p->normal[2] * emins[2]); | |
| dist2 = ((p->normal[0] * emins[0]) + (p->normal[1] * emaxs[1])) + (p->normal[2] * emaxs[2]); | |
| break; | |
| case 7: | |
| dist1 = ((p->normal[0] * emins[0]) + (p->normal[1] * emins[1])) + (p->normal[2] * emins[2]); | |
| dist2 = ((p->normal[0] * emaxs[0]) + (p->normal[1] * emaxs[1])) + (p->normal[2] * emaxs[2]); | |
| break; | |
| default: | |
| dist1 = (dist2 = 0); | |
| BOPS_Error(); | |
| break; | |
| } | |
| sides = 0; | |
| if (dist1 >= p->dist) | |
| sides = 1; | |
| if (dist2 < p->dist) | |
| sides |= 2; | |
| return sides; | |
| } | |
| void AngleVectors(vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) | |
| { | |
| float angle; | |
| float sr; | |
| float sp; | |
| float sy; | |
| float cr; | |
| float cp; | |
| float cy; | |
| angle = angles[YAW] * ((M_PI * 2) / 360); | |
| sy = sin(angle); | |
| cy = cos(angle); | |
| angle = angles[PITCH] * ((M_PI * 2) / 360); | |
| sp = sin(angle); | |
| cp = cos(angle); | |
| angle = angles[ROLL] * ((M_PI * 2) / 360); | |
| sr = sin(angle); | |
| cr = cos(angle); | |
| forward[0] = cp * cy; | |
| forward[1] = cp * sy; | |
| forward[2] = -sp; | |
| right[0] = ((((-1) * sr) * sp) * cy) + (((-1) * cr) * (-sy)); | |
| right[1] = ((((-1) * sr) * sp) * sy) + (((-1) * cr) * cy); | |
| right[2] = ((-1) * sr) * cp; | |
| up[0] = ((cr * sp) * cy) + ((-sr) * (-sy)); | |
| up[1] = ((cr * sp) * sy) + ((-sr) * cy); | |
| up[2] = cr * cp; | |
| } | |
| int32_t VectorCompare(vec3_t v1, vec3_t v2) | |
| { | |
| int32_t i; | |
| for (i = 0; i < 3; i++) | |
| if (v1[i] != v2[i]) | |
| return 0; | |
| return 1; | |
| } | |
| void VectorMA(vec3_t veca, float scale, vec3_t vecb, vec3_t vecc) | |
| { | |
| vecc[0] = veca[0] + (scale * vecb[0]); | |
| vecc[1] = veca[1] + (scale * vecb[1]); | |
| vecc[2] = veca[2] + (scale * vecb[2]); | |
| } | |
| vec_t _DotProduct(vec3_t v1, vec3_t v2) | |
| { | |
| return ((v1[0] * v2[0]) + (v1[1] * v2[1])) + (v1[2] * v2[2]); | |
| } | |
| void _VectorSubtract(vec3_t veca, vec3_t vecb, vec3_t out) | |
| { | |
| out[0] = veca[0] - vecb[0]; | |
| out[1] = veca[1] - vecb[1]; | |
| out[2] = veca[2] - vecb[2]; | |
| } | |
| void _VectorAdd(vec3_t veca, vec3_t vecb, vec3_t out) | |
| { | |
| out[0] = veca[0] + vecb[0]; | |
| out[1] = veca[1] + vecb[1]; | |
| out[2] = veca[2] + vecb[2]; | |
| } | |
| void _VectorCopy(vec3_t in, vec3_t out) | |
| { | |
| out[0] = in[0]; | |
| out[1] = in[1]; | |
| out[2] = in[2]; | |
| } | |
| void CrossProduct(vec3_t v1, vec3_t v2, vec3_t cross) | |
| { | |
| cross[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]); | |
| cross[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]); | |
| cross[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]); | |
| } | |
| vec_t Length(vec3_t v) | |
| { | |
| int32_t i; | |
| float length; | |
| length = 0; | |
| for (i = 0; i < 3; i++) | |
| length += v[i] * v[i]; | |
| length = sqrt(length); | |
| return length; | |
| } | |
| float VectorNormalize(vec3_t v) | |
| { | |
| float length; | |
| float ilength; | |
| length = ((v[0] * v[0]) + (v[1] * v[1])) + (v[2] * v[2]); | |
| length = sqrt(length); | |
| if (length) | |
| { | |
| ilength = 1 / length; | |
| v[0] *= ilength; | |
| v[1] *= ilength; | |
| v[2] *= ilength; | |
| } | |
| return length; | |
| } | |
| void VectorInverse(vec3_t v) | |
| { | |
| v[0] = -v[0]; | |
| v[1] = -v[1]; | |
| v[2] = -v[2]; | |
| } | |
| void VectorScale(vec3_t in, vec_t scale, vec3_t out) | |
| { | |
| out[0] = in[0] * scale; | |
| out[1] = in[1] * scale; | |
| out[2] = in[2] * scale; | |
| } | |
| int32_t Q_log2(int32_t val) | |
| { | |
| int32_t answer = 0; | |
| while (val >>= 1) | |
| answer++; | |
| return answer; | |
| } | |
| void R_ConcatRotations(float in1[3][3], float in2[3][3], float out[3][3]) | |
| { | |
| out[0][0] = ((in1[0][0] * in2[0][0]) + (in1[0][1] * in2[1][0])) + (in1[0][2] * in2[2][0]); | |
| out[0][1] = ((in1[0][0] * in2[0][1]) + (in1[0][1] * in2[1][1])) + (in1[0][2] * in2[2][1]); | |
| out[0][2] = ((in1[0][0] * in2[0][2]) + (in1[0][1] * in2[1][2])) + (in1[0][2] * in2[2][2]); | |
| out[1][0] = ((in1[1][0] * in2[0][0]) + (in1[1][1] * in2[1][0])) + (in1[1][2] * in2[2][0]); | |
| out[1][1] = ((in1[1][0] * in2[0][1]) + (in1[1][1] * in2[1][1])) + (in1[1][2] * in2[2][1]); | |
| out[1][2] = ((in1[1][0] * in2[0][2]) + (in1[1][1] * in2[1][2])) + (in1[1][2] * in2[2][2]); | |
| out[2][0] = ((in1[2][0] * in2[0][0]) + (in1[2][1] * in2[1][0])) + (in1[2][2] * in2[2][0]); | |
| out[2][1] = ((in1[2][0] * in2[0][1]) + (in1[2][1] * in2[1][1])) + (in1[2][2] * in2[2][1]); | |
| out[2][2] = ((in1[2][0] * in2[0][2]) + (in1[2][1] * in2[1][2])) + (in1[2][2] * in2[2][2]); | |
| } | |
| void R_ConcatTransforms(float in1[3][4], float in2[3][4], float out[3][4]) | |
| { | |
| out[0][0] = ((in1[0][0] * in2[0][0]) + (in1[0][1] * in2[1][0])) + (in1[0][2] * in2[2][0]); | |
| out[0][1] = ((in1[0][0] * in2[0][1]) + (in1[0][1] * in2[1][1])) + (in1[0][2] * in2[2][1]); | |
| out[0][2] = ((in1[0][0] * in2[0][2]) + (in1[0][1] * in2[1][2])) + (in1[0][2] * in2[2][2]); | |
| out[0][3] = (((in1[0][0] * in2[0][3]) + (in1[0][1] * in2[1][3])) + (in1[0][2] * in2[2][3])) + in1[0][3]; | |
| out[1][0] = ((in1[1][0] * in2[0][0]) + (in1[1][1] * in2[1][0])) + (in1[1][2] * in2[2][0]); | |
| out[1][1] = ((in1[1][0] * in2[0][1]) + (in1[1][1] * in2[1][1])) + (in1[1][2] * in2[2][1]); | |
| out[1][2] = ((in1[1][0] * in2[0][2]) + (in1[1][1] * in2[1][2])) + (in1[1][2] * in2[2][2]); | |
| out[1][3] = (((in1[1][0] * in2[0][3]) + (in1[1][1] * in2[1][3])) + (in1[1][2] * in2[2][3])) + in1[1][3]; | |
| out[2][0] = ((in1[2][0] * in2[0][0]) + (in1[2][1] * in2[1][0])) + (in1[2][2] * in2[2][0]); | |
| out[2][1] = ((in1[2][0] * in2[0][1]) + (in1[2][1] * in2[1][1])) + (in1[2][2] * in2[2][1]); | |
| out[2][2] = ((in1[2][0] * in2[0][2]) + (in1[2][1] * in2[1][2])) + (in1[2][2] * in2[2][2]); | |
| out[2][3] = (((in1[2][0] * in2[0][3]) + (in1[2][1] * in2[1][3])) + (in1[2][2] * in2[2][3])) + in1[2][3]; | |
| } | |
| void FloorDivMod(double numer, double denom, int32_t *quotient, int32_t *rem) | |
| { | |
| int32_t q; | |
| int32_t r; | |
| double x; | |
| if (denom <= 0.0) | |
| Sys_Error("FloorDivMod: bad denominator %d\n", denom); | |
| if (numer >= 0.0) | |
| { | |
| x = floor(numer / denom); | |
| q = (int32_t) x; | |
| r = (int32_t) floor(numer - (x * denom)); | |
| } | |
| else | |
| { | |
| x = floor((-numer) / denom); | |
| q = -((int32_t) x); | |
| r = (int32_t) floor((-numer) - (x * denom)); | |
| if (r != 0) | |
| { | |
| q--; | |
| r = ((int32_t) denom) - r; | |
| } | |
| } | |
| *quotient = q; | |
| *rem = r; | |
| } | |
| int32_t GreatestCommonDivisor(int32_t i1, int32_t i2) | |
| { | |
| if (i1 > i2) | |
| { | |
| if (i2 == 0) | |
| return i1; | |
| return GreatestCommonDivisor(i2, i1 % i2); | |
| } | |
| else | |
| { | |
| if (i1 == 0) | |
| return i2; | |
| return GreatestCommonDivisor(i1, i2 % i1); | |
| } | |
| } | |
| fixed16_t Invert24To16(fixed16_t val) | |
| { | |
| if (val < 256) | |
| return 0xFFFFFFFF; | |
| return (fixed16_t) (((((double) 0x10000) * ((double) 0x1000000)) / ((double) val)) + 0.5); | |
| } | |
| void M_DrawCharacter(int32_t cx, int32_t line, int32_t num) | |
| { | |
| Draw_Character(cx + ((vid.width - 320) >> 1), line, num); | |
| } | |
| void M_Print(int32_t cx, int32_t cy, char *str) | |
| { | |
| while (*str) | |
| { | |
| M_DrawCharacter(cx, cy, (*str) + 128); | |
| str++; | |
| cx += 8; | |
| } | |
| } | |
| void M_PrintWhite(int32_t cx, int32_t cy, char *str) | |
| { | |
| while (*str) | |
| { | |
| M_DrawCharacter(cx, cy, *str); | |
| str++; | |
| cx += 8; | |
| } | |
| } | |
| void M_DrawTransPic(int32_t x, int32_t y, qpic_t *pic) | |
| { | |
| Draw_TransPic(x + ((vid.width - 320) >> 1), y, pic); | |
| } | |
| void M_DrawPic(int32_t x, int32_t y, qpic_t *pic) | |
| { | |
| Draw_Pic(x + ((vid.width - 320) >> 1), y, pic); | |
| } | |
| void M_BuildTranslationTable(int32_t top, int32_t bottom) | |
| { | |
| int32_t j; | |
| uint8_t *dest; | |
| uint8_t *source; | |
| for (j = 0; j < 256; j++) | |
| identityTable[j] = j; | |
| dest = translationTable; | |
| source = identityTable; | |
| memcpy(dest, source, 256); | |
| if (top < 128) | |
| memcpy(dest + TOP_RANGE, source + top, 16); | |
| else | |
| for (j = 0; j < 16; j++) | |
| dest[TOP_RANGE + j] = source[(top + 15) - j]; | |
| if (bottom < 128) | |
| memcpy(dest + BOTTOM_RANGE, source + bottom, 16); | |
| else | |
| for (j = 0; j < 16; j++) | |
| dest[BOTTOM_RANGE + j] = source[(bottom + 15) - j]; | |
| } | |
| void M_DrawTransPicTranslate(int32_t x, int32_t y, qpic_t *pic) | |
| { | |
| Draw_TransPicTranslate(x + ((vid.width - 320) >> 1), y, pic, translationTable); | |
| } | |
| void M_DrawTextBox(int32_t x, int32_t y, int32_t width, int32_t lines) | |
| { | |
| qpic_t *p; | |
| int32_t cx; | |
| int32_t cy; | |
| int32_t n; | |
| cx = x; | |
| cy = y; | |
| p = Draw_CachePic("gfx/box_tl.lmp"); | |
| M_DrawTransPic(cx, cy, p); | |
| p = Draw_CachePic("gfx/box_ml.lmp"); | |
| for (n = 0; n < lines; n++) | |
| { | |
| cy += 8; | |
| M_DrawTransPic(cx, cy, p); | |
| } | |
| p = Draw_CachePic("gfx/box_bl.lmp"); | |
| M_DrawTransPic(cx, cy + 8, p); | |
| cx += 8; | |
| while (width > 0) | |
| { | |
| cy = y; | |
| p = Draw_CachePic("gfx/box_tm.lmp"); | |
| M_DrawTransPic(cx, cy, p); | |
| p = Draw_CachePic("gfx/box_mm.lmp"); | |
| for (n = 0; n < lines; n++) | |
| { | |
| cy += 8; | |
| if (n == 1) | |
| p = Draw_CachePic("gfx/box_mm2.lmp"); | |
| M_DrawTransPic(cx, cy, p); | |
| } | |
| p = Draw_CachePic("gfx/box_bm.lmp"); | |
| M_DrawTransPic(cx, cy + 8, p); | |
| width -= 2; | |
| cx += 16; | |
| } | |
| cy = y; | |
| p = Draw_CachePic("gfx/box_tr.lmp"); | |
| M_DrawTransPic(cx, cy, p); | |
| p = Draw_CachePic("gfx/box_mr.lmp"); | |
| for (n = 0; n < lines; n++) | |
| { | |
| cy += 8; | |
| M_DrawTransPic(cx, cy, p); | |
| } | |
| p = Draw_CachePic("gfx/box_br.lmp"); | |
| M_DrawTransPic(cx, cy + 8, p); | |
| } | |
| void M_ToggleMenu_f(void) | |
| { | |
| m_entersound = 1; | |
| if (key_dest == key_menu) | |
| { | |
| if (m_state != m_main) | |
| { | |
| M_Menu_Main_f(); | |
| return; | |
| } | |
| key_dest = key_game; | |
| m_state = m_none; | |
| return; | |
| } | |
| if (key_dest == key_console) | |
| { | |
| Con_ToggleConsole_f(); | |
| } | |
| else | |
| { | |
| M_Menu_Main_f(); | |
| } | |
| } | |
| void M_Menu_Main_f(void) | |
| { | |
| if (key_dest != key_menu) | |
| { | |
| m_save_demonum = cls.demonum; | |
| cls.demonum = -1; | |
| } | |
| key_dest = key_menu; | |
| m_state = m_main; | |
| m_entersound = 1; | |
| } | |
| void M_Main_Draw(void) | |
| { | |
| int32_t f; | |
| qpic_t *p; | |
| M_DrawTransPic(16, 4, Draw_CachePic("gfx/qplaque.lmp")); | |
| p = Draw_CachePic("gfx/ttl_main.lmp"); | |
| M_DrawPic((320 - p->width) / 2, 4, p); | |
| M_DrawTransPic(72, 32, Draw_CachePic("gfx/mainmenu.lmp")); | |
| f = ((int32_t) (host_time * 10)) % 6; | |
| M_DrawTransPic(54, 32 + (m_main_cursor * 20), Draw_CachePic(va("gfx/menudot%i.lmp", f + 1))); | |
| } | |
| void M_Main_Key(int32_t key) | |
| { | |
| switch (key) | |
| { | |
| case K_ESCAPE: | |
| key_dest = key_game; | |
| m_state = m_none; | |
| cls.demonum = m_save_demonum; | |
| if (((cls.demonum != (-1)) && (!cls.demoplayback)) && (cls.state != ca_connected)) | |
| CL_NextDemo(); | |
| break; | |
| case K_DOWNARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| if ((++m_main_cursor) >= MAIN_ITEMS) | |
| m_main_cursor = 0; | |
| break; | |
| case K_UPARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| if ((--m_main_cursor) < 0) | |
| m_main_cursor = MAIN_ITEMS - 1; | |
| break; | |
| case K_ENTER: | |
| m_entersound = 1; | |
| switch (m_main_cursor) | |
| { | |
| case 0: | |
| M_Menu_SinglePlayer_f(); | |
| break; | |
| case 1: | |
| M_Menu_MultiPlayer_f(); | |
| break; | |
| case 2: | |
| M_Menu_Options_f(); | |
| break; | |
| case 3: | |
| M_Menu_Help_f(); | |
| break; | |
| case 4: | |
| M_Menu_Quit_f(); | |
| break; | |
| } | |
| } | |
| } | |
| void M_Menu_SinglePlayer_f(void) | |
| { | |
| key_dest = key_menu; | |
| m_state = m_singleplayer; | |
| m_entersound = 1; | |
| } | |
| void M_SinglePlayer_Draw(void) | |
| { | |
| int32_t f; | |
| qpic_t *p; | |
| M_DrawTransPic(16, 4, Draw_CachePic("gfx/qplaque.lmp")); | |
| p = Draw_CachePic("gfx/ttl_sgl.lmp"); | |
| M_DrawPic((320 - p->width) / 2, 4, p); | |
| M_DrawTransPic(72, 32, Draw_CachePic("gfx/sp_menu.lmp")); | |
| f = ((int32_t) (host_time * 10)) % 6; | |
| M_DrawTransPic(54, 32 + (m_singleplayer_cursor * 20), Draw_CachePic(va("gfx/menudot%i.lmp", f + 1))); | |
| } | |
| void M_SinglePlayer_Key(int32_t key) | |
| { | |
| switch (key) | |
| { | |
| case K_ESCAPE: | |
| M_Menu_Main_f(); | |
| break; | |
| case K_DOWNARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| if ((++m_singleplayer_cursor) >= SINGLEPLAYER_ITEMS) | |
| m_singleplayer_cursor = 0; | |
| break; | |
| case K_UPARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| if ((--m_singleplayer_cursor) < 0) | |
| m_singleplayer_cursor = SINGLEPLAYER_ITEMS - 1; | |
| break; | |
| case K_ENTER: | |
| m_entersound = 1; | |
| switch (m_singleplayer_cursor) | |
| { | |
| case 0: | |
| if (sv.active) | |
| if (!SCR_ModalMessage("Are you sure you want to\nstart a new game?\n")) | |
| break; | |
| key_dest = key_game; | |
| if (sv.active) | |
| Cbuf_AddText("disconnect\n"); | |
| Cbuf_AddText("maxplayers 1\n"); | |
| Cbuf_AddText("map start\n"); | |
| break; | |
| case 1: | |
| M_Menu_Load_f(); | |
| break; | |
| case 2: | |
| M_Menu_Save_f(); | |
| break; | |
| } | |
| } | |
| } | |
| void M_ScanSaves(void) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| char name[MAX_OSPATH]; | |
| FILE *f; | |
| int32_t version; | |
| for (i = 0; i < MAX_SAVEGAMES; i++) | |
| { | |
| strcpy(m_filenames[i], "--- UNUSED SLOT ---"); | |
| loadable[i] = 0; | |
| sprintf(name, "%s/s%i.sav", com_gamedir, i); | |
| f = fopen(name, "r"); | |
| if (!f) | |
| continue; | |
| fscanf(f, "%i\n", &version); | |
| fscanf(f, "%79s\n", name); | |
| strncpy(m_filenames[i], name, (sizeof(m_filenames[i])) - 1); | |
| for (j = 0; j < SAVEGAME_COMMENT_LENGTH; j++) | |
| if (m_filenames[i][j] == '_') | |
| m_filenames[i][j] = ' '; | |
| loadable[i] = 1; | |
| fclose(f); | |
| } | |
| } | |
| void M_Menu_Load_f(void) | |
| { | |
| m_entersound = 1; | |
| m_state = m_load; | |
| key_dest = key_menu; | |
| M_ScanSaves(); | |
| } | |
| void M_Menu_Save_f(void) | |
| { | |
| if (!sv.active) | |
| return; | |
| if (cl.intermission) | |
| return; | |
| if (svs.maxclients != 1) | |
| return; | |
| m_entersound = 1; | |
| m_state = m_save; | |
| key_dest = key_menu; | |
| M_ScanSaves(); | |
| } | |
| void M_Load_Draw(void) | |
| { | |
| int32_t i; | |
| qpic_t *p; | |
| p = Draw_CachePic("gfx/p_load.lmp"); | |
| M_DrawPic((320 - p->width) / 2, 4, p); | |
| for (i = 0; i < MAX_SAVEGAMES; i++) | |
| M_Print(16, 32 + (8 * i), m_filenames[i]); | |
| M_DrawCharacter(8, 32 + (load_cursor * 8), 12 + (((int32_t) (realtime * 4)) & 1)); | |
| } | |
| void M_Save_Draw(void) | |
| { | |
| int32_t i; | |
| qpic_t *p; | |
| p = Draw_CachePic("gfx/p_save.lmp"); | |
| M_DrawPic((320 - p->width) / 2, 4, p); | |
| for (i = 0; i < MAX_SAVEGAMES; i++) | |
| M_Print(16, 32 + (8 * i), m_filenames[i]); | |
| M_DrawCharacter(8, 32 + (load_cursor * 8), 12 + (((int32_t) (realtime * 4)) & 1)); | |
| } | |
| void M_Load_Key(int32_t k) | |
| { | |
| switch (k) | |
| { | |
| case K_ESCAPE: | |
| M_Menu_SinglePlayer_f(); | |
| break; | |
| case K_ENTER: | |
| S_LocalSound("misc/menu2.wav"); | |
| if (!loadable[load_cursor]) | |
| return; | |
| m_state = m_none; | |
| key_dest = key_game; | |
| SCR_BeginLoadingPlaque(); | |
| Cbuf_AddText(va("load s%i\n", load_cursor)); | |
| return; | |
| case K_UPARROW: | |
| case K_LEFTARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| load_cursor--; | |
| if (load_cursor < 0) | |
| load_cursor = MAX_SAVEGAMES - 1; | |
| break; | |
| case K_DOWNARROW: | |
| case K_RIGHTARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| load_cursor++; | |
| if (load_cursor >= MAX_SAVEGAMES) | |
| load_cursor = 0; | |
| break; | |
| } | |
| } | |
| void M_Save_Key(int32_t k) | |
| { | |
| switch (k) | |
| { | |
| case K_ESCAPE: | |
| M_Menu_SinglePlayer_f(); | |
| break; | |
| case K_ENTER: | |
| m_state = m_none; | |
| key_dest = key_game; | |
| Cbuf_AddText(va("save s%i\n", load_cursor)); | |
| return; | |
| case K_UPARROW: | |
| case K_LEFTARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| load_cursor--; | |
| if (load_cursor < 0) | |
| load_cursor = MAX_SAVEGAMES - 1; | |
| break; | |
| case K_DOWNARROW: | |
| case K_RIGHTARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| load_cursor++; | |
| if (load_cursor >= MAX_SAVEGAMES) | |
| load_cursor = 0; | |
| break; | |
| } | |
| } | |
| void M_Menu_MultiPlayer_f(void) | |
| { | |
| key_dest = key_menu; | |
| m_state = m_multiplayer; | |
| m_entersound = 1; | |
| } | |
| void M_MultiPlayer_Draw(void) | |
| { | |
| int32_t f; | |
| qpic_t *p; | |
| M_DrawTransPic(16, 4, Draw_CachePic("gfx/qplaque.lmp")); | |
| p = Draw_CachePic("gfx/p_multi.lmp"); | |
| M_DrawPic((320 - p->width) / 2, 4, p); | |
| M_DrawTransPic(72, 32, Draw_CachePic("gfx/mp_menu.lmp")); | |
| f = ((int32_t) (host_time * 10)) % 6; | |
| M_DrawTransPic(54, 32 + (m_multiplayer_cursor * 20), Draw_CachePic(va("gfx/menudot%i.lmp", f + 1))); | |
| if ((serialAvailable || ipxAvailable) || tcpipAvailable) | |
| return; | |
| M_PrintWhite((320 / 2) - ((27 * 8) / 2), 148, "No Communications Available"); | |
| } | |
| void M_MultiPlayer_Key(int32_t key) | |
| { | |
| switch (key) | |
| { | |
| case K_ESCAPE: | |
| M_Menu_Main_f(); | |
| break; | |
| case K_DOWNARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| if ((++m_multiplayer_cursor) >= MULTIPLAYER_ITEMS) | |
| m_multiplayer_cursor = 0; | |
| break; | |
| case K_UPARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| if ((--m_multiplayer_cursor) < 0) | |
| m_multiplayer_cursor = MULTIPLAYER_ITEMS - 1; | |
| break; | |
| case K_ENTER: | |
| m_entersound = 1; | |
| switch (m_multiplayer_cursor) | |
| { | |
| case 0: | |
| if ((serialAvailable || ipxAvailable) || tcpipAvailable) | |
| M_Menu_Net_f(); | |
| break; | |
| case 1: | |
| if ((serialAvailable || ipxAvailable) || tcpipAvailable) | |
| M_Menu_Net_f(); | |
| break; | |
| case 2: | |
| M_Menu_Setup_f(); | |
| break; | |
| } | |
| } | |
| } | |
| void M_Menu_Setup_f(void) | |
| { | |
| key_dest = key_menu; | |
| m_state = m_setup; | |
| m_entersound = 1; | |
| strcpy(setup_myname, cl_name.string); | |
| strcpy(setup_hostname, hostname.string); | |
| setup_top = (setup_oldtop = ((int32_t) cl_color.value) >> 4); | |
| setup_bottom = (setup_oldbottom = ((int32_t) cl_color.value) & 15); | |
| } | |
| void M_Setup_Draw(void) | |
| { | |
| qpic_t *p; | |
| M_DrawTransPic(16, 4, Draw_CachePic("gfx/qplaque.lmp")); | |
| p = Draw_CachePic("gfx/p_multi.lmp"); | |
| M_DrawPic((320 - p->width) / 2, 4, p); | |
| M_Print(64, 40, "Hostname"); | |
| M_DrawTextBox(160, 32, 16, 1); | |
| M_Print(168, 40, setup_hostname); | |
| M_Print(64, 56, "Your name"); | |
| M_DrawTextBox(160, 48, 16, 1); | |
| M_Print(168, 56, setup_myname); | |
| M_Print(64, 80, "Shirt color"); | |
| M_Print(64, 104, "Pants color"); | |
| M_DrawTextBox(64, 140 - 8, 14, 1); | |
| M_Print(72, 140, "Accept Changes"); | |
| p = Draw_CachePic("gfx/bigbox.lmp"); | |
| M_DrawTransPic(160, 64, p); | |
| p = Draw_CachePic("gfx/menuplyr.lmp"); | |
| M_BuildTranslationTable(setup_top * 16, setup_bottom * 16); | |
| M_DrawTransPicTranslate(172, 72, p); | |
| M_DrawCharacter(56, setup_cursor_table[setup_cursor], 12 + (((int32_t) (realtime * 4)) & 1)); | |
| if (setup_cursor == 0) | |
| M_DrawCharacter(168 + (8 * strlen(setup_hostname)), setup_cursor_table[setup_cursor], 10 + (((int32_t) (realtime * 4)) & 1)); | |
| if (setup_cursor == 1) | |
| M_DrawCharacter(168 + (8 * strlen(setup_myname)), setup_cursor_table[setup_cursor], 10 + (((int32_t) (realtime * 4)) & 1)); | |
| } | |
| void M_Setup_Key(int32_t k) | |
| { | |
| int32_t l; | |
| switch (k) | |
| { | |
| case K_ESCAPE: | |
| M_Menu_MultiPlayer_f(); | |
| break; | |
| case K_UPARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| setup_cursor--; | |
| if (setup_cursor < 0) | |
| setup_cursor = NUM_SETUP_CMDS - 1; | |
| break; | |
| case K_DOWNARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| setup_cursor++; | |
| if (setup_cursor >= NUM_SETUP_CMDS) | |
| setup_cursor = 0; | |
| break; | |
| case K_LEFTARROW: | |
| if (setup_cursor < 2) | |
| return; | |
| S_LocalSound("misc/menu3.wav"); | |
| if (setup_cursor == 2) | |
| setup_top = setup_top - 1; | |
| if (setup_cursor == 3) | |
| setup_bottom = setup_bottom - 1; | |
| break; | |
| case K_RIGHTARROW: | |
| if (setup_cursor < 2) | |
| return; | |
| forward: | |
| S_LocalSound("misc/menu3.wav"); | |
| if (setup_cursor == 2) | |
| setup_top = setup_top + 1; | |
| if (setup_cursor == 3) | |
| setup_bottom = setup_bottom + 1; | |
| break; | |
| case K_ENTER: | |
| if ((setup_cursor == 0) || (setup_cursor == 1)) | |
| return; | |
| if ((setup_cursor == 2) || (setup_cursor == 3)) | |
| goto forward; | |
| if (strcmp(cl_name.string, setup_myname) != 0) | |
| Cbuf_AddText(va("name \"%s\"\n", setup_myname)); | |
| if (strcmp(hostname.string, setup_hostname) != 0) | |
| Cvar_Set("hostname", setup_hostname); | |
| if ((setup_top != setup_oldtop) || (setup_bottom != setup_oldbottom)) | |
| Cbuf_AddText(va("color %i %i\n", setup_top, setup_bottom)); | |
| m_entersound = 1; | |
| M_Menu_MultiPlayer_f(); | |
| break; | |
| case K_BACKSPACE: | |
| if (setup_cursor == 0) | |
| { | |
| if (strlen(setup_hostname)) | |
| setup_hostname[strlen(setup_hostname) - 1] = 0; | |
| } | |
| if (setup_cursor == 1) | |
| { | |
| if (strlen(setup_myname)) | |
| setup_myname[strlen(setup_myname) - 1] = 0; | |
| } | |
| break; | |
| default: | |
| if ((k < 32) || (k > 127)) | |
| break; | |
| if (setup_cursor == 0) | |
| { | |
| l = strlen(setup_hostname); | |
| if (l < 15) | |
| { | |
| setup_hostname[l + 1] = 0; | |
| setup_hostname[l] = k; | |
| } | |
| } | |
| if (setup_cursor == 1) | |
| { | |
| l = strlen(setup_myname); | |
| if (l < 15) | |
| { | |
| setup_myname[l + 1] = 0; | |
| setup_myname[l] = k; | |
| } | |
| } | |
| } | |
| if (setup_top > 13) | |
| setup_top = 0; | |
| if (setup_top < 0) | |
| setup_top = 13; | |
| if (setup_bottom > 13) | |
| setup_bottom = 0; | |
| if (setup_bottom < 0) | |
| setup_bottom = 13; | |
| } | |
| void M_Menu_Net_f(void) | |
| { | |
| key_dest = key_menu; | |
| m_state = m_net; | |
| m_entersound = 1; | |
| m_net_items = 4; | |
| if (m_net_cursor >= m_net_items) | |
| m_net_cursor = 0; | |
| m_net_cursor--; | |
| M_Net_Key(K_DOWNARROW); | |
| } | |
| void M_Net_Draw(void) | |
| { | |
| int32_t f; | |
| qpic_t *p; | |
| M_DrawTransPic(16, 4, Draw_CachePic("gfx/qplaque.lmp")); | |
| p = Draw_CachePic("gfx/p_multi.lmp"); | |
| M_DrawPic((320 - p->width) / 2, 4, p); | |
| f = 32; | |
| if (serialAvailable) | |
| { | |
| p = Draw_CachePic("gfx/netmen1.lmp"); | |
| } | |
| else | |
| { | |
| p = Draw_CachePic("gfx/dim_modm.lmp"); | |
| } | |
| if (p) | |
| M_DrawTransPic(72, f, p); | |
| f += 19; | |
| if (serialAvailable) | |
| { | |
| p = Draw_CachePic("gfx/netmen2.lmp"); | |
| } | |
| else | |
| { | |
| p = Draw_CachePic("gfx/dim_drct.lmp"); | |
| } | |
| if (p) | |
| M_DrawTransPic(72, f, p); | |
| f += 19; | |
| if (ipxAvailable) | |
| p = Draw_CachePic("gfx/netmen3.lmp"); | |
| else | |
| p = Draw_CachePic("gfx/dim_ipx.lmp"); | |
| M_DrawTransPic(72, f, p); | |
| f += 19; | |
| if (tcpipAvailable) | |
| p = Draw_CachePic("gfx/netmen4.lmp"); | |
| else | |
| p = Draw_CachePic("gfx/dim_tcp.lmp"); | |
| M_DrawTransPic(72, f, p); | |
| if (m_net_items == 5) | |
| { | |
| f += 19; | |
| p = Draw_CachePic("gfx/netmen5.lmp"); | |
| M_DrawTransPic(72, f, p); | |
| } | |
| f = (320 - (26 * 8)) / 2; | |
| M_DrawTextBox(f, 134, 24, 4); | |
| f += 8; | |
| M_Print(f, 142, net_helpMessage[(m_net_cursor * 4) + 0]); | |
| M_Print(f, 150, net_helpMessage[(m_net_cursor * 4) + 1]); | |
| M_Print(f, 158, net_helpMessage[(m_net_cursor * 4) + 2]); | |
| M_Print(f, 166, net_helpMessage[(m_net_cursor * 4) + 3]); | |
| f = ((int32_t) (host_time * 10)) % 6; | |
| M_DrawTransPic(54, 32 + (m_net_cursor * 20), Draw_CachePic(va("gfx/menudot%i.lmp", f + 1))); | |
| } | |
| void M_Net_Key(int32_t k) | |
| { | |
| again: | |
| switch (k) | |
| { | |
| case K_ESCAPE: | |
| M_Menu_MultiPlayer_f(); | |
| break; | |
| case K_DOWNARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| if ((++m_net_cursor) >= m_net_items) | |
| m_net_cursor = 0; | |
| break; | |
| case K_UPARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| if ((--m_net_cursor) < 0) | |
| m_net_cursor = m_net_items - 1; | |
| break; | |
| case K_ENTER: | |
| m_entersound = 1; | |
| switch (m_net_cursor) | |
| { | |
| case 0: | |
| M_Menu_SerialConfig_f(); | |
| break; | |
| case 1: | |
| M_Menu_SerialConfig_f(); | |
| break; | |
| case 2: | |
| M_Menu_LanConfig_f(); | |
| break; | |
| case 3: | |
| M_Menu_LanConfig_f(); | |
| break; | |
| case 4: | |
| break; | |
| } | |
| } | |
| if ((m_net_cursor == 0) && (!serialAvailable)) | |
| goto again; | |
| if ((m_net_cursor == 1) && (!serialAvailable)) | |
| goto again; | |
| if ((m_net_cursor == 2) && (!ipxAvailable)) | |
| goto again; | |
| if ((m_net_cursor == 3) && (!tcpipAvailable)) | |
| goto again; | |
| } | |
| void M_Menu_Options_f(void) | |
| { | |
| key_dest = key_menu; | |
| m_state = m_options; | |
| m_entersound = 1; | |
| } | |
| void M_AdjustSliders(int32_t dir) | |
| { | |
| S_LocalSound("misc/menu3.wav"); | |
| switch (options_cursor) | |
| { | |
| case 3: | |
| scr_viewsize.value += dir * 10; | |
| if (scr_viewsize.value < 30) | |
| scr_viewsize.value = 30; | |
| if (scr_viewsize.value > 120) | |
| scr_viewsize.value = 120; | |
| Cvar_SetValue("viewsize", scr_viewsize.value); | |
| break; | |
| case 4: | |
| v_gamma.value -= dir * 0.05; | |
| if (v_gamma.value < 0.5) | |
| v_gamma.value = 0.5; | |
| if (v_gamma.value > 1) | |
| v_gamma.value = 1; | |
| Cvar_SetValue("gamma", v_gamma.value); | |
| break; | |
| case 5: | |
| sensitivity.value += dir * 0.5; | |
| if (sensitivity.value < 1) | |
| sensitivity.value = 1; | |
| if (sensitivity.value > 11) | |
| sensitivity.value = 11; | |
| Cvar_SetValue("sensitivity", sensitivity.value); | |
| break; | |
| case 6: | |
| bgmvolume.value += dir * 0.1; | |
| if (bgmvolume.value < 0) | |
| bgmvolume.value = 0; | |
| if (bgmvolume.value > 1) | |
| bgmvolume.value = 1; | |
| Cvar_SetValue("bgmvolume", bgmvolume.value); | |
| break; | |
| case 7: | |
| volume.value += dir * 0.1; | |
| if (volume.value < 0) | |
| volume.value = 0; | |
| if (volume.value > 1) | |
| volume.value = 1; | |
| Cvar_SetValue("volume", volume.value); | |
| break; | |
| case 8: | |
| if (cl_forwardspeed.value > 200) | |
| { | |
| Cvar_SetValue("cl_forwardspeed", 200); | |
| Cvar_SetValue("cl_backspeed", 200); | |
| } | |
| else | |
| { | |
| Cvar_SetValue("cl_forwardspeed", 400); | |
| Cvar_SetValue("cl_backspeed", 400); | |
| } | |
| break; | |
| case 9: | |
| Cvar_SetValue("m_pitch", -m_pitch.value); | |
| break; | |
| case 10: | |
| Cvar_SetValue("lookspring", !lookspring.value); | |
| break; | |
| case 11: | |
| Cvar_SetValue("lookstrafe", !lookstrafe.value); | |
| break; | |
| } | |
| } | |
| void M_DrawSlider(int32_t x, int32_t y, float range) | |
| { | |
| int32_t i; | |
| if (range < 0) | |
| range = 0; | |
| if (range > 1) | |
| range = 1; | |
| M_DrawCharacter(x - 8, y, 128); | |
| for (i = 0; i < SLIDER_RANGE; i++) | |
| M_DrawCharacter(x + (i * 8), y, 129); | |
| M_DrawCharacter(x + (i * 8), y, 130); | |
| M_DrawCharacter(x + (((SLIDER_RANGE - 1) * 8) * range), y, 131); | |
| } | |
| void M_DrawCheckbox(int32_t x, int32_t y, int32_t on) | |
| { | |
| if (on) | |
| M_Print(x, y, "on"); | |
| else | |
| M_Print(x, y, "off"); | |
| } | |
| void M_Options_Draw(void) | |
| { | |
| float r; | |
| qpic_t *p; | |
| M_DrawTransPic(16, 4, Draw_CachePic("gfx/qplaque.lmp")); | |
| p = Draw_CachePic("gfx/p_option.lmp"); | |
| M_DrawPic((320 - p->width) / 2, 4, p); | |
| M_Print(16, 32, " Customize controls"); | |
| M_Print(16, 40, " Go to console"); | |
| M_Print(16, 48, " Reset to defaults"); | |
| M_Print(16, 56, " Screen size"); | |
| r = (scr_viewsize.value - 30) / (120 - 30); | |
| M_DrawSlider(220, 56, r); | |
| M_Print(16, 64, " Brightness"); | |
| r = (1.0 - v_gamma.value) / 0.5; | |
| M_DrawSlider(220, 64, r); | |
| M_Print(16, 72, " Mouse Speed"); | |
| r = (sensitivity.value - 1) / 10; | |
| M_DrawSlider(220, 72, r); | |
| M_Print(16, 80, " Music Volume"); | |
| r = bgmvolume.value; | |
| M_DrawSlider(220, 80, r); | |
| M_Print(16, 88, " Sound Volume"); | |
| r = volume.value; | |
| M_DrawSlider(220, 88, r); | |
| M_Print(16, 96, " Always Run"); | |
| M_DrawCheckbox(220, 96, cl_forwardspeed.value > 200); | |
| M_Print(16, 104, " Invert Mouse"); | |
| M_DrawCheckbox(220, 104, m_pitch.value < 0); | |
| M_Print(16, 112, " Lookspring"); | |
| M_DrawCheckbox(220, 112, lookspring.value); | |
| M_Print(16, 120, " Lookstrafe"); | |
| M_DrawCheckbox(220, 120, lookstrafe.value); | |
| if (vid_menudrawfn) | |
| M_Print(16, 128, " Video Options"); | |
| M_DrawCharacter(200, 32 + (options_cursor * 8), 12 + (((int32_t) (realtime * 4)) & 1)); | |
| } | |
| void M_Options_Key(int32_t k) | |
| { | |
| switch (k) | |
| { | |
| case K_ESCAPE: | |
| M_Menu_Main_f(); | |
| break; | |
| case K_ENTER: | |
| m_entersound = 1; | |
| switch (options_cursor) | |
| { | |
| case 0: | |
| M_Menu_Keys_f(); | |
| break; | |
| case 1: | |
| m_state = m_none; | |
| Con_ToggleConsole_f(); | |
| break; | |
| case 2: | |
| Cbuf_AddText("exec default.cfg\n"); | |
| break; | |
| case 12: | |
| M_Menu_Video_f(); | |
| break; | |
| default: | |
| M_AdjustSliders(1); | |
| break; | |
| } | |
| return; | |
| case K_UPARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| options_cursor--; | |
| if (options_cursor < 0) | |
| options_cursor = OPTIONS_ITEMS - 1; | |
| break; | |
| case K_DOWNARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| options_cursor++; | |
| if (options_cursor >= OPTIONS_ITEMS) | |
| options_cursor = 0; | |
| break; | |
| case K_LEFTARROW: | |
| M_AdjustSliders(-1); | |
| break; | |
| case K_RIGHTARROW: | |
| M_AdjustSliders(1); | |
| break; | |
| } | |
| if ((options_cursor == 12) && (vid_menudrawfn == 0)) | |
| { | |
| if (k == K_UPARROW) | |
| options_cursor = 11; | |
| else | |
| options_cursor = 0; | |
| } | |
| } | |
| void M_Menu_Keys_f(void) | |
| { | |
| key_dest = key_menu; | |
| m_state = m_keys; | |
| m_entersound = 1; | |
| } | |
| void M_FindKeysForCommand(char *command, int32_t *twokeys) | |
| { | |
| int32_t count; | |
| int32_t j; | |
| int32_t l; | |
| char *b; | |
| twokeys[0] = (twokeys[1] = -1); | |
| l = strlen(command); | |
| count = 0; | |
| for (j = 0; j < 256; j++) | |
| { | |
| b = keybindings[j]; | |
| if (!b) | |
| continue; | |
| if (!strncmp(b, command, l)) | |
| { | |
| twokeys[count] = j; | |
| count++; | |
| if (count == 2) | |
| break; | |
| } | |
| } | |
| } | |
| void M_UnbindCommand(char *command) | |
| { | |
| int32_t j; | |
| int32_t l; | |
| char *b; | |
| l = strlen(command); | |
| for (j = 0; j < 256; j++) | |
| { | |
| b = keybindings[j]; | |
| if (!b) | |
| continue; | |
| if (!strncmp(b, command, l)) | |
| Key_SetBinding(j, ""); | |
| } | |
| } | |
| void M_Keys_Draw(void) | |
| { | |
| int32_t i; | |
| int32_t l; | |
| int32_t keys[2]; | |
| char *name; | |
| int32_t x; | |
| int32_t y; | |
| qpic_t *p; | |
| p = Draw_CachePic("gfx/ttl_cstm.lmp"); | |
| M_DrawPic((320 - p->width) / 2, 4, p); | |
| if (bind_grab) | |
| M_Print(12, 32, "Press a key or button for this action"); | |
| else | |
| M_Print(18, 32, "Enter to change, backspace to clear"); | |
| for (i = 0; i < NUMCOMMANDS; i++) | |
| { | |
| y = 48 + (8 * i); | |
| M_Print(16, y, bindnames[i][1]); | |
| l = strlen(bindnames[i][0]); | |
| M_FindKeysForCommand(bindnames[i][0], keys); | |
| if (keys[0] == (-1)) | |
| { | |
| M_Print(140, y, "???"); | |
| } | |
| else | |
| { | |
| name = Key_KeynumToString(keys[0]); | |
| M_Print(140, y, name); | |
| x = strlen(name) * 8; | |
| if (keys[1] != (-1)) | |
| { | |
| M_Print((140 + x) + 8, y, "or"); | |
| M_Print((140 + x) + 32, y, Key_KeynumToString(keys[1])); | |
| } | |
| } | |
| } | |
| if (bind_grab) | |
| M_DrawCharacter(130, 48 + (keys_cursor * 8), '='); | |
| else | |
| M_DrawCharacter(130, 48 + (keys_cursor * 8), 12 + (((int32_t) (realtime * 4)) & 1)); | |
| } | |
| void M_Keys_Key(int32_t k) | |
| { | |
| char cmd[80]; | |
| int32_t keys[2]; | |
| if (bind_grab) | |
| { | |
| S_LocalSound("misc/menu1.wav"); | |
| if (k == K_ESCAPE) | |
| { | |
| bind_grab = 0; | |
| } | |
| else | |
| if (k != '`') | |
| { | |
| sprintf(cmd, "bind \"%s\" \"%s\"\n", Key_KeynumToString(k), bindnames[keys_cursor][0]); | |
| Cbuf_InsertText(cmd); | |
| } | |
| bind_grab = 0; | |
| return; | |
| } | |
| switch (k) | |
| { | |
| case K_ESCAPE: | |
| M_Menu_Options_f(); | |
| break; | |
| case K_LEFTARROW: | |
| case K_UPARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| keys_cursor--; | |
| if (keys_cursor < 0) | |
| keys_cursor = NUMCOMMANDS - 1; | |
| break; | |
| case K_DOWNARROW: | |
| case K_RIGHTARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| keys_cursor++; | |
| if (keys_cursor >= NUMCOMMANDS) | |
| keys_cursor = 0; | |
| break; | |
| case K_ENTER: | |
| M_FindKeysForCommand(bindnames[keys_cursor][0], keys); | |
| S_LocalSound("misc/menu2.wav"); | |
| if (keys[1] != (-1)) | |
| M_UnbindCommand(bindnames[keys_cursor][0]); | |
| bind_grab = 1; | |
| break; | |
| case K_BACKSPACE: | |
| case K_DEL: | |
| S_LocalSound("misc/menu2.wav"); | |
| M_UnbindCommand(bindnames[keys_cursor][0]); | |
| break; | |
| } | |
| } | |
| void M_Menu_Video_f(void) | |
| { | |
| key_dest = key_menu; | |
| m_state = m_video; | |
| m_entersound = 1; | |
| } | |
| void M_Video_Draw(void) | |
| { | |
| (*vid_menudrawfn)(); | |
| } | |
| void M_Video_Key(int32_t key) | |
| { | |
| (*vid_menukeyfn)(key); | |
| } | |
| void M_Menu_Help_f(void) | |
| { | |
| key_dest = key_menu; | |
| m_state = m_help; | |
| m_entersound = 1; | |
| help_page = 0; | |
| } | |
| void M_Help_Draw(void) | |
| { | |
| M_DrawPic(0, 0, Draw_CachePic(va("gfx/help%i.lmp", help_page))); | |
| } | |
| void M_Help_Key(int32_t key) | |
| { | |
| switch (key) | |
| { | |
| case K_ESCAPE: | |
| M_Menu_Main_f(); | |
| break; | |
| case K_UPARROW: | |
| case K_RIGHTARROW: | |
| m_entersound = 1; | |
| if ((++help_page) >= NUM_HELP_PAGES) | |
| help_page = 0; | |
| break; | |
| case K_DOWNARROW: | |
| case K_LEFTARROW: | |
| m_entersound = 1; | |
| if ((--help_page) < 0) | |
| help_page = NUM_HELP_PAGES - 1; | |
| break; | |
| } | |
| } | |
| void M_Menu_Quit_f(void) | |
| { | |
| if (m_state == m_quit) | |
| return; | |
| wasInMenus = key_dest == key_menu; | |
| key_dest = key_menu; | |
| m_quit_prevstate = m_state; | |
| m_state = m_quit; | |
| m_entersound = 1; | |
| msgNumber = rand() & 7; | |
| } | |
| void M_Quit_Key(int32_t key) | |
| { | |
| switch (key) | |
| { | |
| case K_ESCAPE: | |
| case 'n': | |
| case 'N': | |
| if (wasInMenus) | |
| { | |
| m_state = m_quit_prevstate; | |
| m_entersound = 1; | |
| } | |
| else | |
| { | |
| key_dest = key_game; | |
| m_state = m_none; | |
| } | |
| break; | |
| case 'Y': | |
| case 'y': | |
| key_dest = key_console; | |
| Host_Quit_f(); | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| void M_Quit_Draw(void) | |
| { | |
| if (wasInMenus) | |
| { | |
| m_state = m_quit_prevstate; | |
| m_recursiveDraw = 1; | |
| M_Draw(); | |
| m_state = m_quit; | |
| } | |
| M_DrawTextBox(56, 76, 24, 4); | |
| M_Print(64, 84, quitMessage[(msgNumber * 4) + 0]); | |
| M_Print(64, 92, quitMessage[(msgNumber * 4) + 1]); | |
| M_Print(64, 100, quitMessage[(msgNumber * 4) + 2]); | |
| M_Print(64, 108, quitMessage[(msgNumber * 4) + 3]); | |
| } | |
| void M_Menu_SerialConfig_f(void) | |
| { | |
| int32_t n; | |
| int32_t port; | |
| int32_t baudrate; | |
| bool useModem; | |
| key_dest = key_menu; | |
| m_state = m_serialconfig; | |
| m_entersound = 1; | |
| if (JoiningGame && SerialConfig) | |
| serialConfig_cursor = 4; | |
| else | |
| serialConfig_cursor = 5; | |
| (*GetComPortConfig)(0, &port, &serialConfig_irq, &baudrate, &useModem); | |
| for (n = 0; n < 4; n++) | |
| if (ISA_uarts[n] == port) | |
| break; | |
| if (n == 4) | |
| { | |
| n = 0; | |
| serialConfig_irq = 4; | |
| } | |
| serialConfig_comport = n + 1; | |
| for (n = 0; n < 6; n++) | |
| if (serialConfig_baudrate[n] == baudrate) | |
| break; | |
| if (n == 6) | |
| n = 5; | |
| serialConfig_baud = n; | |
| m_return_onerror = 0; | |
| m_return_reason[0] = 0; | |
| } | |
| void M_SerialConfig_Draw(void) | |
| { | |
| qpic_t *p; | |
| int32_t basex; | |
| char *startJoin; | |
| char *directModem; | |
| M_DrawTransPic(16, 4, Draw_CachePic("gfx/qplaque.lmp")); | |
| p = Draw_CachePic("gfx/p_multi.lmp"); | |
| basex = (320 - p->width) / 2; | |
| M_DrawPic(basex, 4, p); | |
| if (StartingGame) | |
| startJoin = "New Game"; | |
| else | |
| startJoin = "Join Game"; | |
| if (SerialConfig) | |
| directModem = "Modem"; | |
| else | |
| directModem = "Direct Connect"; | |
| M_Print(basex, 32, va("%s - %s", startJoin, directModem)); | |
| basex += 8; | |
| M_Print(basex, serialConfig_cursor_table[0], "Port"); | |
| M_DrawTextBox(160, 40, 4, 1); | |
| M_Print(168, serialConfig_cursor_table[0], va("COM%u", serialConfig_comport)); | |
| M_Print(basex, serialConfig_cursor_table[1], "IRQ"); | |
| M_DrawTextBox(160, serialConfig_cursor_table[1] - 8, 1, 1); | |
| M_Print(168, serialConfig_cursor_table[1], va("%u", serialConfig_irq)); | |
| M_Print(basex, serialConfig_cursor_table[2], "Baud"); | |
| M_DrawTextBox(160, serialConfig_cursor_table[2] - 8, 5, 1); | |
| M_Print(168, serialConfig_cursor_table[2], va("%u", serialConfig_baudrate[serialConfig_baud])); | |
| if (SerialConfig) | |
| { | |
| M_Print(basex, serialConfig_cursor_table[3], "Modem Setup..."); | |
| if (JoiningGame) | |
| { | |
| M_Print(basex, serialConfig_cursor_table[4], "Phone number"); | |
| M_DrawTextBox(160, serialConfig_cursor_table[4] - 8, 16, 1); | |
| M_Print(168, serialConfig_cursor_table[4], serialConfig_phone); | |
| } | |
| } | |
| if (JoiningGame) | |
| { | |
| M_DrawTextBox(basex, serialConfig_cursor_table[5] - 8, 7, 1); | |
| M_Print(basex + 8, serialConfig_cursor_table[5], "Connect"); | |
| } | |
| else | |
| { | |
| M_DrawTextBox(basex, serialConfig_cursor_table[5] - 8, 2, 1); | |
| M_Print(basex + 8, serialConfig_cursor_table[5], "OK"); | |
| } | |
| M_DrawCharacter(basex - 8, serialConfig_cursor_table[serialConfig_cursor], 12 + (((int32_t) (realtime * 4)) & 1)); | |
| if (serialConfig_cursor == 4) | |
| M_DrawCharacter(168 + (8 * strlen(serialConfig_phone)), serialConfig_cursor_table[serialConfig_cursor], 10 + (((int32_t) (realtime * 4)) & 1)); | |
| if (*m_return_reason) | |
| M_PrintWhite(basex, 148, m_return_reason); | |
| } | |
| void M_SerialConfig_Key(int32_t key) | |
| { | |
| int32_t l; | |
| switch (key) | |
| { | |
| case K_ESCAPE: | |
| M_Menu_Net_f(); | |
| break; | |
| case K_UPARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| serialConfig_cursor--; | |
| if (serialConfig_cursor < 0) | |
| serialConfig_cursor = NUM_SERIALCONFIG_CMDS - 1; | |
| break; | |
| case K_DOWNARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| serialConfig_cursor++; | |
| if (serialConfig_cursor >= NUM_SERIALCONFIG_CMDS) | |
| serialConfig_cursor = 0; | |
| break; | |
| case K_LEFTARROW: | |
| if (serialConfig_cursor > 2) | |
| break; | |
| S_LocalSound("misc/menu3.wav"); | |
| if (serialConfig_cursor == 0) | |
| { | |
| serialConfig_comport--; | |
| if (serialConfig_comport == 0) | |
| serialConfig_comport = 4; | |
| serialConfig_irq = ISA_IRQs[serialConfig_comport - 1]; | |
| } | |
| if (serialConfig_cursor == 1) | |
| { | |
| serialConfig_irq--; | |
| if (serialConfig_irq == 6) | |
| serialConfig_irq = 5; | |
| if (serialConfig_irq == 1) | |
| serialConfig_irq = 7; | |
| } | |
| if (serialConfig_cursor == 2) | |
| { | |
| serialConfig_baud--; | |
| if (serialConfig_baud < 0) | |
| serialConfig_baud = 5; | |
| } | |
| break; | |
| case K_RIGHTARROW: | |
| if (serialConfig_cursor > 2) | |
| break; | |
| forward: | |
| S_LocalSound("misc/menu3.wav"); | |
| if (serialConfig_cursor == 0) | |
| { | |
| serialConfig_comport++; | |
| if (serialConfig_comport > 4) | |
| serialConfig_comport = 1; | |
| serialConfig_irq = ISA_IRQs[serialConfig_comport - 1]; | |
| } | |
| if (serialConfig_cursor == 1) | |
| { | |
| serialConfig_irq++; | |
| if (serialConfig_irq == 6) | |
| serialConfig_irq = 7; | |
| if (serialConfig_irq == 8) | |
| serialConfig_irq = 2; | |
| } | |
| if (serialConfig_cursor == 2) | |
| { | |
| serialConfig_baud++; | |
| if (serialConfig_baud > 5) | |
| serialConfig_baud = 0; | |
| } | |
| break; | |
| case K_ENTER: | |
| if (serialConfig_cursor < 3) | |
| goto forward; | |
| m_entersound = 1; | |
| if (serialConfig_cursor == 3) | |
| { | |
| (*SetComPortConfig)(0, ISA_uarts[serialConfig_comport - 1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig); | |
| M_Menu_ModemConfig_f(); | |
| break; | |
| } | |
| if (serialConfig_cursor == 4) | |
| { | |
| serialConfig_cursor = 5; | |
| break; | |
| } | |
| (*SetComPortConfig)(0, ISA_uarts[serialConfig_comport - 1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig); | |
| M_ConfigureNetSubsystem(); | |
| if (StartingGame) | |
| { | |
| M_Menu_GameOptions_f(); | |
| break; | |
| } | |
| m_return_state = m_state; | |
| m_return_onerror = 1; | |
| key_dest = key_game; | |
| m_state = m_none; | |
| if (SerialConfig) | |
| Cbuf_AddText(va("connect \"%s\"\n", serialConfig_phone)); | |
| else | |
| Cbuf_AddText("connect\n"); | |
| break; | |
| case K_BACKSPACE: | |
| if (serialConfig_cursor == 4) | |
| { | |
| if (strlen(serialConfig_phone)) | |
| serialConfig_phone[strlen(serialConfig_phone) - 1] = 0; | |
| } | |
| break; | |
| default: | |
| if ((key < 32) || (key > 127)) | |
| break; | |
| if (serialConfig_cursor == 4) | |
| { | |
| l = strlen(serialConfig_phone); | |
| if (l < 15) | |
| { | |
| serialConfig_phone[l + 1] = 0; | |
| serialConfig_phone[l] = key; | |
| } | |
| } | |
| } | |
| if (DirectConfig && ((serialConfig_cursor == 3) || (serialConfig_cursor == 4))) | |
| if (key == K_UPARROW) | |
| serialConfig_cursor = 2; | |
| else | |
| serialConfig_cursor = 5; | |
| if ((SerialConfig && StartingGame) && (serialConfig_cursor == 4)) | |
| if (key == K_UPARROW) | |
| serialConfig_cursor = 3; | |
| else | |
| serialConfig_cursor = 5; | |
| } | |
| void M_Menu_ModemConfig_f(void) | |
| { | |
| key_dest = key_menu; | |
| m_state = m_modemconfig; | |
| m_entersound = 1; | |
| (*GetModemConfig)(0, &modemConfig_dialing, modemConfig_clear, modemConfig_init, modemConfig_hangup); | |
| } | |
| void M_ModemConfig_Draw(void) | |
| { | |
| qpic_t *p; | |
| int32_t basex; | |
| M_DrawTransPic(16, 4, Draw_CachePic("gfx/qplaque.lmp")); | |
| p = Draw_CachePic("gfx/p_multi.lmp"); | |
| basex = (320 - p->width) / 2; | |
| M_DrawPic(basex, 4, p); | |
| basex += 8; | |
| if (modemConfig_dialing == 'P') | |
| M_Print(basex, modemConfig_cursor_table[0], "Pulse Dialing"); | |
| else | |
| M_Print(basex, modemConfig_cursor_table[0], "Touch Tone Dialing"); | |
| M_Print(basex, modemConfig_cursor_table[1], "Clear"); | |
| M_DrawTextBox(basex, modemConfig_cursor_table[1] + 4, 16, 1); | |
| M_Print(basex + 8, modemConfig_cursor_table[1] + 12, modemConfig_clear); | |
| if (modemConfig_cursor == 1) | |
| M_DrawCharacter((basex + 8) + (8 * strlen(modemConfig_clear)), modemConfig_cursor_table[1] + 12, 10 + (((int32_t) (realtime * 4)) & 1)); | |
| M_Print(basex, modemConfig_cursor_table[2], "Init"); | |
| M_DrawTextBox(basex, modemConfig_cursor_table[2] + 4, 30, 1); | |
| M_Print(basex + 8, modemConfig_cursor_table[2] + 12, modemConfig_init); | |
| if (modemConfig_cursor == 2) | |
| M_DrawCharacter((basex + 8) + (8 * strlen(modemConfig_init)), modemConfig_cursor_table[2] + 12, 10 + (((int32_t) (realtime * 4)) & 1)); | |
| M_Print(basex, modemConfig_cursor_table[3], "Hangup"); | |
| M_DrawTextBox(basex, modemConfig_cursor_table[3] + 4, 16, 1); | |
| M_Print(basex + 8, modemConfig_cursor_table[3] + 12, modemConfig_hangup); | |
| if (modemConfig_cursor == 3) | |
| M_DrawCharacter((basex + 8) + (8 * strlen(modemConfig_hangup)), modemConfig_cursor_table[3] + 12, 10 + (((int32_t) (realtime * 4)) & 1)); | |
| M_DrawTextBox(basex, modemConfig_cursor_table[4] - 8, 2, 1); | |
| M_Print(basex + 8, modemConfig_cursor_table[4], "OK"); | |
| M_DrawCharacter(basex - 8, modemConfig_cursor_table[modemConfig_cursor], 12 + (((int32_t) (realtime * 4)) & 1)); | |
| } | |
| void M_ModemConfig_Key(int32_t key) | |
| { | |
| int32_t l; | |
| switch (key) | |
| { | |
| case K_ESCAPE: | |
| M_Menu_SerialConfig_f(); | |
| break; | |
| case K_UPARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| modemConfig_cursor--; | |
| if (modemConfig_cursor < 0) | |
| modemConfig_cursor = NUM_MODEMCONFIG_CMDS - 1; | |
| break; | |
| case K_DOWNARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| modemConfig_cursor++; | |
| if (modemConfig_cursor >= NUM_MODEMCONFIG_CMDS) | |
| modemConfig_cursor = 0; | |
| break; | |
| case K_LEFTARROW: | |
| case K_RIGHTARROW: | |
| if (modemConfig_cursor == 0) | |
| { | |
| if (modemConfig_dialing == 'P') | |
| modemConfig_dialing = 'T'; | |
| else | |
| modemConfig_dialing = 'P'; | |
| S_LocalSound("misc/menu1.wav"); | |
| } | |
| break; | |
| case K_ENTER: | |
| if (modemConfig_cursor == 0) | |
| { | |
| if (modemConfig_dialing == 'P') | |
| modemConfig_dialing = 'T'; | |
| else | |
| modemConfig_dialing = 'P'; | |
| m_entersound = 1; | |
| } | |
| if (modemConfig_cursor == 4) | |
| { | |
| (*SetModemConfig)(0, va("%c", modemConfig_dialing), modemConfig_clear, modemConfig_init, modemConfig_hangup); | |
| m_entersound = 1; | |
| M_Menu_SerialConfig_f(); | |
| } | |
| break; | |
| case K_BACKSPACE: | |
| if (modemConfig_cursor == 1) | |
| { | |
| if (strlen(modemConfig_clear)) | |
| modemConfig_clear[strlen(modemConfig_clear) - 1] = 0; | |
| } | |
| if (modemConfig_cursor == 2) | |
| { | |
| if (strlen(modemConfig_init)) | |
| modemConfig_init[strlen(modemConfig_init) - 1] = 0; | |
| } | |
| if (modemConfig_cursor == 3) | |
| { | |
| if (strlen(modemConfig_hangup)) | |
| modemConfig_hangup[strlen(modemConfig_hangup) - 1] = 0; | |
| } | |
| break; | |
| default: | |
| if ((key < 32) || (key > 127)) | |
| break; | |
| if (modemConfig_cursor == 1) | |
| { | |
| l = strlen(modemConfig_clear); | |
| if (l < 15) | |
| { | |
| modemConfig_clear[l + 1] = 0; | |
| modemConfig_clear[l] = key; | |
| } | |
| } | |
| if (modemConfig_cursor == 2) | |
| { | |
| l = strlen(modemConfig_init); | |
| if (l < 29) | |
| { | |
| modemConfig_init[l + 1] = 0; | |
| modemConfig_init[l] = key; | |
| } | |
| } | |
| if (modemConfig_cursor == 3) | |
| { | |
| l = strlen(modemConfig_hangup); | |
| if (l < 15) | |
| { | |
| modemConfig_hangup[l + 1] = 0; | |
| modemConfig_hangup[l] = key; | |
| } | |
| } | |
| } | |
| } | |
| void M_Menu_LanConfig_f(void) | |
| { | |
| key_dest = key_menu; | |
| m_state = m_lanconfig; | |
| m_entersound = 1; | |
| if (lanConfig_cursor == (-1)) | |
| { | |
| if (JoiningGame && TCPIPConfig) | |
| lanConfig_cursor = 2; | |
| else | |
| lanConfig_cursor = 1; | |
| } | |
| if (StartingGame && (lanConfig_cursor == 2)) | |
| lanConfig_cursor = 1; | |
| lanConfig_port = DEFAULTnet_hostport; | |
| sprintf(lanConfig_portname, "%u", lanConfig_port); | |
| m_return_onerror = 0; | |
| m_return_reason[0] = 0; | |
| } | |
| void M_LanConfig_Draw(void) | |
| { | |
| qpic_t *p; | |
| int32_t basex; | |
| char *startJoin; | |
| char *protocol; | |
| M_DrawTransPic(16, 4, Draw_CachePic("gfx/qplaque.lmp")); | |
| p = Draw_CachePic("gfx/p_multi.lmp"); | |
| basex = (320 - p->width) / 2; | |
| M_DrawPic(basex, 4, p); | |
| if (StartingGame) | |
| startJoin = "New Game"; | |
| else | |
| startJoin = "Join Game"; | |
| if (IPXConfig) | |
| protocol = "IPX"; | |
| else | |
| protocol = "TCP/IP"; | |
| M_Print(basex, 32, va("%s - %s", startJoin, protocol)); | |
| basex += 8; | |
| M_Print(basex, 52, "Address:"); | |
| if (IPXConfig) | |
| M_Print(basex + (9 * 8), 52, my_ipx_address); | |
| else | |
| M_Print(basex + (9 * 8), 52, my_tcpip_address); | |
| M_Print(basex, lanConfig_cursor_table[0], "Port"); | |
| M_DrawTextBox(basex + (8 * 8), lanConfig_cursor_table[0] - 8, 6, 1); | |
| M_Print(basex + (9 * 8), lanConfig_cursor_table[0], lanConfig_portname); | |
| if (JoiningGame) | |
| { | |
| M_Print(basex, lanConfig_cursor_table[1], "Search for local games..."); | |
| M_Print(basex, 108, "Join game at:"); | |
| M_DrawTextBox(basex + 8, lanConfig_cursor_table[2] - 8, 22, 1); | |
| M_Print(basex + 16, lanConfig_cursor_table[2], lanConfig_joinname); | |
| } | |
| else | |
| { | |
| M_DrawTextBox(basex, lanConfig_cursor_table[1] - 8, 2, 1); | |
| M_Print(basex + 8, lanConfig_cursor_table[1], "OK"); | |
| } | |
| M_DrawCharacter(basex - 8, lanConfig_cursor_table[lanConfig_cursor], 12 + (((int32_t) (realtime * 4)) & 1)); | |
| if (lanConfig_cursor == 0) | |
| M_DrawCharacter((basex + (9 * 8)) + (8 * strlen(lanConfig_portname)), lanConfig_cursor_table[0], 10 + (((int32_t) (realtime * 4)) & 1)); | |
| if (lanConfig_cursor == 2) | |
| M_DrawCharacter((basex + 16) + (8 * strlen(lanConfig_joinname)), lanConfig_cursor_table[2], 10 + (((int32_t) (realtime * 4)) & 1)); | |
| if (*m_return_reason) | |
| M_PrintWhite(basex, 148, m_return_reason); | |
| } | |
| void M_LanConfig_Key(int32_t key) | |
| { | |
| int32_t l; | |
| switch (key) | |
| { | |
| case K_ESCAPE: | |
| M_Menu_Net_f(); | |
| break; | |
| case K_UPARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| lanConfig_cursor--; | |
| if (lanConfig_cursor < 0) | |
| lanConfig_cursor = NUM_LANCONFIG_CMDS - 1; | |
| break; | |
| case K_DOWNARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| lanConfig_cursor++; | |
| if (lanConfig_cursor >= NUM_LANCONFIG_CMDS) | |
| lanConfig_cursor = 0; | |
| break; | |
| case K_ENTER: | |
| if (lanConfig_cursor == 0) | |
| break; | |
| m_entersound = 1; | |
| M_ConfigureNetSubsystem(); | |
| if (lanConfig_cursor == 1) | |
| { | |
| if (StartingGame) | |
| { | |
| M_Menu_GameOptions_f(); | |
| break; | |
| } | |
| M_Menu_Search_f(); | |
| break; | |
| } | |
| if (lanConfig_cursor == 2) | |
| { | |
| m_return_state = m_state; | |
| m_return_onerror = 1; | |
| key_dest = key_game; | |
| m_state = m_none; | |
| Cbuf_AddText(va("connect \"%s\"\n", lanConfig_joinname)); | |
| break; | |
| } | |
| break; | |
| case K_BACKSPACE: | |
| if (lanConfig_cursor == 0) | |
| { | |
| if (strlen(lanConfig_portname)) | |
| lanConfig_portname[strlen(lanConfig_portname) - 1] = 0; | |
| } | |
| if (lanConfig_cursor == 2) | |
| { | |
| if (strlen(lanConfig_joinname)) | |
| lanConfig_joinname[strlen(lanConfig_joinname) - 1] = 0; | |
| } | |
| break; | |
| default: | |
| if ((key < 32) || (key > 127)) | |
| break; | |
| if (lanConfig_cursor == 2) | |
| { | |
| l = strlen(lanConfig_joinname); | |
| if (l < 21) | |
| { | |
| lanConfig_joinname[l + 1] = 0; | |
| lanConfig_joinname[l] = key; | |
| } | |
| } | |
| if ((key < '0') || (key > '9')) | |
| break; | |
| if (lanConfig_cursor == 0) | |
| { | |
| l = strlen(lanConfig_portname); | |
| if (l < 5) | |
| { | |
| lanConfig_portname[l + 1] = 0; | |
| lanConfig_portname[l] = key; | |
| } | |
| } | |
| } | |
| if (StartingGame && (lanConfig_cursor == 2)) | |
| if (key == K_UPARROW) | |
| lanConfig_cursor = 1; | |
| else | |
| lanConfig_cursor = 0; | |
| l = (int32_t) strtol(lanConfig_portname, 0, 0); | |
| if (l > 65535) | |
| l = lanConfig_port; | |
| else | |
| lanConfig_port = l; | |
| sprintf(lanConfig_portname, "%u", lanConfig_port); | |
| } | |
| void M_Menu_GameOptions_f(void) | |
| { | |
| key_dest = key_menu; | |
| m_state = m_gameoptions; | |
| m_entersound = 1; | |
| if (maxplayers == 0) | |
| maxplayers = svs.maxclients; | |
| if (maxplayers < 2) | |
| maxplayers = svs.maxclientslimit; | |
| } | |
| void M_GameOptions_Draw(void) | |
| { | |
| qpic_t *p; | |
| int32_t x; | |
| M_DrawTransPic(16, 4, Draw_CachePic("gfx/qplaque.lmp")); | |
| p = Draw_CachePic("gfx/p_multi.lmp"); | |
| M_DrawPic((320 - p->width) / 2, 4, p); | |
| M_DrawTextBox(152, 32, 10, 1); | |
| M_Print(160, 40, "begin game"); | |
| M_Print(0, 56, " Max players"); | |
| M_Print(160, 56, va("%i", maxplayers)); | |
| M_Print(0, 64, " Game Type"); | |
| if (coop.value) | |
| M_Print(160, 64, "Cooperative"); | |
| else | |
| M_Print(160, 64, "Deathmatch"); | |
| M_Print(0, 72, " Teamplay"); | |
| if (rogue) | |
| { | |
| char *msg; | |
| switch ((int32_t) teamplay.value) | |
| { | |
| case 1: | |
| msg = "No Friendly Fire"; | |
| break; | |
| case 2: | |
| msg = "Friendly Fire"; | |
| break; | |
| case 3: | |
| msg = "Tag"; | |
| break; | |
| case 4: | |
| msg = "Capture the Flag"; | |
| break; | |
| case 5: | |
| msg = "One Flag CTF"; | |
| break; | |
| case 6: | |
| msg = "Three Team CTF"; | |
| break; | |
| default: | |
| msg = "Off"; | |
| break; | |
| } | |
| M_Print(160, 72, msg); | |
| } | |
| else | |
| { | |
| char *msg; | |
| switch ((int32_t) teamplay.value) | |
| { | |
| case 1: | |
| msg = "No Friendly Fire"; | |
| break; | |
| case 2: | |
| msg = "Friendly Fire"; | |
| break; | |
| default: | |
| msg = "Off"; | |
| break; | |
| } | |
| M_Print(160, 72, msg); | |
| } | |
| M_Print(0, 80, " Skill"); | |
| if (skill.value == 0) | |
| M_Print(160, 80, "Easy difficulty"); | |
| else | |
| if (skill.value == 1) | |
| M_Print(160, 80, "Normal difficulty"); | |
| else | |
| if (skill.value == 2) | |
| M_Print(160, 80, "Hard difficulty"); | |
| else | |
| M_Print(160, 80, "Nightmare difficulty"); | |
| M_Print(0, 88, " Frag Limit"); | |
| if (fraglimit.value == 0) | |
| M_Print(160, 88, "none"); | |
| else | |
| M_Print(160, 88, va("%i frags", (int32_t) fraglimit.value)); | |
| M_Print(0, 96, " Time Limit"); | |
| if (timelimit.value == 0) | |
| M_Print(160, 96, "none"); | |
| else | |
| M_Print(160, 96, va("%i minutes", (int32_t) timelimit.value)); | |
| M_Print(0, 112, " Episode"); | |
| if (hipnotic) | |
| M_Print(160, 112, hipnoticepisodes[startepisode].description); | |
| else | |
| if (rogue) | |
| M_Print(160, 112, rogueepisodes[startepisode].description); | |
| else | |
| M_Print(160, 112, episodes[startepisode].description); | |
| M_Print(0, 120, " Level"); | |
| if (hipnotic) | |
| { | |
| M_Print(160, 120, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].description); | |
| M_Print(160, 128, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name); | |
| } | |
| else | |
| if (rogue) | |
| { | |
| M_Print(160, 120, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].description); | |
| M_Print(160, 128, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name); | |
| } | |
| else | |
| { | |
| M_Print(160, 120, levels[episodes[startepisode].firstLevel + startlevel].description); | |
| M_Print(160, 128, levels[episodes[startepisode].firstLevel + startlevel].name); | |
| } | |
| M_DrawCharacter(144, gameoptions_cursor_table[gameoptions_cursor], 12 + (((int32_t) (realtime * 4)) & 1)); | |
| if (m_serverInfoMessage) | |
| { | |
| if ((realtime - m_serverInfoMessageTime) < 5.0) | |
| { | |
| x = (320 - (26 * 8)) / 2; | |
| M_DrawTextBox(x, 138, 24, 4); | |
| x += 8; | |
| M_Print(x, 146, " More than 4 players "); | |
| M_Print(x, 154, " requires using command "); | |
| M_Print(x, 162, "line parameters; please "); | |
| M_Print(x, 170, " see techinfo.txt. "); | |
| } | |
| else | |
| { | |
| m_serverInfoMessage = 0; | |
| } | |
| } | |
| } | |
| void M_NetStart_Change(int32_t dir) | |
| { | |
| int32_t count; | |
| switch (gameoptions_cursor) | |
| { | |
| case 1: | |
| maxplayers += dir; | |
| if (maxplayers > svs.maxclientslimit) | |
| { | |
| maxplayers = svs.maxclientslimit; | |
| m_serverInfoMessage = 1; | |
| m_serverInfoMessageTime = realtime; | |
| } | |
| if (maxplayers < 2) | |
| maxplayers = 2; | |
| break; | |
| case 2: | |
| Cvar_SetValue("coop", (coop.value) ? (0) : (1)); | |
| break; | |
| case 3: | |
| if (rogue) | |
| count = 6; | |
| else | |
| count = 2; | |
| Cvar_SetValue("teamplay", teamplay.value + dir); | |
| if (teamplay.value > count) | |
| Cvar_SetValue("teamplay", 0); | |
| else | |
| if (teamplay.value < 0) | |
| Cvar_SetValue("teamplay", count); | |
| break; | |
| case 4: | |
| Cvar_SetValue("skill", skill.value + dir); | |
| if (skill.value > 3) | |
| Cvar_SetValue("skill", 0); | |
| if (skill.value < 0) | |
| Cvar_SetValue("skill", 3); | |
| break; | |
| case 5: | |
| Cvar_SetValue("fraglimit", fraglimit.value + (dir * 10)); | |
| if (fraglimit.value > 100) | |
| Cvar_SetValue("fraglimit", 0); | |
| if (fraglimit.value < 0) | |
| Cvar_SetValue("fraglimit", 100); | |
| break; | |
| case 6: | |
| Cvar_SetValue("timelimit", timelimit.value + (dir * 5)); | |
| if (timelimit.value > 60) | |
| Cvar_SetValue("timelimit", 0); | |
| if (timelimit.value < 0) | |
| Cvar_SetValue("timelimit", 60); | |
| break; | |
| case 7: | |
| startepisode += dir; | |
| if (hipnotic) | |
| count = 6; | |
| else | |
| if (rogue) | |
| count = 4; | |
| else | |
| if (registered.value) | |
| count = 7; | |
| else | |
| count = 2; | |
| if (startepisode < 0) | |
| startepisode = count - 1; | |
| if (startepisode >= count) | |
| startepisode = 0; | |
| startlevel = 0; | |
| break; | |
| case 8: | |
| startlevel += dir; | |
| if (hipnotic) | |
| count = hipnoticepisodes[startepisode].levels; | |
| else | |
| if (rogue) | |
| count = rogueepisodes[startepisode].levels; | |
| else | |
| count = episodes[startepisode].levels; | |
| if (startlevel < 0) | |
| startlevel = count - 1; | |
| if (startlevel >= count) | |
| startlevel = 0; | |
| break; | |
| } | |
| } | |
| void M_GameOptions_Key(int32_t key) | |
| { | |
| switch (key) | |
| { | |
| case K_ESCAPE: | |
| M_Menu_Net_f(); | |
| break; | |
| case K_UPARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| gameoptions_cursor--; | |
| if (gameoptions_cursor < 0) | |
| gameoptions_cursor = NUM_GAMEOPTIONS - 1; | |
| break; | |
| case K_DOWNARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| gameoptions_cursor++; | |
| if (gameoptions_cursor >= NUM_GAMEOPTIONS) | |
| gameoptions_cursor = 0; | |
| break; | |
| case K_LEFTARROW: | |
| if (gameoptions_cursor == 0) | |
| break; | |
| S_LocalSound("misc/menu3.wav"); | |
| M_NetStart_Change(-1); | |
| break; | |
| case K_RIGHTARROW: | |
| if (gameoptions_cursor == 0) | |
| break; | |
| S_LocalSound("misc/menu3.wav"); | |
| M_NetStart_Change(1); | |
| break; | |
| case K_ENTER: | |
| S_LocalSound("misc/menu2.wav"); | |
| if (gameoptions_cursor == 0) | |
| { | |
| if (sv.active) | |
| Cbuf_AddText("disconnect\n"); | |
| Cbuf_AddText("listen 0\n"); | |
| Cbuf_AddText(va("maxplayers %u\n", maxplayers)); | |
| SCR_BeginLoadingPlaque(); | |
| if (hipnotic) | |
| Cbuf_AddText(va("map %s\n", hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name)); | |
| else | |
| if (rogue) | |
| Cbuf_AddText(va("map %s\n", roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name)); | |
| else | |
| Cbuf_AddText(va("map %s\n", levels[episodes[startepisode].firstLevel + startlevel].name)); | |
| return; | |
| } | |
| M_NetStart_Change(1); | |
| break; | |
| } | |
| } | |
| void M_Menu_Search_f(void) | |
| { | |
| key_dest = key_menu; | |
| m_state = m_search; | |
| m_entersound = 0; | |
| slistSilent = 1; | |
| slistLocal = 0; | |
| searchComplete = 0; | |
| NET_Slist_f(); | |
| } | |
| void M_Search_Draw(void) | |
| { | |
| qpic_t *p; | |
| int32_t x; | |
| p = Draw_CachePic("gfx/p_multi.lmp"); | |
| M_DrawPic((320 - p->width) / 2, 4, p); | |
| x = ((320 / 2) - ((12 * 8) / 2)) + 4; | |
| M_DrawTextBox(x - 8, 32, 12, 1); | |
| M_Print(x, 40, "Searching..."); | |
| if (slistInProgress) | |
| { | |
| NET_Poll(); | |
| return; | |
| } | |
| if (!searchComplete) | |
| { | |
| searchComplete = 1; | |
| searchCompleteTime = realtime; | |
| } | |
| if (hostCacheCount) | |
| { | |
| M_Menu_ServerList_f(); | |
| return; | |
| } | |
| M_PrintWhite((320 / 2) - ((22 * 8) / 2), 64, "No Quake servers found"); | |
| if ((realtime - searchCompleteTime) < 3.0) | |
| return; | |
| M_Menu_LanConfig_f(); | |
| } | |
| void M_Search_Key(int32_t key) | |
| { | |
| } | |
| void M_Menu_ServerList_f(void) | |
| { | |
| key_dest = key_menu; | |
| m_state = m_slist; | |
| m_entersound = 1; | |
| slist_cursor = 0; | |
| m_return_onerror = 0; | |
| m_return_reason[0] = 0; | |
| slist_sorted = 0; | |
| } | |
| void M_ServerList_Draw(void) | |
| { | |
| int32_t n; | |
| char string[64]; | |
| qpic_t *p; | |
| if (!slist_sorted) | |
| { | |
| if (hostCacheCount > 1) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| hostcache_t temp; | |
| for (i = 0; i < hostCacheCount; i++) | |
| for (j = i + 1; j < hostCacheCount; j++) | |
| if (strcmp(hostcache[j].name, hostcache[i].name) < 0) | |
| { | |
| memcpy(&temp, &hostcache[j], sizeof(hostcache_t)); | |
| memcpy(&hostcache[j], &hostcache[i], sizeof(hostcache_t)); | |
| memcpy(&hostcache[i], &temp, sizeof(hostcache_t)); | |
| } | |
| } | |
| slist_sorted = 1; | |
| } | |
| p = Draw_CachePic("gfx/p_multi.lmp"); | |
| M_DrawPic((320 - p->width) / 2, 4, p); | |
| for (n = 0; n < hostCacheCount; n++) | |
| { | |
| if (hostcache[n].maxusers) | |
| sprintf(string, "%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers); | |
| else | |
| sprintf(string, "%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map); | |
| M_Print(16, 32 + (8 * n), string); | |
| } | |
| M_DrawCharacter(0, 32 + (slist_cursor * 8), 12 + (((int32_t) (realtime * 4)) & 1)); | |
| if (*m_return_reason) | |
| M_PrintWhite(16, 148, m_return_reason); | |
| } | |
| void M_ServerList_Key(int32_t k) | |
| { | |
| switch (k) | |
| { | |
| case K_ESCAPE: | |
| M_Menu_LanConfig_f(); | |
| break; | |
| case K_SPACE: | |
| M_Menu_Search_f(); | |
| break; | |
| case K_UPARROW: | |
| case K_LEFTARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| slist_cursor--; | |
| if (slist_cursor < 0) | |
| slist_cursor = hostCacheCount - 1; | |
| break; | |
| case K_DOWNARROW: | |
| case K_RIGHTARROW: | |
| S_LocalSound("misc/menu1.wav"); | |
| slist_cursor++; | |
| if (slist_cursor >= hostCacheCount) | |
| slist_cursor = 0; | |
| break; | |
| case K_ENTER: | |
| S_LocalSound("misc/menu2.wav"); | |
| m_return_state = m_state; | |
| m_return_onerror = 1; | |
| slist_sorted = 0; | |
| key_dest = key_game; | |
| m_state = m_none; | |
| Cbuf_AddText(va("connect \"%s\"\n", hostcache[slist_cursor].cname)); | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| void M_Init(void) | |
| { | |
| Cmd_AddCommand("togglemenu", M_ToggleMenu_f); | |
| Cmd_AddCommand("menu_main", M_Menu_Main_f); | |
| Cmd_AddCommand("menu_singleplayer", M_Menu_SinglePlayer_f); | |
| Cmd_AddCommand("menu_load", M_Menu_Load_f); | |
| Cmd_AddCommand("menu_save", M_Menu_Save_f); | |
| Cmd_AddCommand("menu_multiplayer", M_Menu_MultiPlayer_f); | |
| Cmd_AddCommand("menu_setup", M_Menu_Setup_f); | |
| Cmd_AddCommand("menu_options", M_Menu_Options_f); | |
| Cmd_AddCommand("menu_keys", M_Menu_Keys_f); | |
| Cmd_AddCommand("menu_video", M_Menu_Video_f); | |
| Cmd_AddCommand("help", M_Menu_Help_f); | |
| Cmd_AddCommand("menu_quit", M_Menu_Quit_f); | |
| } | |
| void M_Draw(void) | |
| { | |
| if ((m_state == m_none) || (key_dest != key_menu)) | |
| return; | |
| if (!m_recursiveDraw) | |
| { | |
| scr_copyeverything = 1; | |
| if (scr_con_current) | |
| { | |
| Draw_ConsoleBackground(vid.height); | |
| VID_UnlockBuffer(); | |
| S_ExtraUpdate(); | |
| VID_LockBuffer(); | |
| } | |
| else | |
| Draw_FadeScreen(); | |
| scr_fullupdate = 0; | |
| } | |
| else | |
| { | |
| m_recursiveDraw = 0; | |
| } | |
| switch (m_state) | |
| { | |
| case m_none: | |
| break; | |
| case m_main: | |
| M_Main_Draw(); | |
| break; | |
| case m_singleplayer: | |
| M_SinglePlayer_Draw(); | |
| break; | |
| case m_load: | |
| M_Load_Draw(); | |
| break; | |
| case m_save: | |
| M_Save_Draw(); | |
| break; | |
| case m_multiplayer: | |
| M_MultiPlayer_Draw(); | |
| break; | |
| case m_setup: | |
| M_Setup_Draw(); | |
| break; | |
| case m_net: | |
| M_Net_Draw(); | |
| break; | |
| case m_options: | |
| M_Options_Draw(); | |
| break; | |
| case m_keys: | |
| M_Keys_Draw(); | |
| break; | |
| case m_video: | |
| M_Video_Draw(); | |
| break; | |
| case m_help: | |
| M_Help_Draw(); | |
| break; | |
| case m_quit: | |
| M_Quit_Draw(); | |
| break; | |
| case m_serialconfig: | |
| M_SerialConfig_Draw(); | |
| break; | |
| case m_modemconfig: | |
| M_ModemConfig_Draw(); | |
| break; | |
| case m_lanconfig: | |
| M_LanConfig_Draw(); | |
| break; | |
| case m_gameoptions: | |
| M_GameOptions_Draw(); | |
| break; | |
| case m_search: | |
| M_Search_Draw(); | |
| break; | |
| case m_slist: | |
| M_ServerList_Draw(); | |
| break; | |
| } | |
| if (m_entersound) | |
| { | |
| S_LocalSound("misc/menu2.wav"); | |
| m_entersound = 0; | |
| } | |
| VID_UnlockBuffer(); | |
| S_ExtraUpdate(); | |
| VID_LockBuffer(); | |
| } | |
| void M_Keydown(int32_t key) | |
| { | |
| switch (m_state) | |
| { | |
| case m_none: | |
| return; | |
| case m_main: | |
| M_Main_Key(key); | |
| return; | |
| case m_singleplayer: | |
| M_SinglePlayer_Key(key); | |
| return; | |
| case m_load: | |
| M_Load_Key(key); | |
| return; | |
| case m_save: | |
| M_Save_Key(key); | |
| return; | |
| case m_multiplayer: | |
| M_MultiPlayer_Key(key); | |
| return; | |
| case m_setup: | |
| M_Setup_Key(key); | |
| return; | |
| case m_net: | |
| M_Net_Key(key); | |
| return; | |
| case m_options: | |
| M_Options_Key(key); | |
| return; | |
| case m_keys: | |
| M_Keys_Key(key); | |
| return; | |
| case m_video: | |
| M_Video_Key(key); | |
| return; | |
| case m_help: | |
| M_Help_Key(key); | |
| return; | |
| case m_quit: | |
| M_Quit_Key(key); | |
| return; | |
| case m_serialconfig: | |
| M_SerialConfig_Key(key); | |
| return; | |
| case m_modemconfig: | |
| M_ModemConfig_Key(key); | |
| return; | |
| case m_lanconfig: | |
| M_LanConfig_Key(key); | |
| return; | |
| case m_gameoptions: | |
| M_GameOptions_Key(key); | |
| return; | |
| case m_search: | |
| M_Search_Key(key); | |
| break; | |
| case m_slist: | |
| M_ServerList_Key(key); | |
| return; | |
| } | |
| } | |
| void M_ConfigureNetSubsystem(void) | |
| { | |
| Cbuf_AddText("stopdemo\n"); | |
| if (SerialConfig || DirectConfig) | |
| { | |
| Cbuf_AddText("com1 enable\n"); | |
| } | |
| if (IPXConfig || TCPIPConfig) | |
| net_hostport = lanConfig_port; | |
| } | |
| void Mod_Init(void) | |
| { | |
| memset(mod_novis, 0xff, sizeof(mod_novis)); | |
| } | |
| void *Mod_Extradata(model_t *mod) | |
| { | |
| void *r; | |
| r = Cache_Check(&mod->cache); | |
| if (r) | |
| return r; | |
| Mod_LoadModel(mod, 1); | |
| if (!mod->cache.data) | |
| Sys_Error("Mod_Extradata: caching failed"); | |
| return mod->cache.data; | |
| } | |
| mleaf_t *Mod_PointInLeaf(vec3_t p, model_t *model) | |
| { | |
| mnode_t *node; | |
| float d; | |
| mplane_t *plane; | |
| if ((!model) || (!model->nodes)) | |
| Sys_Error("Mod_PointInLeaf: bad model"); | |
| node = model->nodes; | |
| while (1) | |
| { | |
| if (node->contents < 0) | |
| return (mleaf_t *) node; | |
| plane = node->plane; | |
| d = DotProduct(p, plane->normal) - plane->dist; | |
| if (d > 0) | |
| node = node->children[0]; | |
| else | |
| node = node->children[1]; | |
| } | |
| return 0; | |
| } | |
| uint8_t *Mod_DecompressVis(uint8_t *in, model_t *model) | |
| { | |
| static uint8_t decompressed[MAX_MAP_LEAFS / 8]; | |
| int32_t c; | |
| uint8_t *out; | |
| int32_t row; | |
| row = (model->numleafs + 7) >> 3; | |
| out = decompressed; | |
| if (!in) | |
| { | |
| while (row) | |
| { | |
| *(out++) = 0xff; | |
| row--; | |
| } | |
| return decompressed; | |
| } | |
| do | |
| { | |
| if (*in) | |
| { | |
| *(out++) = *(in++); | |
| continue; | |
| } | |
| c = in[1]; | |
| in += 2; | |
| while (c) | |
| { | |
| *(out++) = 0; | |
| c--; | |
| } | |
| } | |
| while ((out - decompressed) < row); | |
| return decompressed; | |
| } | |
| uint8_t *Mod_LeafPVS(mleaf_t *leaf, model_t *model) | |
| { | |
| if (leaf == model->leafs) | |
| return mod_novis; | |
| return Mod_DecompressVis(leaf->compressed_vis, model); | |
| } | |
| void Mod_ClearAll(void) | |
| { | |
| int32_t i; | |
| model_t *mod; | |
| for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++) | |
| { | |
| mod->needload = NL_UNREFERENCED; | |
| if (mod->type == mod_sprite) | |
| mod->cache.data = 0; | |
| } | |
| } | |
| model_t *Mod_FindName(char *name) | |
| { | |
| int32_t i; | |
| model_t *mod; | |
| model_t *avail = 0; | |
| if (!name[0]) | |
| Sys_Error("Mod_ForName: NULL name"); | |
| for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++) | |
| { | |
| if (!strcmp(mod->name, name)) | |
| break; | |
| if (mod->needload == NL_UNREFERENCED) | |
| if ((!avail) || (mod->type != mod_alias)) | |
| avail = mod; | |
| } | |
| if (i == mod_numknown) | |
| { | |
| if (mod_numknown == MAX_MOD_KNOWN) | |
| { | |
| if (avail) | |
| { | |
| mod = avail; | |
| if (mod->type == mod_alias) | |
| if (Cache_Check(&mod->cache)) | |
| Cache_Free(&mod->cache); | |
| } | |
| else | |
| Sys_Error("mod_numknown == MAX_MOD_KNOWN"); | |
| } | |
| else | |
| mod_numknown++; | |
| strcpy(mod->name, name); | |
| mod->needload = NL_NEEDS_LOADED; | |
| } | |
| return mod; | |
| } | |
| void Mod_TouchModel(char *name) | |
| { | |
| model_t *mod; | |
| mod = Mod_FindName(name); | |
| if (mod->needload == NL_PRESENT) | |
| { | |
| if (mod->type == mod_alias) | |
| Cache_Check(&mod->cache); | |
| } | |
| } | |
| model_t *Mod_LoadModel(model_t *mod, bool crash) | |
| { | |
| uint32_t *buf; | |
| uint8_t stackbuf[1024]; | |
| if (mod->type == mod_alias) | |
| { | |
| if (Cache_Check(&mod->cache)) | |
| { | |
| mod->needload = NL_PRESENT; | |
| return mod; | |
| } | |
| } | |
| else | |
| { | |
| if (mod->needload == NL_PRESENT) | |
| return mod; | |
| } | |
| buf = (uint32_t *) COM_LoadStackFile(mod->name, stackbuf, sizeof(stackbuf)); | |
| if (!buf) | |
| { | |
| if (crash) | |
| Sys_Error("Mod_NumForName: %s not found", mod->name); | |
| return 0; | |
| } | |
| COM_FileBase(mod->name, loadname); | |
| loadmodel = mod; | |
| mod->needload = NL_PRESENT; | |
| switch (*((uint32_t *) buf)) | |
| { | |
| case IDPOLYHEADER: | |
| Mod_LoadAliasModel(mod, buf); | |
| break; | |
| case IDSPRITEHEADER: | |
| Mod_LoadSpriteModel(mod, buf); | |
| break; | |
| default: | |
| Mod_LoadBrushModel(mod, buf); | |
| break; | |
| } | |
| return mod; | |
| } | |
| model_t *Mod_ForName(char *name, bool crash) | |
| { | |
| model_t *mod; | |
| mod = Mod_FindName(name); | |
| return Mod_LoadModel(mod, crash); | |
| } | |
| void Mod_LoadTextures(lump_t *l) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| int32_t pixels; | |
| int32_t num; | |
| int32_t max; | |
| int32_t altmax; | |
| miptex_t *mt; | |
| texture_t *tx; | |
| texture_t *tx2; | |
| texture_t *anims[10]; | |
| texture_t *altanims[10]; | |
| dmiptexlump_t *m; | |
| if (!l->filelen) | |
| { | |
| loadmodel->textures = 0; | |
| return; | |
| } | |
| m = (dmiptexlump_t *) (mod_base + l->fileofs); | |
| m->nummiptex = m->nummiptex; | |
| loadmodel->numtextures = m->nummiptex; | |
| loadmodel->textures = Hunk_AllocName(m->nummiptex * (sizeof(*loadmodel->textures)), loadname); | |
| for (i = 0; i < m->nummiptex; i++) | |
| { | |
| m->dataofs[i] = m->dataofs[i]; | |
| if (m->dataofs[i] == (-1)) | |
| continue; | |
| mt = (miptex_t *) (((uint8_t *) m) + m->dataofs[i]); | |
| mt->width = mt->width; | |
| mt->height = mt->height; | |
| for (j = 0; j < MIPLEVELS; j++) | |
| mt->offsets[j] = mt->offsets[j]; | |
| if ((mt->width & 15) || (mt->height & 15)) | |
| Sys_Error("Texture %s is not 16 aligned", mt->name); | |
| pixels = ((mt->width * mt->height) / 64) * 85; | |
| tx = Hunk_AllocName((sizeof(texture_t)) + pixels, loadname); | |
| loadmodel->textures[i] = tx; | |
| memcpy(tx->name, mt->name, sizeof(tx->name)); | |
| tx->width = mt->width; | |
| tx->height = mt->height; | |
| for (j = 0; j < MIPLEVELS; j++) | |
| tx->offsets[j] = (mt->offsets[j] + (sizeof(texture_t))) - (sizeof(miptex_t)); | |
| memcpy(tx + 1, mt + 1, pixels); | |
| if (!strncmp(mt->name, "sky", 3)) | |
| R_InitSky(tx); | |
| } | |
| for (i = 0; i < m->nummiptex; i++) | |
| { | |
| tx = loadmodel->textures[i]; | |
| if ((!tx) || (tx->name[0] != '+')) | |
| continue; | |
| if (tx->anim_next) | |
| continue; | |
| memset(anims, 0, sizeof(anims)); | |
| memset(altanims, 0, sizeof(altanims)); | |
| max = tx->name[1]; | |
| altmax = 0; | |
| if ((max >= 'a') && (max <= 'z')) | |
| max -= 'a' - 'A'; | |
| if ((max >= '0') && (max <= '9')) | |
| { | |
| max -= '0'; | |
| altmax = 0; | |
| anims[max] = tx; | |
| max++; | |
| } | |
| else | |
| if ((max >= 'A') && (max <= 'J')) | |
| { | |
| altmax = max - 'A'; | |
| max = 0; | |
| altanims[altmax] = tx; | |
| altmax++; | |
| } | |
| else | |
| Sys_Error("Bad animating texture %s", tx->name); | |
| for (j = i + 1; j < m->nummiptex; j++) | |
| { | |
| tx2 = loadmodel->textures[j]; | |
| if ((!tx2) || (tx2->name[0] != '+')) | |
| continue; | |
| if (strcmp(tx2->name + 2, tx->name + 2)) | |
| continue; | |
| num = tx2->name[1]; | |
| if ((num >= 'a') && (num <= 'z')) | |
| num -= 'a' - 'A'; | |
| if ((num >= '0') && (num <= '9')) | |
| { | |
| num -= '0'; | |
| anims[num] = tx2; | |
| if ((num + 1) > max) | |
| max = num + 1; | |
| } | |
| else | |
| if ((num >= 'A') && (num <= 'J')) | |
| { | |
| num = num - 'A'; | |
| altanims[num] = tx2; | |
| if ((num + 1) > altmax) | |
| altmax = num + 1; | |
| } | |
| else | |
| Sys_Error("Bad animating texture %s", tx->name); | |
| } | |
| for (j = 0; j < max; j++) | |
| { | |
| tx2 = anims[j]; | |
| if (!tx2) | |
| Sys_Error("Missing frame %i of %s", j, tx->name); | |
| tx2->anim_total = max * ANIM_CYCLE; | |
| tx2->anim_min = j * ANIM_CYCLE; | |
| tx2->anim_max = (j + 1) * ANIM_CYCLE; | |
| tx2->anim_next = anims[(j + 1) % max]; | |
| if (altmax) | |
| tx2->alternate_anims = altanims[0]; | |
| } | |
| for (j = 0; j < altmax; j++) | |
| { | |
| tx2 = altanims[j]; | |
| if (!tx2) | |
| Sys_Error("Missing frame %i of %s", j, tx->name); | |
| tx2->anim_total = altmax * ANIM_CYCLE; | |
| tx2->anim_min = j * ANIM_CYCLE; | |
| tx2->anim_max = (j + 1) * ANIM_CYCLE; | |
| tx2->anim_next = altanims[(j + 1) % altmax]; | |
| if (max) | |
| tx2->alternate_anims = anims[0]; | |
| } | |
| } | |
| } | |
| void Mod_LoadLighting(lump_t *l) | |
| { | |
| if (!l->filelen) | |
| { | |
| loadmodel->lightdata = 0; | |
| return; | |
| } | |
| loadmodel->lightdata = Hunk_AllocName(l->filelen, loadname); | |
| memcpy(loadmodel->lightdata, mod_base + l->fileofs, l->filelen); | |
| } | |
| void Mod_LoadVisibility(lump_t *l) | |
| { | |
| if (!l->filelen) | |
| { | |
| loadmodel->visdata = 0; | |
| return; | |
| } | |
| loadmodel->visdata = Hunk_AllocName(l->filelen, loadname); | |
| memcpy(loadmodel->visdata, mod_base + l->fileofs, l->filelen); | |
| } | |
| void Mod_LoadEntities(lump_t *l) | |
| { | |
| if (!l->filelen) | |
| { | |
| loadmodel->entities = 0; | |
| return; | |
| } | |
| loadmodel->entities = Hunk_AllocName(l->filelen, loadname); | |
| memcpy(loadmodel->entities, mod_base + l->fileofs, l->filelen); | |
| } | |
| void Mod_LoadVertexes(lump_t *l) | |
| { | |
| dvertex_t *in; | |
| mvertex_t *out; | |
| int32_t i; | |
| int32_t count; | |
| in = (void *) (mod_base + l->fileofs); | |
| if (l->filelen % (sizeof(*in))) | |
| Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); | |
| count = l->filelen / (sizeof(*in)); | |
| out = Hunk_AllocName(count * (sizeof(*out)), loadname); | |
| loadmodel->vertexes = out; | |
| loadmodel->numvertexes = count; | |
| for (i = 0; i < count; i++, in++, out++) | |
| { | |
| out->position[0] = in->point[0]; | |
| out->position[1] = in->point[1]; | |
| out->position[2] = in->point[2]; | |
| } | |
| } | |
| void Mod_LoadSubmodels(lump_t *l) | |
| { | |
| dmodel_t *in; | |
| dmodel_t *out; | |
| int32_t i; | |
| int32_t j; | |
| int32_t count; | |
| in = (void *) (mod_base + l->fileofs); | |
| if (l->filelen % (sizeof(*in))) | |
| Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); | |
| count = l->filelen / (sizeof(*in)); | |
| out = Hunk_AllocName(count * (sizeof(*out)), loadname); | |
| loadmodel->submodels = out; | |
| loadmodel->numsubmodels = count; | |
| for (i = 0; i < count; i++, in++, out++) | |
| { | |
| for (j = 0; j < 3; j++) | |
| { | |
| out->mins[j] = in->mins[j] - 1; | |
| out->maxs[j] = in->maxs[j] + 1; | |
| out->origin[j] = in->origin[j]; | |
| } | |
| for (j = 0; j < MAX_MAP_HULLS; j++) | |
| out->headnode[j] = in->headnode[j]; | |
| out->visleafs = in->visleafs; | |
| out->firstface = in->firstface; | |
| out->numfaces = in->numfaces; | |
| } | |
| } | |
| void Mod_LoadEdges(lump_t *l) | |
| { | |
| dedge_t *in; | |
| medge_t *out; | |
| int32_t i; | |
| int32_t count; | |
| in = (void *) (mod_base + l->fileofs); | |
| if (l->filelen % (sizeof(*in))) | |
| Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); | |
| count = l->filelen / (sizeof(*in)); | |
| out = Hunk_AllocName((count + 1) * (sizeof(*out)), loadname); | |
| loadmodel->edges = out; | |
| loadmodel->numedges = count; | |
| for (i = 0; i < count; i++, in++, out++) | |
| { | |
| out->v[0] = (uint16_t) in->v[0]; | |
| out->v[1] = (uint16_t) in->v[1]; | |
| } | |
| } | |
| void Mod_LoadTexinfo(lump_t *l) | |
| { | |
| texinfo_t *in; | |
| mtexinfo_t *out; | |
| int32_t i; | |
| int32_t j; | |
| int32_t count; | |
| int32_t miptex; | |
| float len1; | |
| float len2; | |
| in = (void *) (mod_base + l->fileofs); | |
| if (l->filelen % (sizeof(*in))) | |
| Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); | |
| count = l->filelen / (sizeof(*in)); | |
| out = Hunk_AllocName(count * (sizeof(*out)), loadname); | |
| loadmodel->texinfo = out; | |
| loadmodel->numtexinfo = count; | |
| for (i = 0; i < count; i++, in++, out++) | |
| { | |
| for (j = 0; j < 8; j++) | |
| out->vecs[0][j] = in->vecs[0][j]; | |
| len1 = Length(out->vecs[0]); | |
| len2 = Length(out->vecs[1]); | |
| len1 = (len1 + len2) / 2; | |
| if (len1 < 0.32) | |
| out->mipadjust = 4; | |
| else | |
| if (len1 < 0.49) | |
| out->mipadjust = 3; | |
| else | |
| if (len1 < 0.99) | |
| out->mipadjust = 2; | |
| else | |
| out->mipadjust = 1; | |
| miptex = in->miptex; | |
| out->flags = in->flags; | |
| if (!loadmodel->textures) | |
| { | |
| out->texture = r_notexture_mip; | |
| out->flags = 0; | |
| } | |
| else | |
| { | |
| if (miptex >= loadmodel->numtextures) | |
| Sys_Error("miptex >= loadmodel->numtextures"); | |
| out->texture = loadmodel->textures[miptex]; | |
| if (!out->texture) | |
| { | |
| out->texture = r_notexture_mip; | |
| out->flags = 0; | |
| } | |
| } | |
| } | |
| } | |
| void CalcSurfaceExtents(msurface_t *s) | |
| { | |
| float mins[2]; | |
| float maxs[2]; | |
| float val; | |
| int32_t i; | |
| int32_t j; | |
| int32_t e; | |
| mvertex_t *v; | |
| mtexinfo_t *tex; | |
| int32_t bmins[2]; | |
| int32_t bmaxs[2]; | |
| mins[0] = (mins[1] = 999999); | |
| maxs[0] = (maxs[1] = -99999); | |
| tex = s->texinfo; | |
| for (i = 0; i < s->numedges; i++) | |
| { | |
| e = loadmodel->surfedges[s->firstedge + i]; | |
| if (e >= 0) | |
| v = &loadmodel->vertexes[loadmodel->edges[e].v[0]]; | |
| else | |
| v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]]; | |
| for (j = 0; j < 2; j++) | |
| { | |
| val = (((v->position[0] * tex->vecs[j][0]) + (v->position[1] * tex->vecs[j][1])) + (v->position[2] * tex->vecs[j][2])) + tex->vecs[j][3]; | |
| if (val < mins[j]) | |
| mins[j] = val; | |
| if (val > maxs[j]) | |
| maxs[j] = val; | |
| } | |
| } | |
| for (i = 0; i < 2; i++) | |
| { | |
| bmins[i] = floor(mins[i] / 16); | |
| bmaxs[i] = ceil(maxs[i] / 16); | |
| s->texturemins[i] = bmins[i] * 16; | |
| s->extents[i] = (bmaxs[i] - bmins[i]) * 16; | |
| if ((!(tex->flags & TEX_SPECIAL)) && (s->extents[i] > 256)) | |
| Sys_Error("Bad surface extents"); | |
| } | |
| } | |
| void Mod_LoadFaces(lump_t *l) | |
| { | |
| dface_t *in; | |
| msurface_t *out; | |
| int32_t i; | |
| int32_t count; | |
| int32_t surfnum; | |
| int32_t planenum; | |
| int32_t side; | |
| in = (void *) (mod_base + l->fileofs); | |
| if (l->filelen % (sizeof(*in))) | |
| Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); | |
| count = l->filelen / (sizeof(*in)); | |
| out = Hunk_AllocName(count * (sizeof(*out)), loadname); | |
| loadmodel->surfaces = out; | |
| loadmodel->numsurfaces = count; | |
| for (surfnum = 0; surfnum < count; surfnum++, in++, out++) | |
| { | |
| out->firstedge = in->firstedge; | |
| out->numedges = in->numedges; | |
| out->flags = 0; | |
| planenum = in->planenum; | |
| side = in->side; | |
| if (side) | |
| out->flags |= SURF_PLANEBACK; | |
| out->plane = loadmodel->planes + planenum; | |
| out->texinfo = loadmodel->texinfo + in->texinfo; | |
| CalcSurfaceExtents(out); | |
| for (i = 0; i < MAXLIGHTMAPS; i++) | |
| out->styles[i] = in->styles[i]; | |
| i = in->lightofs; | |
| if (i == (-1)) | |
| out->samples = 0; | |
| else | |
| out->samples = loadmodel->lightdata + i; | |
| if (!strncmp(out->texinfo->texture->name, "sky", 3)) | |
| { | |
| out->flags |= SURF_DRAWSKY | SURF_DRAWTILED; | |
| continue; | |
| } | |
| if (!strncmp(out->texinfo->texture->name, "*", 1)) | |
| { | |
| out->flags |= SURF_DRAWTURB | SURF_DRAWTILED; | |
| for (i = 0; i < 2; i++) | |
| { | |
| out->extents[i] = 16384; | |
| out->texturemins[i] = -8192; | |
| } | |
| continue; | |
| } | |
| } | |
| } | |
| void Mod_SetParent(mnode_t *node, mnode_t *parent) | |
| { | |
| node->parent = parent; | |
| if (node->contents < 0) | |
| return; | |
| Mod_SetParent(node->children[0], node); | |
| Mod_SetParent(node->children[1], node); | |
| } | |
| void Mod_LoadNodes(lump_t *l) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| int32_t count; | |
| int32_t p; | |
| dnode_t *in; | |
| mnode_t *out; | |
| in = (void *) (mod_base + l->fileofs); | |
| if (l->filelen % (sizeof(*in))) | |
| Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); | |
| count = l->filelen / (sizeof(*in)); | |
| out = Hunk_AllocName(count * (sizeof(*out)), loadname); | |
| loadmodel->nodes = out; | |
| loadmodel->numnodes = count; | |
| for (i = 0; i < count; i++, in++, out++) | |
| { | |
| for (j = 0; j < 3; j++) | |
| { | |
| out->minmaxs[j] = in->mins[j]; | |
| out->minmaxs[3 + j] = in->maxs[j]; | |
| } | |
| p = in->planenum; | |
| out->plane = loadmodel->planes + p; | |
| out->firstsurface = in->firstface; | |
| out->numsurfaces = in->numfaces; | |
| for (j = 0; j < 2; j++) | |
| { | |
| p = in->children[j]; | |
| if (p >= 0) | |
| out->children[j] = loadmodel->nodes + p; | |
| else | |
| out->children[j] = (mnode_t *) (loadmodel->leafs + ((-1) - p)); | |
| } | |
| } | |
| Mod_SetParent(loadmodel->nodes, 0); | |
| } | |
| void Mod_LoadLeafs(lump_t *l) | |
| { | |
| dleaf_t *in; | |
| mleaf_t *out; | |
| int32_t i; | |
| int32_t j; | |
| int32_t count; | |
| int32_t p; | |
| in = (void *) (mod_base + l->fileofs); | |
| if (l->filelen % (sizeof(*in))) | |
| Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); | |
| count = l->filelen / (sizeof(*in)); | |
| out = Hunk_AllocName(count * (sizeof(*out)), loadname); | |
| loadmodel->leafs = out; | |
| loadmodel->numleafs = count; | |
| for (i = 0; i < count; i++, in++, out++) | |
| { | |
| for (j = 0; j < 3; j++) | |
| { | |
| out->minmaxs[j] = in->mins[j]; | |
| out->minmaxs[3 + j] = in->maxs[j]; | |
| } | |
| p = in->contents; | |
| out->contents = p; | |
| out->firstmarksurface = loadmodel->marksurfaces + in->firstmarksurface; | |
| out->nummarksurfaces = in->nummarksurfaces; | |
| p = in->visofs; | |
| if (p == (-1)) | |
| out->compressed_vis = 0; | |
| else | |
| out->compressed_vis = loadmodel->visdata + p; | |
| out->efrags = 0; | |
| for (j = 0; j < 4; j++) | |
| out->ambient_sound_level[j] = in->ambient_level[j]; | |
| } | |
| } | |
| void Mod_LoadClipnodes(lump_t *l) | |
| { | |
| dclipnode_t *in; | |
| dclipnode_t *out; | |
| int32_t i; | |
| int32_t count; | |
| hull_t *hull; | |
| in = (void *) (mod_base + l->fileofs); | |
| if (l->filelen % (sizeof(*in))) | |
| Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); | |
| count = l->filelen / (sizeof(*in)); | |
| out = Hunk_AllocName(count * (sizeof(*out)), loadname); | |
| loadmodel->clipnodes = out; | |
| loadmodel->numclipnodes = count; | |
| hull = &loadmodel->hulls[1]; | |
| hull->clipnodes = out; | |
| hull->firstclipnode = 0; | |
| hull->lastclipnode = count - 1; | |
| hull->planes = loadmodel->planes; | |
| hull->clip_mins[0] = -16; | |
| hull->clip_mins[1] = -16; | |
| hull->clip_mins[2] = -24; | |
| hull->clip_maxs[0] = 16; | |
| hull->clip_maxs[1] = 16; | |
| hull->clip_maxs[2] = 32; | |
| hull = &loadmodel->hulls[2]; | |
| hull->clipnodes = out; | |
| hull->firstclipnode = 0; | |
| hull->lastclipnode = count - 1; | |
| hull->planes = loadmodel->planes; | |
| hull->clip_mins[0] = -32; | |
| hull->clip_mins[1] = -32; | |
| hull->clip_mins[2] = -24; | |
| hull->clip_maxs[0] = 32; | |
| hull->clip_maxs[1] = 32; | |
| hull->clip_maxs[2] = 64; | |
| for (i = 0; i < count; i++, out++, in++) | |
| { | |
| out->planenum = in->planenum; | |
| out->children[0] = in->children[0]; | |
| out->children[1] = in->children[1]; | |
| } | |
| } | |
| void Mod_MakeHull0(void) | |
| { | |
| mnode_t *in; | |
| mnode_t *child; | |
| dclipnode_t *out; | |
| int32_t i; | |
| int32_t j; | |
| int32_t count; | |
| hull_t *hull; | |
| hull = &loadmodel->hulls[0]; | |
| in = loadmodel->nodes; | |
| count = loadmodel->numnodes; | |
| out = Hunk_AllocName(count * (sizeof(*out)), loadname); | |
| hull->clipnodes = out; | |
| hull->firstclipnode = 0; | |
| hull->lastclipnode = count - 1; | |
| hull->planes = loadmodel->planes; | |
| for (i = 0; i < count; i++, out++, in++) | |
| { | |
| out->planenum = in->plane - loadmodel->planes; | |
| for (j = 0; j < 2; j++) | |
| { | |
| child = in->children[j]; | |
| if (child->contents < 0) | |
| out->children[j] = child->contents; | |
| else | |
| out->children[j] = child - loadmodel->nodes; | |
| } | |
| } | |
| } | |
| void Mod_LoadMarksurfaces(lump_t *l) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| int32_t count; | |
| int16_t *in; | |
| msurface_t **out; | |
| in = (void *) (mod_base + l->fileofs); | |
| if (l->filelen % (sizeof(*in))) | |
| Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); | |
| count = l->filelen / (sizeof(*in)); | |
| out = Hunk_AllocName(count * (sizeof(*out)), loadname); | |
| loadmodel->marksurfaces = out; | |
| loadmodel->nummarksurfaces = count; | |
| for (i = 0; i < count; i++) | |
| { | |
| j = in[i]; | |
| if (j >= loadmodel->numsurfaces) | |
| Sys_Error("Mod_ParseMarksurfaces: bad surface number"); | |
| out[i] = loadmodel->surfaces + j; | |
| } | |
| } | |
| void Mod_LoadSurfedges(lump_t *l) | |
| { | |
| int32_t i; | |
| int32_t count; | |
| int32_t *in; | |
| int32_t *out; | |
| in = (void *) (mod_base + l->fileofs); | |
| if (l->filelen % (sizeof(*in))) | |
| Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); | |
| count = l->filelen / (sizeof(*in)); | |
| out = Hunk_AllocName(count * (sizeof(*out)), loadname); | |
| loadmodel->surfedges = out; | |
| loadmodel->numsurfedges = count; | |
| for (i = 0; i < count; i++) | |
| out[i] = in[i]; | |
| } | |
| void Mod_LoadPlanes(lump_t *l) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| mplane_t *out; | |
| dplane_t *in; | |
| int32_t count; | |
| int32_t bits; | |
| in = (void *) (mod_base + l->fileofs); | |
| if (l->filelen % (sizeof(*in))) | |
| Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); | |
| count = l->filelen / (sizeof(*in)); | |
| out = Hunk_AllocName((count * 2) * (sizeof(*out)), loadname); | |
| loadmodel->planes = out; | |
| loadmodel->numplanes = count; | |
| for (i = 0; i < count; i++, in++, out++) | |
| { | |
| bits = 0; | |
| for (j = 0; j < 3; j++) | |
| { | |
| out->normal[j] = in->normal[j]; | |
| if (out->normal[j] < 0) | |
| bits |= 1 << j; | |
| } | |
| out->dist = in->dist; | |
| out->type = in->type; | |
| out->signbits = bits; | |
| } | |
| } | |
| float RadiusFromBounds(vec3_t mins, vec3_t maxs) | |
| { | |
| int32_t i; | |
| vec3_t corner; | |
| for (i = 0; i < 3; i++) | |
| { | |
| corner[i] = (fabs(mins[i]) > fabs(maxs[i])) ? (fabs(mins[i])) : (fabs(maxs[i])); | |
| } | |
| return Length(corner); | |
| } | |
| void Mod_LoadBrushModel(model_t *mod, void *buffer) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| dheader_t *header; | |
| dmodel_t *bm; | |
| loadmodel->type = mod_brush; | |
| header = (dheader_t *) buffer; | |
| i = header->version; | |
| if (i != BSPVERSION) | |
| Sys_Error("Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION); | |
| mod_base = (uint8_t *) header; | |
| for (i = 0; i < ((sizeof(dheader_t)) / 4); i++) | |
| ((int32_t *) header)[i] = ((int32_t *) header)[i]; | |
| Mod_LoadVertexes(&header->lumps[LUMP_VERTEXES]); | |
| Mod_LoadEdges(&header->lumps[LUMP_EDGES]); | |
| Mod_LoadSurfedges(&header->lumps[LUMP_SURFEDGES]); | |
| Mod_LoadTextures(&header->lumps[LUMP_TEXTURES]); | |
| Mod_LoadLighting(&header->lumps[LUMP_LIGHTING]); | |
| Mod_LoadPlanes(&header->lumps[LUMP_PLANES]); | |
| Mod_LoadTexinfo(&header->lumps[LUMP_TEXINFO]); | |
| Mod_LoadFaces(&header->lumps[LUMP_FACES]); | |
| Mod_LoadMarksurfaces(&header->lumps[LUMP_MARKSURFACES]); | |
| Mod_LoadVisibility(&header->lumps[LUMP_VISIBILITY]); | |
| Mod_LoadLeafs(&header->lumps[LUMP_LEAFS]); | |
| Mod_LoadNodes(&header->lumps[LUMP_NODES]); | |
| Mod_LoadClipnodes(&header->lumps[LUMP_CLIPNODES]); | |
| Mod_LoadEntities(&header->lumps[LUMP_ENTITIES]); | |
| Mod_LoadSubmodels(&header->lumps[LUMP_MODELS]); | |
| Mod_MakeHull0(); | |
| mod->numframes = 2; | |
| mod->flags = 0; | |
| for (i = 0; i < mod->numsubmodels; i++) | |
| { | |
| bm = &mod->submodels[i]; | |
| mod->hulls[0].firstclipnode = bm->headnode[0]; | |
| for (j = 1; j < MAX_MAP_HULLS; j++) | |
| { | |
| mod->hulls[j].firstclipnode = bm->headnode[j]; | |
| mod->hulls[j].lastclipnode = mod->numclipnodes - 1; | |
| } | |
| mod->firstmodelsurface = bm->firstface; | |
| mod->nummodelsurfaces = bm->numfaces; | |
| VectorCopy(bm->maxs, mod->maxs); | |
| VectorCopy(bm->mins, mod->mins); | |
| mod->radius = RadiusFromBounds(mod->mins, mod->maxs); | |
| mod->numleafs = bm->visleafs; | |
| if (i < (mod->numsubmodels - 1)) | |
| { | |
| char name[10]; | |
| sprintf(name, "*%i", i + 1); | |
| loadmodel = Mod_FindName(name); | |
| *loadmodel = *mod; | |
| strcpy(loadmodel->name, name); | |
| mod = loadmodel; | |
| } | |
| } | |
| } | |
| void *Mod_LoadAliasFrame(void *pin, int32_t *pframeindex, int32_t numv, trivertx_t *pbboxmin, trivertx_t *pbboxmax, aliashdr_t *pheader, char *name) | |
| { | |
| trivertx_t *pframe; | |
| trivertx_t *pinframe; | |
| int32_t i; | |
| int32_t j; | |
| daliasframe_t *pdaliasframe; | |
| pdaliasframe = (daliasframe_t *) pin; | |
| strcpy(name, pdaliasframe->name); | |
| for (i = 0; i < 3; i++) | |
| { | |
| pbboxmin->v[i] = pdaliasframe->bboxmin.v[i]; | |
| pbboxmax->v[i] = pdaliasframe->bboxmax.v[i]; | |
| } | |
| pinframe = (trivertx_t *) (pdaliasframe + 1); | |
| pframe = Hunk_AllocName(numv * (sizeof(*pframe)), loadname); | |
| *pframeindex = ((uint8_t *) pframe) - ((uint8_t *) pheader); | |
| for (j = 0; j < numv; j++) | |
| { | |
| int32_t k; | |
| pframe[j].lightnormalindex = pinframe[j].lightnormalindex; | |
| for (k = 0; k < 3; k++) | |
| { | |
| pframe[j].v[k] = pinframe[j].v[k]; | |
| } | |
| } | |
| pinframe += numv; | |
| return (void *) pinframe; | |
| } | |
| void *Mod_LoadAliasGroup(void *pin, int32_t *pframeindex, int32_t numv, trivertx_t *pbboxmin, trivertx_t *pbboxmax, aliashdr_t *pheader, char *name) | |
| { | |
| daliasgroup_t *pingroup; | |
| maliasgroup_t *paliasgroup; | |
| int32_t i; | |
| int32_t numframes; | |
| daliasinterval_t *pin_intervals; | |
| float *poutintervals; | |
| void *ptemp; | |
| pingroup = (daliasgroup_t *) pin; | |
| numframes = pingroup->numframes; | |
| paliasgroup = Hunk_AllocName((sizeof(maliasgroup_t)) + ((numframes - 1) * (sizeof(paliasgroup->frames[0]))), loadname); | |
| paliasgroup->numframes = numframes; | |
| for (i = 0; i < 3; i++) | |
| { | |
| pbboxmin->v[i] = pingroup->bboxmin.v[i]; | |
| pbboxmax->v[i] = pingroup->bboxmax.v[i]; | |
| } | |
| *pframeindex = ((uint8_t *) paliasgroup) - ((uint8_t *) pheader); | |
| pin_intervals = (daliasinterval_t *) (pingroup + 1); | |
| poutintervals = Hunk_AllocName(numframes * (sizeof(float)), loadname); | |
| paliasgroup->intervals = ((uint8_t *) poutintervals) - ((uint8_t *) pheader); | |
| for (i = 0; i < numframes; i++) | |
| { | |
| *poutintervals = pin_intervals->interval; | |
| if ((*poutintervals) <= 0.0) | |
| Sys_Error("Mod_LoadAliasGroup: interval<=0"); | |
| poutintervals++; | |
| pin_intervals++; | |
| } | |
| ptemp = (void *) pin_intervals; | |
| for (i = 0; i < numframes; i++) | |
| { | |
| ptemp = Mod_LoadAliasFrame(ptemp, &paliasgroup->frames[i].frame, numv, &paliasgroup->frames[i].bboxmin, &paliasgroup->frames[i].bboxmax, pheader, name); | |
| } | |
| return ptemp; | |
| } | |
| void *Mod_LoadAliasSkin(void *pin, int32_t *pskinindex, int32_t skinsize, aliashdr_t *pheader) | |
| { | |
| int32_t i; | |
| uint8_t *pskin; | |
| uint8_t *pinskin; | |
| uint16_t *pusskin; | |
| pskin = Hunk_AllocName(skinsize * r_pixbytes, loadname); | |
| pinskin = (uint8_t *) pin; | |
| *pskinindex = ((uint8_t *) pskin) - ((uint8_t *) pheader); | |
| if (r_pixbytes == 1) | |
| { | |
| memcpy(pskin, pinskin, skinsize); | |
| } | |
| else | |
| if (r_pixbytes == 2) | |
| { | |
| pusskin = (uint16_t *) pskin; | |
| for (i = 0; i < skinsize; i++) | |
| pusskin[i] = d_8to16table[pinskin[i]]; | |
| } | |
| else | |
| { | |
| Sys_Error("Mod_LoadAliasSkin: driver set invalid r_pixbytes: %d\n", r_pixbytes); | |
| } | |
| pinskin += skinsize; | |
| return (void *) pinskin; | |
| } | |
| void *Mod_LoadAliasSkinGroup(void *pin, int32_t *pskinindex, int32_t skinsize, aliashdr_t *pheader) | |
| { | |
| daliasskingroup_t *pinskingroup; | |
| maliasskingroup_t *paliasskingroup; | |
| int32_t i; | |
| int32_t numskins; | |
| daliasskininterval_t *pinskinintervals; | |
| float *poutskinintervals; | |
| void *ptemp; | |
| pinskingroup = (daliasskingroup_t *) pin; | |
| numskins = pinskingroup->numskins; | |
| paliasskingroup = Hunk_AllocName((sizeof(maliasskingroup_t)) + ((numskins - 1) * (sizeof(paliasskingroup->skindescs[0]))), loadname); | |
| paliasskingroup->numskins = numskins; | |
| *pskinindex = ((uint8_t *) paliasskingroup) - ((uint8_t *) pheader); | |
| pinskinintervals = (daliasskininterval_t *) (pinskingroup + 1); | |
| poutskinintervals = Hunk_AllocName(numskins * (sizeof(float)), loadname); | |
| paliasskingroup->intervals = ((uint8_t *) poutskinintervals) - ((uint8_t *) pheader); | |
| for (i = 0; i < numskins; i++) | |
| { | |
| *poutskinintervals = pinskinintervals->interval; | |
| if ((*poutskinintervals) <= 0) | |
| Sys_Error("Mod_LoadAliasSkinGroup: interval<=0"); | |
| poutskinintervals++; | |
| pinskinintervals++; | |
| } | |
| ptemp = (void *) pinskinintervals; | |
| for (i = 0; i < numskins; i++) | |
| { | |
| ptemp = Mod_LoadAliasSkin(ptemp, &paliasskingroup->skindescs[i].skin, skinsize, pheader); | |
| } | |
| return ptemp; | |
| } | |
| void Mod_LoadAliasModel(model_t *mod, void *buffer) | |
| { | |
| int32_t i; | |
| mdl_t *pmodel; | |
| mdl_t *pinmodel; | |
| stvert_t *pstverts; | |
| stvert_t *pinstverts; | |
| aliashdr_t *pheader; | |
| mtriangle_t *ptri; | |
| dtriangle_t *pintriangles; | |
| int32_t version; | |
| int32_t numframes; | |
| int32_t numskins; | |
| int32_t size; | |
| daliasframetype_t *pframetype; | |
| daliasskintype_t *pskintype; | |
| maliasskindesc_t *pskindesc; | |
| int32_t skinsize; | |
| int32_t start; | |
| int32_t end; | |
| int32_t total; | |
| start = Hunk_LowMark(); | |
| pinmodel = (mdl_t *) buffer; | |
| version = pinmodel->version; | |
| if (version != ALIAS_VERSION) | |
| Sys_Error("%s has wrong version number (%i should be %i)", mod->name, version, ALIAS_VERSION); | |
| size = ((((sizeof(aliashdr_t)) + ((pinmodel->numframes - 1) * (sizeof(pheader->frames[0])))) + (sizeof(mdl_t))) + (pinmodel->numverts * (sizeof(stvert_t)))) + (pinmodel->numtris * (sizeof(mtriangle_t))); | |
| pheader = Hunk_AllocName(size, loadname); | |
| pmodel = (mdl_t *) (((uint8_t *) (&pheader[1])) + ((pinmodel->numframes - 1) * (sizeof(pheader->frames[0])))); | |
| mod->flags = pinmodel->flags; | |
| pmodel->boundingradius = pinmodel->boundingradius; | |
| pmodel->numskins = pinmodel->numskins; | |
| pmodel->skinwidth = pinmodel->skinwidth; | |
| pmodel->skinheight = pinmodel->skinheight; | |
| if (pmodel->skinheight > MAX_LBM_HEIGHT) | |
| Sys_Error("model %s has a skin taller than %d", mod->name, MAX_LBM_HEIGHT); | |
| pmodel->numverts = pinmodel->numverts; | |
| if (pmodel->numverts <= 0) | |
| Sys_Error("model %s has no vertices", mod->name); | |
| if (pmodel->numverts > MAXALIASVERTS) | |
| Sys_Error("model %s has too many vertices", mod->name); | |
| pmodel->numtris = pinmodel->numtris; | |
| if (pmodel->numtris <= 0) | |
| Sys_Error("model %s has no triangles", mod->name); | |
| pmodel->numframes = pinmodel->numframes; | |
| pmodel->size = pinmodel->size * ALIAS_BASE_SIZE_RATIO; | |
| mod->synctype = pinmodel->synctype; | |
| mod->numframes = pmodel->numframes; | |
| for (i = 0; i < 3; i++) | |
| { | |
| pmodel->scale[i] = pinmodel->scale[i]; | |
| pmodel->scale_origin[i] = pinmodel->scale_origin[i]; | |
| pmodel->eyeposition[i] = pinmodel->eyeposition[i]; | |
| } | |
| numskins = pmodel->numskins; | |
| numframes = pmodel->numframes; | |
| if (pmodel->skinwidth & 0x03) | |
| Sys_Error("Mod_LoadAliasModel: skinwidth not multiple of 4"); | |
| pheader->model = ((uint8_t *) pmodel) - ((uint8_t *) pheader); | |
| skinsize = pmodel->skinheight * pmodel->skinwidth; | |
| if (numskins < 1) | |
| Sys_Error("Mod_LoadAliasModel: Invalid # of skins: %d\n", numskins); | |
| pskintype = (daliasskintype_t *) (&pinmodel[1]); | |
| pskindesc = Hunk_AllocName(numskins * (sizeof(maliasskindesc_t)), loadname); | |
| pheader->skindesc = ((uint8_t *) pskindesc) - ((uint8_t *) pheader); | |
| for (i = 0; i < numskins; i++) | |
| { | |
| aliasskintype_t skintype; | |
| skintype = pskintype->type; | |
| pskindesc[i].type = skintype; | |
| if (skintype == ALIAS_SKIN_SINGLE) | |
| { | |
| pskintype = (daliasskintype_t *) Mod_LoadAliasSkin(pskintype + 1, &pskindesc[i].skin, skinsize, pheader); | |
| } | |
| else | |
| { | |
| pskintype = (daliasskintype_t *) Mod_LoadAliasSkinGroup(pskintype + 1, &pskindesc[i].skin, skinsize, pheader); | |
| } | |
| } | |
| pstverts = (stvert_t *) (&pmodel[1]); | |
| pinstverts = (stvert_t *) pskintype; | |
| pheader->stverts = ((uint8_t *) pstverts) - ((uint8_t *) pheader); | |
| for (i = 0; i < pmodel->numverts; i++) | |
| { | |
| pstverts[i].onseam = pinstverts[i].onseam; | |
| pstverts[i].s = pinstverts[i].s << 16; | |
| pstverts[i].t = pinstverts[i].t << 16; | |
| } | |
| ptri = (mtriangle_t *) (&pstverts[pmodel->numverts]); | |
| pintriangles = (dtriangle_t *) (&pinstverts[pmodel->numverts]); | |
| pheader->triangles = ((uint8_t *) ptri) - ((uint8_t *) pheader); | |
| for (i = 0; i < pmodel->numtris; i++) | |
| { | |
| int32_t j; | |
| ptri[i].facesfront = pintriangles[i].facesfront; | |
| for (j = 0; j < 3; j++) | |
| { | |
| ptri[i].vertindex[j] = pintriangles[i].vertindex[j]; | |
| } | |
| } | |
| if (numframes < 1) | |
| Sys_Error("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes); | |
| pframetype = (daliasframetype_t *) (&pintriangles[pmodel->numtris]); | |
| for (i = 0; i < numframes; i++) | |
| { | |
| aliasframetype_t frametype; | |
| frametype = pframetype->type; | |
| pheader->frames[i].type = frametype; | |
| if (frametype == ALIAS_SINGLE) | |
| { | |
| pframetype = (daliasframetype_t *) Mod_LoadAliasFrame(pframetype + 1, &pheader->frames[i].frame, pmodel->numverts, &pheader->frames[i].bboxmin, &pheader->frames[i].bboxmax, pheader, pheader->frames[i].name); | |
| } | |
| else | |
| { | |
| pframetype = (daliasframetype_t *) Mod_LoadAliasGroup(pframetype + 1, &pheader->frames[i].frame, pmodel->numverts, &pheader->frames[i].bboxmin, &pheader->frames[i].bboxmax, pheader, pheader->frames[i].name); | |
| } | |
| } | |
| mod->type = mod_alias; | |
| mod->mins[0] = (mod->mins[1] = (mod->mins[2] = -16)); | |
| mod->maxs[0] = (mod->maxs[1] = (mod->maxs[2] = 16)); | |
| end = Hunk_LowMark(); | |
| total = end - start; | |
| Cache_Alloc(&mod->cache, total, loadname); | |
| if (!mod->cache.data) | |
| return; | |
| memcpy(mod->cache.data, pheader, total); | |
| Hunk_FreeToLowMark(start); | |
| } | |
| void *Mod_LoadSpriteFrame(void *pin, mspriteframe_t **ppframe) | |
| { | |
| dspriteframe_t *pinframe; | |
| mspriteframe_t *pspriteframe; | |
| int32_t i; | |
| int32_t width; | |
| int32_t height; | |
| int32_t size; | |
| int32_t origin[2]; | |
| uint16_t *ppixout; | |
| uint8_t *ppixin; | |
| pinframe = (dspriteframe_t *) pin; | |
| width = pinframe->width; | |
| height = pinframe->height; | |
| size = width * height; | |
| pspriteframe = Hunk_AllocName((sizeof(mspriteframe_t)) + (size * r_pixbytes), loadname); | |
| memset(pspriteframe, 0, (sizeof(mspriteframe_t)) + size); | |
| *ppframe = pspriteframe; | |
| pspriteframe->width = width; | |
| pspriteframe->height = height; | |
| origin[0] = pinframe->origin[0]; | |
| origin[1] = pinframe->origin[1]; | |
| pspriteframe->up = origin[1]; | |
| pspriteframe->down = origin[1] - height; | |
| pspriteframe->left = origin[0]; | |
| pspriteframe->right = width + origin[0]; | |
| if (r_pixbytes == 1) | |
| { | |
| memcpy(&pspriteframe->pixels[0], (uint8_t *) (pinframe + 1), size); | |
| } | |
| else | |
| if (r_pixbytes == 2) | |
| { | |
| ppixin = (uint8_t *) (pinframe + 1); | |
| ppixout = (uint16_t *) (&pspriteframe->pixels[0]); | |
| for (i = 0; i < size; i++) | |
| ppixout[i] = d_8to16table[ppixin[i]]; | |
| } | |
| else | |
| { | |
| Sys_Error("Mod_LoadSpriteFrame: driver set invalid r_pixbytes: %d\n", r_pixbytes); | |
| } | |
| return (void *) ((((uint8_t *) pinframe) + (sizeof(dspriteframe_t))) + size); | |
| } | |
| void *Mod_LoadSpriteGroup(void *pin, mspriteframe_t **ppframe) | |
| { | |
| dspritegroup_t *pingroup; | |
| mspritegroup_t *pspritegroup; | |
| int32_t i; | |
| int32_t numframes; | |
| dspriteinterval_t *pin_intervals; | |
| float *poutintervals; | |
| void *ptemp; | |
| pingroup = (dspritegroup_t *) pin; | |
| numframes = pingroup->numframes; | |
| pspritegroup = Hunk_AllocName((sizeof(mspritegroup_t)) + ((numframes - 1) * (sizeof(pspritegroup->frames[0]))), loadname); | |
| pspritegroup->numframes = numframes; | |
| *ppframe = (mspriteframe_t *) pspritegroup; | |
| pin_intervals = (dspriteinterval_t *) (pingroup + 1); | |
| poutintervals = Hunk_AllocName(numframes * (sizeof(float)), loadname); | |
| pspritegroup->intervals = poutintervals; | |
| for (i = 0; i < numframes; i++) | |
| { | |
| *poutintervals = pin_intervals->interval; | |
| if ((*poutintervals) <= 0.0) | |
| Sys_Error("Mod_LoadSpriteGroup: interval<=0"); | |
| poutintervals++; | |
| pin_intervals++; | |
| } | |
| ptemp = (void *) pin_intervals; | |
| for (i = 0; i < numframes; i++) | |
| { | |
| ptemp = Mod_LoadSpriteFrame(ptemp, &pspritegroup->frames[i]); | |
| } | |
| return ptemp; | |
| } | |
| void Mod_LoadSpriteModel(model_t *mod, void *buffer) | |
| { | |
| int32_t i; | |
| int32_t version; | |
| dsprite_t *pin; | |
| msprite_t *psprite; | |
| int32_t numframes; | |
| int32_t size; | |
| dspriteframetype_t *pframetype; | |
| pin = (dsprite_t *) buffer; | |
| version = pin->version; | |
| if (version != SPRITE_VERSION) | |
| Sys_Error("%s has wrong version number (%i should be %i)", mod->name, version, SPRITE_VERSION); | |
| numframes = pin->numframes; | |
| size = (sizeof(msprite_t)) + ((numframes - 1) * (sizeof(psprite->frames))); | |
| psprite = Hunk_AllocName(size, loadname); | |
| mod->cache.data = psprite; | |
| psprite->type = pin->type; | |
| psprite->maxwidth = pin->width; | |
| psprite->maxheight = pin->height; | |
| psprite->beamlength = pin->beamlength; | |
| mod->synctype = pin->synctype; | |
| psprite->numframes = numframes; | |
| mod->mins[0] = (mod->mins[1] = (-psprite->maxwidth) / 2); | |
| mod->maxs[0] = (mod->maxs[1] = psprite->maxwidth / 2); | |
| mod->mins[2] = (-psprite->maxheight) / 2; | |
| mod->maxs[2] = psprite->maxheight / 2; | |
| if (numframes < 1) | |
| Sys_Error("Mod_LoadSpriteModel: Invalid # of frames: %d\n", numframes); | |
| mod->numframes = numframes; | |
| mod->flags = 0; | |
| pframetype = (dspriteframetype_t *) (pin + 1); | |
| for (i = 0; i < numframes; i++) | |
| { | |
| spriteframetype_t frametype; | |
| frametype = pframetype->type; | |
| psprite->frames[i].type = frametype; | |
| if (frametype == SPR_SINGLE) | |
| { | |
| pframetype = (dspriteframetype_t *) Mod_LoadSpriteFrame(pframetype + 1, &psprite->frames[i].frameptr); | |
| } | |
| else | |
| { | |
| pframetype = (dspriteframetype_t *) Mod_LoadSpriteGroup(pframetype + 1, &psprite->frames[i].frameptr); | |
| } | |
| } | |
| mod->type = mod_sprite; | |
| } | |
| void Mod_Print(void) | |
| { | |
| int32_t i; | |
| model_t *mod; | |
| Con_Printf("Cached models:\n"); | |
| for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++) | |
| { | |
| Con_Printf("%8p : %s", mod->cache.data, mod->name); | |
| if (mod->needload & NL_UNREFERENCED) | |
| Con_Printf(" (!R)"); | |
| if (mod->needload & NL_NEEDS_LOADED) | |
| Con_Printf(" (!P)"); | |
| Con_Printf("\n"); | |
| } | |
| } | |
| int32_t Datagram_SendMessage(qsocket_t *sock, sizebuf_t *data) | |
| { | |
| uint32_t packetLen; | |
| uint32_t dataLen; | |
| uint32_t eom; | |
| memcpy(sock->sendMessage, data->data, data->cursize); | |
| sock->sendMessageLength = data->cursize; | |
| if (data->cursize <= MAX_DATAGRAM) | |
| { | |
| dataLen = data->cursize; | |
| eom = NETFLAG_EOM; | |
| } | |
| else | |
| { | |
| dataLen = MAX_DATAGRAM; | |
| eom = 0; | |
| } | |
| packetLen = NET_HEADERSIZE + dataLen; | |
| packetBuffer.length = packetLen | (NETFLAG_DATA | eom); | |
| packetBuffer.sequence = sock->sendSequence++; | |
| memcpy(packetBuffer.data, sock->sendMessage, dataLen); | |
| sock->canSend = 0; | |
| if (sfunc.Write(sock->socket, (uint8_t *) (&packetBuffer), packetLen, &sock->addr) == (-1)) | |
| return -1; | |
| sock->lastSendTime = net_time; | |
| packetsSent++; | |
| return 1; | |
| } | |
| int32_t SendMessageNext(qsocket_t *sock) | |
| { | |
| uint32_t packetLen; | |
| uint32_t dataLen; | |
| uint32_t eom; | |
| if (sock->sendMessageLength <= MAX_DATAGRAM) | |
| { | |
| dataLen = sock->sendMessageLength; | |
| eom = NETFLAG_EOM; | |
| } | |
| else | |
| { | |
| dataLen = MAX_DATAGRAM; | |
| eom = 0; | |
| } | |
| packetLen = NET_HEADERSIZE + dataLen; | |
| packetBuffer.length = packetLen | (NETFLAG_DATA | eom); | |
| packetBuffer.sequence = sock->sendSequence++; | |
| memcpy(packetBuffer.data, sock->sendMessage, dataLen); | |
| sock->sendNext = 0; | |
| if (sfunc.Write(sock->socket, (uint8_t *) (&packetBuffer), packetLen, &sock->addr) == (-1)) | |
| return -1; | |
| sock->lastSendTime = net_time; | |
| packetsSent++; | |
| return 1; | |
| } | |
| int32_t ReSendMessage(qsocket_t *sock) | |
| { | |
| uint32_t packetLen; | |
| uint32_t dataLen; | |
| uint32_t eom; | |
| if (sock->sendMessageLength <= MAX_DATAGRAM) | |
| { | |
| dataLen = sock->sendMessageLength; | |
| eom = NETFLAG_EOM; | |
| } | |
| else | |
| { | |
| dataLen = MAX_DATAGRAM; | |
| eom = 0; | |
| } | |
| packetLen = NET_HEADERSIZE + dataLen; | |
| packetBuffer.length = packetLen | (NETFLAG_DATA | eom); | |
| packetBuffer.sequence = sock->sendSequence - 1; | |
| memcpy(packetBuffer.data, sock->sendMessage, dataLen); | |
| sock->sendNext = 0; | |
| if (sfunc.Write(sock->socket, (uint8_t *) (&packetBuffer), packetLen, &sock->addr) == (-1)) | |
| return -1; | |
| sock->lastSendTime = net_time; | |
| packetsReSent++; | |
| return 1; | |
| } | |
| bool Datagram_CanSendMessage(qsocket_t *sock) | |
| { | |
| if (sock->sendNext) | |
| SendMessageNext(sock); | |
| return sock->canSend; | |
| } | |
| bool Datagram_CanSendUnreliableMessage(qsocket_t *sock) | |
| { | |
| return 1; | |
| } | |
| int32_t Datagram_SendUnreliableMessage(qsocket_t *sock, sizebuf_t *data) | |
| { | |
| int32_t packetLen; | |
| packetLen = NET_HEADERSIZE + data->cursize; | |
| packetBuffer.length = packetLen | NETFLAG_UNRELIABLE; | |
| packetBuffer.sequence = sock->unreliableSendSequence++; | |
| memcpy(packetBuffer.data, data->data, data->cursize); | |
| if (sfunc.Write(sock->socket, (uint8_t *) (&packetBuffer), packetLen, &sock->addr) == (-1)) | |
| return -1; | |
| packetsSent++; | |
| return 1; | |
| } | |
| int32_t Datagram_GetMessage(qsocket_t *sock) | |
| { | |
| uint32_t length; | |
| uint32_t flags; | |
| int32_t ret = 0; | |
| struct qsockaddr readaddr; | |
| uint32_t sequence; | |
| uint32_t count; | |
| if (!sock->canSend) | |
| if ((net_time - sock->lastSendTime) > 1.0) | |
| ReSendMessage(sock); | |
| while (1) | |
| { | |
| length = sfunc.Read(sock->socket, (uint8_t *) (&packetBuffer), NET_DATAGRAMSIZE, &readaddr); | |
| if (length == 0) | |
| break; | |
| if (length == (-1)) | |
| { | |
| Con_Printf("Read error\n"); | |
| return -1; | |
| } | |
| if (sfunc.AddrCompare(&readaddr, &sock->addr) != 0) | |
| { | |
| continue; | |
| } | |
| if (length < NET_HEADERSIZE) | |
| { | |
| shortPacketCount++; | |
| continue; | |
| } | |
| length = packetBuffer.length; | |
| flags = length & (~NETFLAG_LENGTH_MASK); | |
| length &= NETFLAG_LENGTH_MASK; | |
| if (flags & NETFLAG_CTL) | |
| continue; | |
| sequence = packetBuffer.sequence; | |
| packetsReceived++; | |
| if (flags & NETFLAG_UNRELIABLE) | |
| { | |
| if (sequence < sock->unreliableReceiveSequence) | |
| { | |
| Con_DPrintf("Got a stale datagram\n"); | |
| ret = 0; | |
| break; | |
| } | |
| if (sequence != sock->unreliableReceiveSequence) | |
| { | |
| count = sequence - sock->unreliableReceiveSequence; | |
| droppedDatagrams += count; | |
| Con_DPrintf("Dropped %u datagram(s)\n", count); | |
| } | |
| sock->unreliableReceiveSequence = sequence + 1; | |
| length -= NET_HEADERSIZE; | |
| SZ_Clear(&net_message); | |
| SZ_Write(&net_message, packetBuffer.data, length); | |
| ret = 2; | |
| break; | |
| } | |
| if (flags & NETFLAG_ACK) | |
| { | |
| if (sequence != (sock->sendSequence - 1)) | |
| { | |
| Con_DPrintf("Stale ACK received\n"); | |
| continue; | |
| } | |
| if (sequence == sock->ackSequence) | |
| { | |
| sock->ackSequence++; | |
| if (sock->ackSequence != sock->sendSequence) | |
| Con_DPrintf("ack sequencing error\n"); | |
| } | |
| else | |
| { | |
| Con_DPrintf("Duplicate ACK received\n"); | |
| continue; | |
| } | |
| sock->sendMessageLength -= MAX_DATAGRAM; | |
| if (sock->sendMessageLength > 0) | |
| { | |
| memcpy(sock->sendMessage, sock->sendMessage + MAX_DATAGRAM, sock->sendMessageLength); | |
| sock->sendNext = 1; | |
| } | |
| else | |
| { | |
| sock->sendMessageLength = 0; | |
| sock->canSend = 1; | |
| } | |
| continue; | |
| } | |
| if (flags & NETFLAG_DATA) | |
| { | |
| packetBuffer.length = NET_HEADERSIZE | NETFLAG_ACK; | |
| packetBuffer.sequence = sequence; | |
| sfunc.Write(sock->socket, (uint8_t *) (&packetBuffer), NET_HEADERSIZE, &readaddr); | |
| if (sequence != sock->receiveSequence) | |
| { | |
| receivedDuplicateCount++; | |
| continue; | |
| } | |
| sock->receiveSequence++; | |
| length -= NET_HEADERSIZE; | |
| if (flags & NETFLAG_EOM) | |
| { | |
| SZ_Clear(&net_message); | |
| SZ_Write(&net_message, sock->receiveMessage, sock->receiveMessageLength); | |
| SZ_Write(&net_message, packetBuffer.data, length); | |
| sock->receiveMessageLength = 0; | |
| ret = 1; | |
| break; | |
| } | |
| memcpy(sock->receiveMessage + sock->receiveMessageLength, packetBuffer.data, length); | |
| sock->receiveMessageLength += length; | |
| continue; | |
| } | |
| } | |
| if (sock->sendNext) | |
| SendMessageNext(sock); | |
| return ret; | |
| } | |
| void PrintStats(qsocket_t *s) | |
| { | |
| Con_Printf("canSend = %4u \n", s->canSend); | |
| Con_Printf("sendSeq = %4u ", s->sendSequence); | |
| Con_Printf("recvSeq = %4u \n", s->receiveSequence); | |
| Con_Printf("\n"); | |
| } | |
| void NET_Stats_f(void) | |
| { | |
| qsocket_t *s; | |
| if (Cmd_Argc() == 1) | |
| { | |
| Con_Printf("unreliable messages sent = %i\n", unreliableMessagesSent); | |
| Con_Printf("unreliable messages recv = %i\n", unreliableMessagesReceived); | |
| Con_Printf("reliable messages sent = %i\n", messagesSent); | |
| Con_Printf("reliable messages received = %i\n", messagesReceived); | |
| Con_Printf("packetsSent = %i\n", packetsSent); | |
| Con_Printf("packetsReSent = %i\n", packetsReSent); | |
| Con_Printf("packetsReceived = %i\n", packetsReceived); | |
| Con_Printf("receivedDuplicateCount = %i\n", receivedDuplicateCount); | |
| Con_Printf("shortPacketCount = %i\n", shortPacketCount); | |
| Con_Printf("droppedDatagrams = %i\n", droppedDatagrams); | |
| } | |
| else | |
| if (strcmp(Cmd_Argv(1), "*") == 0) | |
| { | |
| for (s = net_activeSockets; s; s = s->next) | |
| PrintStats(s); | |
| for (s = net_freeSockets; s; s = s->next) | |
| PrintStats(s); | |
| } | |
| else | |
| { | |
| for (s = net_activeSockets; s; s = s->next) | |
| if (strcasecmp(Cmd_Argv(1), s->address) == 0) | |
| break; | |
| if (s == 0) | |
| for (s = net_freeSockets; s; s = s->next) | |
| if (strcasecmp(Cmd_Argv(1), s->address) == 0) | |
| break; | |
| if (s == 0) | |
| return; | |
| PrintStats(s); | |
| } | |
| } | |
| static void Test_Poll(void) | |
| { | |
| struct qsockaddr clientaddr; | |
| int32_t control; | |
| int32_t len; | |
| char name[32]; | |
| char address[64]; | |
| int32_t colors; | |
| int32_t frags; | |
| int32_t connectTime; | |
| uint8_t playerNumber; | |
| net_landriverlevel = testDriver; | |
| while (1) | |
| { | |
| len = dfunc.Read(testSocket, net_message.data, net_message.maxsize, &clientaddr); | |
| if (len < (sizeof(int32_t))) | |
| break; | |
| net_message.cursize = len; | |
| MSG_BeginReading(); | |
| control = *((int32_t *) net_message.data); | |
| MSG_ReadLong(); | |
| if (control == (-1)) | |
| break; | |
| if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) | |
| break; | |
| if ((control & NETFLAG_LENGTH_MASK) != len) | |
| break; | |
| if (MSG_ReadByte() != CCREP_PLAYER_INFO) | |
| Sys_Error("Unexpected repsonse to Player Info request\n"); | |
| playerNumber = MSG_ReadByte(); | |
| strcpy(name, MSG_ReadString()); | |
| colors = MSG_ReadLong(); | |
| frags = MSG_ReadLong(); | |
| connectTime = MSG_ReadLong(); | |
| strcpy(address, MSG_ReadString()); | |
| Con_Printf("%s\n frags:%3i colors:%u %u time:%u\n %s\n", name, frags, colors >> 4, colors & 0x0f, connectTime / 60, address); | |
| } | |
| testPollCount--; | |
| if (testPollCount) | |
| { | |
| SchedulePollProcedure(&testPollProcedure, 0.1); | |
| } | |
| else | |
| { | |
| dfunc.CloseSocket(testSocket); | |
| testInProgress = 0; | |
| } | |
| } | |
| static void Test_f(void) | |
| { | |
| char *host; | |
| int32_t n; | |
| int32_t max = MAX_SCOREBOARD; | |
| struct qsockaddr sendaddr; | |
| if (testInProgress) | |
| return; | |
| host = Cmd_Argv(1); | |
| if (host && hostCacheCount) | |
| { | |
| for (n = 0; n < hostCacheCount; n++) | |
| if (strcasecmp(host, hostcache[n].name) == 0) | |
| { | |
| if (hostcache[n].driver != myDriverLevel) | |
| continue; | |
| net_landriverlevel = hostcache[n].ldriver; | |
| max = hostcache[n].maxusers; | |
| memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr)); | |
| break; | |
| } | |
| if (n < hostCacheCount) | |
| goto JustDoIt; | |
| } | |
| for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) | |
| { | |
| if (!net_landrivers[net_landriverlevel].initialized) | |
| continue; | |
| if (dfunc.GetAddrFromName(host, &sendaddr) != (-1)) | |
| break; | |
| } | |
| if (net_landriverlevel == net_numlandrivers) | |
| return; | |
| JustDoIt: | |
| testSocket = dfunc.OpenSocket(0); | |
| if (testSocket == (-1)) | |
| return; | |
| testInProgress = 1; | |
| testPollCount = 20; | |
| testDriver = net_landriverlevel; | |
| for (n = 0; n < max; n++) | |
| { | |
| SZ_Clear(&net_message); | |
| MSG_WriteLong(&net_message, 0); | |
| MSG_WriteByte(&net_message, CCREQ_PLAYER_INFO); | |
| MSG_WriteByte(&net_message, n); | |
| *((int32_t *) net_message.data) = NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK); | |
| dfunc.Write(testSocket, net_message.data, net_message.cursize, &sendaddr); | |
| } | |
| SZ_Clear(&net_message); | |
| SchedulePollProcedure(&testPollProcedure, 0.1); | |
| } | |
| static void Test2_Poll(void) | |
| { | |
| struct qsockaddr clientaddr; | |
| int32_t control; | |
| int32_t len; | |
| char name[256]; | |
| char value[256]; | |
| net_landriverlevel = test2Driver; | |
| name[0] = 0; | |
| len = dfunc.Read(test2Socket, net_message.data, net_message.maxsize, &clientaddr); | |
| if (len < (sizeof(int32_t))) | |
| goto Reschedule; | |
| net_message.cursize = len; | |
| MSG_BeginReading(); | |
| control = *((int32_t *) net_message.data); | |
| MSG_ReadLong(); | |
| if (control == (-1)) | |
| goto Error; | |
| if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) | |
| goto Error; | |
| if ((control & NETFLAG_LENGTH_MASK) != len) | |
| goto Error; | |
| if (MSG_ReadByte() != CCREP_RULE_INFO) | |
| goto Error; | |
| strcpy(name, MSG_ReadString()); | |
| if (name[0] == 0) | |
| goto Done; | |
| strcpy(value, MSG_ReadString()); | |
| Con_Printf("%-16.16s %-16.16s\n", name, value); | |
| SZ_Clear(&net_message); | |
| MSG_WriteLong(&net_message, 0); | |
| MSG_WriteByte(&net_message, CCREQ_RULE_INFO); | |
| MSG_WriteString(&net_message, name); | |
| *((int32_t *) net_message.data) = NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK); | |
| dfunc.Write(test2Socket, net_message.data, net_message.cursize, &clientaddr); | |
| SZ_Clear(&net_message); | |
| Reschedule: | |
| SchedulePollProcedure(&test2PollProcedure, 0.05); | |
| return; | |
| Error: | |
| Con_Printf("Unexpected repsonse to Rule Info request\n"); | |
| Done: | |
| dfunc.CloseSocket(test2Socket); | |
| test2InProgress = 0; | |
| return; | |
| } | |
| static void Test2_f(void) | |
| { | |
| char *host; | |
| int32_t n; | |
| struct qsockaddr sendaddr; | |
| if (test2InProgress) | |
| return; | |
| host = Cmd_Argv(1); | |
| if (host && hostCacheCount) | |
| { | |
| for (n = 0; n < hostCacheCount; n++) | |
| if (strcasecmp(host, hostcache[n].name) == 0) | |
| { | |
| if (hostcache[n].driver != myDriverLevel) | |
| continue; | |
| net_landriverlevel = hostcache[n].ldriver; | |
| memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr)); | |
| break; | |
| } | |
| if (n < hostCacheCount) | |
| goto JustDoIt; | |
| } | |
| for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) | |
| { | |
| if (!net_landrivers[net_landriverlevel].initialized) | |
| continue; | |
| if (dfunc.GetAddrFromName(host, &sendaddr) != (-1)) | |
| break; | |
| } | |
| if (net_landriverlevel == net_numlandrivers) | |
| return; | |
| JustDoIt: | |
| test2Socket = dfunc.OpenSocket(0); | |
| if (test2Socket == (-1)) | |
| return; | |
| test2InProgress = 1; | |
| test2Driver = net_landriverlevel; | |
| SZ_Clear(&net_message); | |
| MSG_WriteLong(&net_message, 0); | |
| MSG_WriteByte(&net_message, CCREQ_RULE_INFO); | |
| MSG_WriteString(&net_message, ""); | |
| *((int32_t *) net_message.data) = NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK); | |
| dfunc.Write(test2Socket, net_message.data, net_message.cursize, &sendaddr); | |
| SZ_Clear(&net_message); | |
| SchedulePollProcedure(&test2PollProcedure, 0.05); | |
| } | |
| int32_t Datagram_Init(void) | |
| { | |
| int32_t i; | |
| int32_t csock; | |
| myDriverLevel = net_driverlevel; | |
| Cmd_AddCommand("net_stats", NET_Stats_f); | |
| if (COM_CheckParm("-nolan")) | |
| return -1; | |
| for (i = 0; i < net_numlandrivers; i++) | |
| { | |
| csock = net_landrivers[i].Init(); | |
| if (csock == (-1)) | |
| continue; | |
| net_landrivers[i].initialized = 1; | |
| net_landrivers[i].controlSock = csock; | |
| } | |
| Cmd_AddCommand("test", Test_f); | |
| Cmd_AddCommand("test2", Test2_f); | |
| return 0; | |
| } | |
| void Datagram_Shutdown(void) | |
| { | |
| int32_t i; | |
| for (i = 0; i < net_numlandrivers; i++) | |
| { | |
| if (net_landrivers[i].initialized) | |
| { | |
| net_landrivers[i].Shutdown(); | |
| net_landrivers[i].initialized = 0; | |
| } | |
| } | |
| } | |
| void Datagram_Close(qsocket_t *sock) | |
| { | |
| sfunc.CloseSocket(sock->socket); | |
| } | |
| void Datagram_Listen(bool state) | |
| { | |
| int32_t i; | |
| for (i = 0; i < net_numlandrivers; i++) | |
| if (net_landrivers[i].initialized) | |
| net_landrivers[i].Listen(state); | |
| } | |
| static qsocket_t *_Datagram_CheckNewConnections(void) | |
| { | |
| struct qsockaddr clientaddr; | |
| struct qsockaddr newaddr; | |
| int32_t newsock; | |
| int32_t acceptsock; | |
| qsocket_t *sock; | |
| qsocket_t *s; | |
| int32_t len; | |
| int32_t command; | |
| int32_t control; | |
| int32_t ret; | |
| acceptsock = dfunc.CheckNewConnections(); | |
| if (acceptsock == (-1)) | |
| return 0; | |
| SZ_Clear(&net_message); | |
| len = dfunc.Read(acceptsock, net_message.data, net_message.maxsize, &clientaddr); | |
| if (len < (sizeof(int32_t))) | |
| return 0; | |
| net_message.cursize = len; | |
| MSG_BeginReading(); | |
| control = *((int32_t *) net_message.data); | |
| MSG_ReadLong(); | |
| if (control == (-1)) | |
| return 0; | |
| if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) | |
| return 0; | |
| if ((control & NETFLAG_LENGTH_MASK) != len) | |
| return 0; | |
| command = MSG_ReadByte(); | |
| if (command == CCREQ_SERVER_INFO) | |
| { | |
| if (strcmp(MSG_ReadString(), "QUAKE") != 0) | |
| return 0; | |
| SZ_Clear(&net_message); | |
| MSG_WriteLong(&net_message, 0); | |
| MSG_WriteByte(&net_message, CCREP_SERVER_INFO); | |
| dfunc.GetSocketAddr(acceptsock, &newaddr); | |
| MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr)); | |
| MSG_WriteString(&net_message, hostname.string); | |
| MSG_WriteString(&net_message, sv.name); | |
| MSG_WriteByte(&net_message, net_activeconnections); | |
| MSG_WriteByte(&net_message, svs.maxclients); | |
| MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION); | |
| *((int32_t *) net_message.data) = NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK); | |
| dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr); | |
| SZ_Clear(&net_message); | |
| return 0; | |
| } | |
| if (command == CCREQ_PLAYER_INFO) | |
| { | |
| int32_t playerNumber; | |
| int32_t activeNumber; | |
| int32_t clientNumber; | |
| client_t *client; | |
| playerNumber = MSG_ReadByte(); | |
| activeNumber = -1; | |
| for (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++) | |
| { | |
| if (client->active) | |
| { | |
| activeNumber++; | |
| if (activeNumber == playerNumber) | |
| break; | |
| } | |
| } | |
| if (clientNumber == svs.maxclients) | |
| return 0; | |
| SZ_Clear(&net_message); | |
| MSG_WriteLong(&net_message, 0); | |
| MSG_WriteByte(&net_message, CCREP_PLAYER_INFO); | |
| MSG_WriteByte(&net_message, playerNumber); | |
| MSG_WriteString(&net_message, client->name); | |
| MSG_WriteLong(&net_message, client->colors); | |
| MSG_WriteLong(&net_message, (int32_t) client->edict->v.frags); | |
| MSG_WriteLong(&net_message, (int32_t) (net_time - client->netconnection->connecttime)); | |
| MSG_WriteString(&net_message, client->netconnection->address); | |
| *((int32_t *) net_message.data) = NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK); | |
| dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr); | |
| SZ_Clear(&net_message); | |
| return 0; | |
| } | |
| if (command == CCREQ_RULE_INFO) | |
| { | |
| char *prevCvarName; | |
| cvar_t *var; | |
| prevCvarName = MSG_ReadString(); | |
| if (*prevCvarName) | |
| { | |
| var = Cvar_FindVar(prevCvarName); | |
| if (!var) | |
| return 0; | |
| var = var->next; | |
| } | |
| else | |
| var = cvar_vars; | |
| while (var) | |
| { | |
| if (var->server) | |
| break; | |
| var = var->next; | |
| } | |
| SZ_Clear(&net_message); | |
| MSG_WriteLong(&net_message, 0); | |
| MSG_WriteByte(&net_message, CCREP_RULE_INFO); | |
| if (var) | |
| { | |
| MSG_WriteString(&net_message, var->name); | |
| MSG_WriteString(&net_message, var->string); | |
| } | |
| *((int32_t *) net_message.data) = NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK); | |
| dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr); | |
| SZ_Clear(&net_message); | |
| return 0; | |
| } | |
| if (command != CCREQ_CONNECT) | |
| return 0; | |
| if (strcmp(MSG_ReadString(), "QUAKE") != 0) | |
| return 0; | |
| if (MSG_ReadByte() != NET_PROTOCOL_VERSION) | |
| { | |
| SZ_Clear(&net_message); | |
| MSG_WriteLong(&net_message, 0); | |
| MSG_WriteByte(&net_message, CCREP_REJECT); | |
| MSG_WriteString(&net_message, "Incompatible version.\n"); | |
| *((int32_t *) net_message.data) = NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK); | |
| dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr); | |
| SZ_Clear(&net_message); | |
| return 0; | |
| } | |
| for (s = net_activeSockets; s; s = s->next) | |
| { | |
| if (s->driver != net_driverlevel) | |
| continue; | |
| ret = dfunc.AddrCompare(&clientaddr, &s->addr); | |
| if (ret >= 0) | |
| { | |
| if ((ret == 0) && ((net_time - s->connecttime) < 2.0)) | |
| { | |
| SZ_Clear(&net_message); | |
| MSG_WriteLong(&net_message, 0); | |
| MSG_WriteByte(&net_message, CCREP_ACCEPT); | |
| dfunc.GetSocketAddr(s->socket, &newaddr); | |
| MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr)); | |
| *((int32_t *) net_message.data) = NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK); | |
| dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr); | |
| SZ_Clear(&net_message); | |
| return 0; | |
| } | |
| NET_Close(s); | |
| return 0; | |
| } | |
| } | |
| sock = NET_NewQSocket(); | |
| if (sock == 0) | |
| { | |
| SZ_Clear(&net_message); | |
| MSG_WriteLong(&net_message, 0); | |
| MSG_WriteByte(&net_message, CCREP_REJECT); | |
| MSG_WriteString(&net_message, "Server is full.\n"); | |
| *((int32_t *) net_message.data) = NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK); | |
| dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr); | |
| SZ_Clear(&net_message); | |
| return 0; | |
| } | |
| newsock = dfunc.OpenSocket(0); | |
| if (newsock == (-1)) | |
| { | |
| NET_FreeQSocket(sock); | |
| return 0; | |
| } | |
| if (dfunc.Connect(newsock, &clientaddr) == (-1)) | |
| { | |
| dfunc.CloseSocket(newsock); | |
| NET_FreeQSocket(sock); | |
| return 0; | |
| } | |
| sock->socket = newsock; | |
| sock->landriver = net_landriverlevel; | |
| sock->addr = clientaddr; | |
| strcpy(sock->address, dfunc.AddrToString(&clientaddr)); | |
| SZ_Clear(&net_message); | |
| MSG_WriteLong(&net_message, 0); | |
| MSG_WriteByte(&net_message, CCREP_ACCEPT); | |
| dfunc.GetSocketAddr(newsock, &newaddr); | |
| MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr)); | |
| *((int32_t *) net_message.data) = NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK); | |
| dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr); | |
| SZ_Clear(&net_message); | |
| return sock; | |
| } | |
| qsocket_t *Datagram_CheckNewConnections(void) | |
| { | |
| qsocket_t *ret = 0; | |
| for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) | |
| if (net_landrivers[net_landriverlevel].initialized) | |
| if ((ret = _Datagram_CheckNewConnections()) != 0) | |
| break; | |
| return ret; | |
| } | |
| static void _Datagram_SearchForHosts(bool xmit) | |
| { | |
| int32_t ret; | |
| int32_t n; | |
| int32_t i; | |
| struct qsockaddr readaddr; | |
| struct qsockaddr myaddr; | |
| int32_t control; | |
| dfunc.GetSocketAddr(dfunc.controlSock, &myaddr); | |
| if (xmit) | |
| { | |
| SZ_Clear(&net_message); | |
| MSG_WriteLong(&net_message, 0); | |
| MSG_WriteByte(&net_message, CCREQ_SERVER_INFO); | |
| MSG_WriteString(&net_message, "QUAKE"); | |
| MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION); | |
| *((int32_t *) net_message.data) = NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK); | |
| dfunc.Broadcast(dfunc.controlSock, net_message.data, net_message.cursize); | |
| SZ_Clear(&net_message); | |
| } | |
| while ((ret = dfunc.Read(dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0) | |
| { | |
| if (ret < (sizeof(int32_t))) | |
| continue; | |
| net_message.cursize = ret; | |
| if (dfunc.AddrCompare(&readaddr, &myaddr) >= 0) | |
| continue; | |
| if (hostCacheCount == HOSTCACHESIZE) | |
| continue; | |
| MSG_BeginReading(); | |
| control = *((int32_t *) net_message.data); | |
| MSG_ReadLong(); | |
| if (control == (-1)) | |
| continue; | |
| if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) | |
| continue; | |
| if ((control & NETFLAG_LENGTH_MASK) != ret) | |
| continue; | |
| if (MSG_ReadByte() != CCREP_SERVER_INFO) | |
| continue; | |
| dfunc.GetAddrFromName(MSG_ReadString(), &readaddr); | |
| for (n = 0; n < hostCacheCount; n++) | |
| if (dfunc.AddrCompare(&readaddr, &hostcache[n].addr) == 0) | |
| break; | |
| if (n < hostCacheCount) | |
| continue; | |
| hostCacheCount++; | |
| strcpy(hostcache[n].name, MSG_ReadString()); | |
| strcpy(hostcache[n].map, MSG_ReadString()); | |
| hostcache[n].users = MSG_ReadByte(); | |
| hostcache[n].maxusers = MSG_ReadByte(); | |
| if (MSG_ReadByte() != NET_PROTOCOL_VERSION) | |
| { | |
| strcpy(hostcache[n].cname, hostcache[n].name); | |
| hostcache[n].cname[14] = 0; | |
| strcpy(hostcache[n].name, "*"); | |
| strcat(hostcache[n].name, hostcache[n].cname); | |
| } | |
| memcpy(&hostcache[n].addr, &readaddr, sizeof(struct qsockaddr)); | |
| hostcache[n].driver = net_driverlevel; | |
| hostcache[n].ldriver = net_landriverlevel; | |
| strcpy(hostcache[n].cname, dfunc.AddrToString(&readaddr)); | |
| for (i = 0; i < hostCacheCount; i++) | |
| { | |
| if (i == n) | |
| continue; | |
| if (strcasecmp(hostcache[n].name, hostcache[i].name) == 0) | |
| { | |
| i = strlen(hostcache[n].name); | |
| if ((i < 15) && (hostcache[n].name[i - 1] > '8')) | |
| { | |
| hostcache[n].name[i] = '0'; | |
| hostcache[n].name[i + 1] = 0; | |
| } | |
| else | |
| hostcache[n].name[i - 1]++; | |
| i = -1; | |
| } | |
| } | |
| } | |
| } | |
| void Datagram_SearchForHosts(bool xmit) | |
| { | |
| for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) | |
| { | |
| if (hostCacheCount == HOSTCACHESIZE) | |
| break; | |
| if (net_landrivers[net_landriverlevel].initialized) | |
| _Datagram_SearchForHosts(xmit); | |
| } | |
| } | |
| static qsocket_t *_Datagram_Connect(char *host) | |
| { | |
| struct qsockaddr sendaddr; | |
| struct qsockaddr readaddr; | |
| qsocket_t *sock; | |
| int32_t newsock; | |
| int32_t ret; | |
| int32_t reps; | |
| double start_time; | |
| int32_t control; | |
| char *reason; | |
| if (dfunc.GetAddrFromName(host, &sendaddr) == (-1)) | |
| return 0; | |
| newsock = dfunc.OpenSocket(0); | |
| if (newsock == (-1)) | |
| return 0; | |
| sock = NET_NewQSocket(); | |
| if (sock == 0) | |
| goto ErrorReturn2; | |
| sock->socket = newsock; | |
| sock->landriver = net_landriverlevel; | |
| if (dfunc.Connect(newsock, &sendaddr) == (-1)) | |
| goto ErrorReturn; | |
| Con_Printf("trying...\n"); | |
| SCR_UpdateScreen(); | |
| start_time = net_time; | |
| for (reps = 0; reps < 3; reps++) | |
| { | |
| SZ_Clear(&net_message); | |
| MSG_WriteLong(&net_message, 0); | |
| MSG_WriteByte(&net_message, CCREQ_CONNECT); | |
| MSG_WriteString(&net_message, "QUAKE"); | |
| MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION); | |
| *((int32_t *) net_message.data) = NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK); | |
| dfunc.Write(newsock, net_message.data, net_message.cursize, &sendaddr); | |
| SZ_Clear(&net_message); | |
| do | |
| { | |
| ret = dfunc.Read(newsock, net_message.data, net_message.maxsize, &readaddr); | |
| if (ret > 0) | |
| { | |
| if (sfunc.AddrCompare(&readaddr, &sendaddr) != 0) | |
| { | |
| ret = 0; | |
| continue; | |
| } | |
| if (ret < (sizeof(int32_t))) | |
| { | |
| ret = 0; | |
| continue; | |
| } | |
| net_message.cursize = ret; | |
| MSG_BeginReading(); | |
| control = *((int32_t *) net_message.data); | |
| MSG_ReadLong(); | |
| if (control == (-1)) | |
| { | |
| ret = 0; | |
| continue; | |
| } | |
| if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) | |
| { | |
| ret = 0; | |
| continue; | |
| } | |
| if ((control & NETFLAG_LENGTH_MASK) != ret) | |
| { | |
| ret = 0; | |
| continue; | |
| } | |
| } | |
| } | |
| while ((ret == 0) && ((SetNetTime() - start_time) < 2.5)); | |
| if (ret) | |
| break; | |
| Con_Printf("still trying...\n"); | |
| SCR_UpdateScreen(); | |
| start_time = SetNetTime(); | |
| } | |
| if (ret == 0) | |
| { | |
| reason = "No Response"; | |
| Con_Printf("%s\n", reason); | |
| strcpy(m_return_reason, reason); | |
| goto ErrorReturn; | |
| } | |
| if (ret == (-1)) | |
| { | |
| reason = "Network Error"; | |
| Con_Printf("%s\n", reason); | |
| strcpy(m_return_reason, reason); | |
| goto ErrorReturn; | |
| } | |
| ret = MSG_ReadByte(); | |
| if (ret == CCREP_REJECT) | |
| { | |
| reason = MSG_ReadString(); | |
| Con_Printf(reason); | |
| strncpy(m_return_reason, reason, 31); | |
| goto ErrorReturn; | |
| } | |
| if (ret == CCREP_ACCEPT) | |
| { | |
| memcpy(&sock->addr, &sendaddr, sizeof(struct qsockaddr)); | |
| dfunc.SetSocketPort(&sock->addr, MSG_ReadLong()); | |
| } | |
| else | |
| { | |
| reason = "Bad Response"; | |
| Con_Printf("%s\n", reason); | |
| strcpy(m_return_reason, reason); | |
| goto ErrorReturn; | |
| } | |
| dfunc.GetNameFromAddr(&sendaddr, sock->address); | |
| Con_Printf("Connection accepted\n"); | |
| sock->lastMessageTime = SetNetTime(); | |
| if (dfunc.Connect(newsock, &sock->addr) == (-1)) | |
| { | |
| reason = "Connect to Game failed"; | |
| Con_Printf("%s\n", reason); | |
| strcpy(m_return_reason, reason); | |
| goto ErrorReturn; | |
| } | |
| m_return_onerror = 0; | |
| return sock; | |
| ErrorReturn: | |
| NET_FreeQSocket(sock); | |
| ErrorReturn2: | |
| dfunc.CloseSocket(newsock); | |
| if (m_return_onerror) | |
| { | |
| key_dest = key_menu; | |
| m_state = m_return_state; | |
| m_return_onerror = 0; | |
| } | |
| return 0; | |
| } | |
| qsocket_t *Datagram_Connect(char *host) | |
| { | |
| qsocket_t *ret = 0; | |
| for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) | |
| if (net_landrivers[net_landriverlevel].initialized) | |
| if ((ret = _Datagram_Connect(host)) != 0) | |
| break; | |
| return ret; | |
| } | |
| int32_t Loop_Init(void) | |
| { | |
| if (cls.state == ca_dedicated) | |
| return -1; | |
| return 0; | |
| } | |
| void Loop_Shutdown(void) | |
| { | |
| } | |
| void Loop_Listen(bool state) | |
| { | |
| } | |
| void Loop_SearchForHosts(bool xmit) | |
| { | |
| if (!sv.active) | |
| return; | |
| hostCacheCount = 1; | |
| if (strcmp(hostname.string, "UNNAMED") == 0) | |
| strcpy(hostcache[0].name, "local"); | |
| else | |
| strcpy(hostcache[0].name, hostname.string); | |
| strcpy(hostcache[0].map, sv.name); | |
| hostcache[0].users = net_activeconnections; | |
| hostcache[0].maxusers = svs.maxclients; | |
| hostcache[0].driver = net_driverlevel; | |
| strcpy(hostcache[0].cname, "local"); | |
| } | |
| qsocket_t *Loop_Connect(char *host) | |
| { | |
| if (strcmp(host, "local") != 0) | |
| return 0; | |
| localconnectpending = 1; | |
| if (!loop_client) | |
| { | |
| if ((loop_client = NET_NewQSocket()) == 0) | |
| { | |
| Con_Printf("Loop_Connect: no qsocket available\n"); | |
| return 0; | |
| } | |
| strcpy(loop_client->address, "localhost"); | |
| } | |
| loop_client->receiveMessageLength = 0; | |
| loop_client->sendMessageLength = 0; | |
| loop_client->canSend = 1; | |
| if (!loop_server) | |
| { | |
| if ((loop_server = NET_NewQSocket()) == 0) | |
| { | |
| Con_Printf("Loop_Connect: no qsocket available\n"); | |
| return 0; | |
| } | |
| strcpy(loop_server->address, "LOCAL"); | |
| } | |
| loop_server->receiveMessageLength = 0; | |
| loop_server->sendMessageLength = 0; | |
| loop_server->canSend = 1; | |
| loop_client->driverdata = (void *) loop_server; | |
| loop_server->driverdata = (void *) loop_client; | |
| return loop_client; | |
| } | |
| qsocket_t *Loop_CheckNewConnections(void) | |
| { | |
| if (!localconnectpending) | |
| return 0; | |
| localconnectpending = 0; | |
| loop_server->sendMessageLength = 0; | |
| loop_server->receiveMessageLength = 0; | |
| loop_server->canSend = 1; | |
| loop_client->sendMessageLength = 0; | |
| loop_client->receiveMessageLength = 0; | |
| loop_client->canSend = 1; | |
| return loop_server; | |
| } | |
| static int32_t IntAlign(int32_t value) | |
| { | |
| return (value + ((sizeof(int32_t)) - 1)) & (~((sizeof(int32_t)) - 1)); | |
| } | |
| int32_t Loop_GetMessage(qsocket_t *sock) | |
| { | |
| int32_t ret; | |
| int32_t length; | |
| if (sock->receiveMessageLength == 0) | |
| return 0; | |
| ret = sock->receiveMessage[0]; | |
| length = sock->receiveMessage[1] + (sock->receiveMessage[2] << 8); | |
| SZ_Clear(&net_message); | |
| SZ_Write(&net_message, &sock->receiveMessage[4], length); | |
| length = IntAlign(length + 4); | |
| sock->receiveMessageLength -= length; | |
| if (sock->receiveMessageLength) | |
| memcpy(sock->receiveMessage, &sock->receiveMessage[length], sock->receiveMessageLength); | |
| if (sock->driverdata && (ret == 1)) | |
| ((qsocket_t *) sock->driverdata)->canSend = 1; | |
| return ret; | |
| } | |
| int32_t Loop_SendMessage(qsocket_t *sock, sizebuf_t *data) | |
| { | |
| uint8_t *buffer; | |
| int32_t *bufferLength; | |
| if (!sock->driverdata) | |
| return -1; | |
| bufferLength = &((qsocket_t *) sock->driverdata)->receiveMessageLength; | |
| if ((((*bufferLength) + data->cursize) + 4) > NET_MAXMESSAGE) | |
| Sys_Error("Loop_SendMessage: overflow\n"); | |
| buffer = ((qsocket_t *) sock->driverdata)->receiveMessage + (*bufferLength); | |
| *(buffer++) = 1; | |
| *(buffer++) = data->cursize & 0xff; | |
| *(buffer++) = data->cursize >> 8; | |
| buffer++; | |
| memcpy(buffer, data->data, data->cursize); | |
| *bufferLength = IntAlign(((*bufferLength) + data->cursize) + 4); | |
| sock->canSend = 0; | |
| return 1; | |
| } | |
| int32_t Loop_SendUnreliableMessage(qsocket_t *sock, sizebuf_t *data) | |
| { | |
| uint8_t *buffer; | |
| int32_t *bufferLength; | |
| if (!sock->driverdata) | |
| return -1; | |
| bufferLength = &((qsocket_t *) sock->driverdata)->receiveMessageLength; | |
| if (((((*bufferLength) + data->cursize) + (sizeof(uint8_t))) + (sizeof(int16_t))) > NET_MAXMESSAGE) | |
| return 0; | |
| buffer = ((qsocket_t *) sock->driverdata)->receiveMessage + (*bufferLength); | |
| *(buffer++) = 2; | |
| *(buffer++) = data->cursize & 0xff; | |
| *(buffer++) = data->cursize >> 8; | |
| buffer++; | |
| memcpy(buffer, data->data, data->cursize); | |
| *bufferLength = IntAlign(((*bufferLength) + data->cursize) + 4); | |
| return 1; | |
| } | |
| bool Loop_CanSendMessage(qsocket_t *sock) | |
| { | |
| if (!sock->driverdata) | |
| return 0; | |
| return sock->canSend; | |
| } | |
| bool Loop_CanSendUnreliableMessage(qsocket_t *sock) | |
| { | |
| return 1; | |
| } | |
| void Loop_Close(qsocket_t *sock) | |
| { | |
| if (sock->driverdata) | |
| ((qsocket_t *) sock->driverdata)->driverdata = 0; | |
| sock->receiveMessageLength = 0; | |
| sock->sendMessageLength = 0; | |
| sock->canSend = 1; | |
| if (sock == loop_client) | |
| loop_client = 0; | |
| else | |
| loop_server = 0; | |
| } | |
| double SetNetTime(void) | |
| { | |
| net_time = Sys_FloatTime(); | |
| return net_time; | |
| } | |
| qsocket_t *NET_NewQSocket(void) | |
| { | |
| qsocket_t *sock; | |
| if (net_freeSockets == 0) | |
| return 0; | |
| if (net_activeconnections >= svs.maxclients) | |
| return 0; | |
| sock = net_freeSockets; | |
| net_freeSockets = sock->next; | |
| sock->next = net_activeSockets; | |
| net_activeSockets = sock; | |
| sock->disconnected = 0; | |
| sock->connecttime = net_time; | |
| strcpy(sock->address, "UNSET ADDRESS"); | |
| sock->driver = net_driverlevel; | |
| sock->socket = 0; | |
| sock->driverdata = 0; | |
| sock->canSend = 1; | |
| sock->sendNext = 0; | |
| sock->lastMessageTime = net_time; | |
| sock->ackSequence = 0; | |
| sock->sendSequence = 0; | |
| sock->unreliableSendSequence = 0; | |
| sock->sendMessageLength = 0; | |
| sock->receiveSequence = 0; | |
| sock->unreliableReceiveSequence = 0; | |
| sock->receiveMessageLength = 0; | |
| return sock; | |
| } | |
| void NET_FreeQSocket(qsocket_t *sock) | |
| { | |
| qsocket_t *s; | |
| if (sock == net_activeSockets) | |
| net_activeSockets = net_activeSockets->next; | |
| else | |
| { | |
| for (s = net_activeSockets; s; s = s->next) | |
| if (s->next == sock) | |
| { | |
| s->next = sock->next; | |
| break; | |
| } | |
| if (!s) | |
| Sys_Error("NET_FreeQSocket: not active\n"); | |
| } | |
| sock->next = net_freeSockets; | |
| net_freeSockets = sock; | |
| sock->disconnected = 1; | |
| } | |
| static void NET_Listen_f(void) | |
| { | |
| if (Cmd_Argc() != 2) | |
| { | |
| Con_Printf("\"listen\" is \"%u\"\n", (listening) ? (1) : (0)); | |
| return; | |
| } | |
| listening = ((int32_t) strtol(Cmd_Argv(1), 0, 0)) ? (1) : (0); | |
| for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++) | |
| { | |
| if (net_drivers[net_driverlevel].initialized == 0) | |
| continue; | |
| net_drivers[net_driverlevel].Listen(listening); | |
| } | |
| } | |
| static void MaxPlayers_f(void) | |
| { | |
| int32_t n; | |
| if (Cmd_Argc() != 2) | |
| { | |
| Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients); | |
| return; | |
| } | |
| if (sv.active) | |
| { | |
| Con_Printf("maxplayers can not be changed while a server is running.\n"); | |
| return; | |
| } | |
| n = (int32_t) strtol(Cmd_Argv(1), 0, 0); | |
| if (n < 1) | |
| n = 1; | |
| if (n > svs.maxclientslimit) | |
| { | |
| n = svs.maxclientslimit; | |
| Con_Printf("\"maxplayers\" set to \"%u\"\n", n); | |
| } | |
| if ((n == 1) && listening) | |
| Cbuf_AddText("listen 0\n"); | |
| if ((n > 1) && (!listening)) | |
| Cbuf_AddText("listen 1\n"); | |
| svs.maxclients = n; | |
| if (n == 1) | |
| Cvar_Set("deathmatch", "0"); | |
| else | |
| Cvar_Set("deathmatch", "1"); | |
| } | |
| static void NET_Port_f(void) | |
| { | |
| int32_t n; | |
| if (Cmd_Argc() != 2) | |
| { | |
| Con_Printf("\"port\" is \"%u\"\n", net_hostport); | |
| return; | |
| } | |
| n = (int32_t) strtol(Cmd_Argv(1), 0, 0); | |
| if ((n < 1) || (n > 65534)) | |
| { | |
| Con_Printf("Bad value, must be between 1 and 65534\n"); | |
| return; | |
| } | |
| DEFAULTnet_hostport = n; | |
| net_hostport = n; | |
| if (listening) | |
| { | |
| Cbuf_AddText("listen 0\n"); | |
| Cbuf_AddText("listen 1\n"); | |
| } | |
| } | |
| static void PrintSlistHeader(void) | |
| { | |
| Con_Printf("Server Map Users\n"); | |
| Con_Printf("--------------- --------------- -----\n"); | |
| slistLastShown = 0; | |
| } | |
| static void PrintSlist(void) | |
| { | |
| int32_t n; | |
| for (n = slistLastShown; n < hostCacheCount; n++) | |
| { | |
| if (hostcache[n].maxusers) | |
| Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers); | |
| else | |
| Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map); | |
| } | |
| slistLastShown = n; | |
| } | |
| static void PrintSlistTrailer(void) | |
| { | |
| if (hostCacheCount) | |
| Con_Printf("== end list ==\n\n"); | |
| else | |
| Con_Printf("No Quake servers found.\n\n"); | |
| } | |
| void NET_Slist_f(void) | |
| { | |
| if (slistInProgress) | |
| return; | |
| if (!slistSilent) | |
| { | |
| Con_Printf("Looking for Quake servers...\n"); | |
| PrintSlistHeader(); | |
| } | |
| slistInProgress = 1; | |
| slistStartTime = Sys_FloatTime(); | |
| SchedulePollProcedure(&slistSendProcedure, 0.0); | |
| SchedulePollProcedure(&slistPollProcedure, 0.1); | |
| hostCacheCount = 0; | |
| } | |
| static void Slist_Send(void) | |
| { | |
| for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++) | |
| { | |
| if ((!slistLocal) && (net_driverlevel == 0)) | |
| continue; | |
| if (net_drivers[net_driverlevel].initialized == 0) | |
| continue; | |
| net_drivers[net_driverlevel].SearchForHosts(1); | |
| } | |
| if ((Sys_FloatTime() - slistStartTime) < 0.5) | |
| SchedulePollProcedure(&slistSendProcedure, 0.75); | |
| } | |
| static void Slist_Poll(void) | |
| { | |
| for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++) | |
| { | |
| if ((!slistLocal) && (net_driverlevel == 0)) | |
| continue; | |
| if (net_drivers[net_driverlevel].initialized == 0) | |
| continue; | |
| net_drivers[net_driverlevel].SearchForHosts(0); | |
| } | |
| if (!slistSilent) | |
| PrintSlist(); | |
| if ((Sys_FloatTime() - slistStartTime) < 1.5) | |
| { | |
| SchedulePollProcedure(&slistPollProcedure, 0.1); | |
| return; | |
| } | |
| if (!slistSilent) | |
| PrintSlistTrailer(); | |
| slistInProgress = 0; | |
| slistSilent = 0; | |
| slistLocal = 1; | |
| } | |
| qsocket_t *NET_Connect(char *host) | |
| { | |
| qsocket_t *ret; | |
| int32_t n; | |
| int32_t numdrivers = net_numdrivers; | |
| SetNetTime(); | |
| if (host && ((*host) == 0)) | |
| host = 0; | |
| if (host) | |
| { | |
| if (strcasecmp(host, "local") == 0) | |
| { | |
| numdrivers = 1; | |
| goto JustDoIt; | |
| } | |
| if (hostCacheCount) | |
| { | |
| for (n = 0; n < hostCacheCount; n++) | |
| if (strcasecmp(host, hostcache[n].name) == 0) | |
| { | |
| host = hostcache[n].cname; | |
| break; | |
| } | |
| if (n < hostCacheCount) | |
| goto JustDoIt; | |
| } | |
| } | |
| slistSilent = (host) ? (1) : (0); | |
| NET_Slist_f(); | |
| while (slistInProgress) | |
| NET_Poll(); | |
| if (host == 0) | |
| { | |
| if (hostCacheCount != 1) | |
| return 0; | |
| host = hostcache[0].cname; | |
| Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host); | |
| } | |
| if (hostCacheCount) | |
| for (n = 0; n < hostCacheCount; n++) | |
| if (strcasecmp(host, hostcache[n].name) == 0) | |
| { | |
| host = hostcache[n].cname; | |
| break; | |
| } | |
| JustDoIt: | |
| for (net_driverlevel = 0; net_driverlevel < numdrivers; net_driverlevel++) | |
| { | |
| if (net_drivers[net_driverlevel].initialized == 0) | |
| continue; | |
| ret = net_drivers[net_driverlevel].Connect(host); | |
| if (ret) | |
| return ret; | |
| } | |
| if (host) | |
| { | |
| Con_Printf("\n"); | |
| PrintSlistHeader(); | |
| PrintSlist(); | |
| PrintSlistTrailer(); | |
| } | |
| return 0; | |
| } | |
| qsocket_t *NET_CheckNewConnections(void) | |
| { | |
| qsocket_t *ret; | |
| SetNetTime(); | |
| for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++) | |
| { | |
| if (net_drivers[net_driverlevel].initialized == 0) | |
| continue; | |
| if (net_driverlevel && (listening == 0)) | |
| continue; | |
| ret = net_drivers[net_driverlevel].CheckNewConnections(); | |
| if (ret) | |
| { | |
| if (recording) | |
| { | |
| vcrConnect.time = host_time; | |
| vcrConnect.op = VCR_OP_CONNECT; | |
| vcrConnect.session = (int32_t) ret; | |
| Sys_FileWrite(vcrFile, &vcrConnect, sizeof(vcrConnect)); | |
| Sys_FileWrite(vcrFile, ret->address, NET_NAMELEN); | |
| } | |
| return ret; | |
| } | |
| } | |
| if (recording) | |
| { | |
| vcrConnect.time = host_time; | |
| vcrConnect.op = VCR_OP_CONNECT; | |
| vcrConnect.session = 0; | |
| Sys_FileWrite(vcrFile, &vcrConnect, sizeof(vcrConnect)); | |
| } | |
| return 0; | |
| } | |
| void NET_Close(qsocket_t *sock) | |
| { | |
| if (!sock) | |
| return; | |
| if (sock->disconnected) | |
| return; | |
| SetNetTime(); | |
| net_drivers[sock->driver].Close(sock); | |
| NET_FreeQSocket(sock); | |
| } | |
| int32_t NET_GetMessage(qsocket_t *sock) | |
| { | |
| int32_t ret; | |
| if (!sock) | |
| return -1; | |
| if (sock->disconnected) | |
| { | |
| Con_Printf("NET_GetMessage: disconnected socket\n"); | |
| return -1; | |
| } | |
| SetNetTime(); | |
| ret = net_drivers[sock->driver].QGetMessage(sock); | |
| if ((ret == 0) && sock->driver) | |
| { | |
| if ((net_time - sock->lastMessageTime) > net_messagetimeout.value) | |
| { | |
| NET_Close(sock); | |
| return -1; | |
| } | |
| } | |
| if (ret > 0) | |
| { | |
| if (sock->driver) | |
| { | |
| sock->lastMessageTime = net_time; | |
| if (ret == 1) | |
| messagesReceived++; | |
| else | |
| if (ret == 2) | |
| unreliableMessagesReceived++; | |
| } | |
| if (recording) | |
| { | |
| vcrGetMessage.time = host_time; | |
| vcrGetMessage.op = VCR_OP_GETMESSAGE; | |
| vcrGetMessage.session = (int32_t) sock; | |
| vcrGetMessage.ret = ret; | |
| vcrGetMessage.len = net_message.cursize; | |
| Sys_FileWrite(vcrFile, &vcrGetMessage, 24); | |
| Sys_FileWrite(vcrFile, net_message.data, net_message.cursize); | |
| } | |
| } | |
| else | |
| { | |
| if (recording) | |
| { | |
| vcrGetMessage.time = host_time; | |
| vcrGetMessage.op = VCR_OP_GETMESSAGE; | |
| vcrGetMessage.session = (int32_t) sock; | |
| vcrGetMessage.ret = ret; | |
| Sys_FileWrite(vcrFile, &vcrGetMessage, 20); | |
| } | |
| } | |
| return ret; | |
| } | |
| int32_t NET_SendMessage(qsocket_t *sock, sizebuf_t *data) | |
| { | |
| int32_t r; | |
| if (!sock) | |
| return -1; | |
| if (sock->disconnected) | |
| { | |
| Con_Printf("NET_SendMessage: disconnected socket\n"); | |
| return -1; | |
| } | |
| SetNetTime(); | |
| r = net_drivers[sock->driver].QSendMessage(sock, data); | |
| if ((r == 1) && sock->driver) | |
| messagesSent++; | |
| if (recording) | |
| { | |
| vcrSendMessage.time = host_time; | |
| vcrSendMessage.op = VCR_OP_SENDMESSAGE; | |
| vcrSendMessage.session = (int32_t) sock; | |
| vcrSendMessage.r = r; | |
| Sys_FileWrite(vcrFile, &vcrSendMessage, 20); | |
| } | |
| return r; | |
| } | |
| int32_t NET_SendUnreliableMessage(qsocket_t *sock, sizebuf_t *data) | |
| { | |
| int32_t r; | |
| if (!sock) | |
| return -1; | |
| if (sock->disconnected) | |
| { | |
| Con_Printf("NET_SendMessage: disconnected socket\n"); | |
| return -1; | |
| } | |
| SetNetTime(); | |
| r = net_drivers[sock->driver].SendUnreliableMessage(sock, data); | |
| if ((r == 1) && sock->driver) | |
| unreliableMessagesSent++; | |
| if (recording) | |
| { | |
| vcrSendMessage.time = host_time; | |
| vcrSendMessage.op = VCR_OP_SENDMESSAGE; | |
| vcrSendMessage.session = (int32_t) sock; | |
| vcrSendMessage.r = r; | |
| Sys_FileWrite(vcrFile, &vcrSendMessage, 20); | |
| } | |
| return r; | |
| } | |
| bool NET_CanSendMessage(qsocket_t *sock) | |
| { | |
| int32_t r; | |
| if (!sock) | |
| return 0; | |
| if (sock->disconnected) | |
| return 0; | |
| SetNetTime(); | |
| r = net_drivers[sock->driver].CanSendMessage(sock); | |
| if (recording) | |
| { | |
| vcrSendMessage.time = host_time; | |
| vcrSendMessage.op = VCR_OP_CANSENDMESSAGE; | |
| vcrSendMessage.session = (int32_t) sock; | |
| vcrSendMessage.r = r; | |
| Sys_FileWrite(vcrFile, &vcrSendMessage, 20); | |
| } | |
| return r; | |
| } | |
| int32_t NET_SendToAll(sizebuf_t *data, int32_t blocktime) | |
| { | |
| double start; | |
| int32_t i; | |
| int32_t count = 0; | |
| bool state1[MAX_SCOREBOARD]; | |
| bool state2[MAX_SCOREBOARD]; | |
| for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++) | |
| { | |
| if (!host_client->netconnection) | |
| continue; | |
| if (host_client->active) | |
| { | |
| if (host_client->netconnection->driver == 0) | |
| { | |
| NET_SendMessage(host_client->netconnection, data); | |
| state1[i] = 1; | |
| state2[i] = 1; | |
| continue; | |
| } | |
| count++; | |
| state1[i] = 0; | |
| state2[i] = 0; | |
| } | |
| else | |
| { | |
| state1[i] = 1; | |
| state2[i] = 1; | |
| } | |
| } | |
| start = Sys_FloatTime(); | |
| while (count) | |
| { | |
| count = 0; | |
| for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++) | |
| { | |
| if (!state1[i]) | |
| { | |
| if (NET_CanSendMessage(host_client->netconnection)) | |
| { | |
| state1[i] = 1; | |
| NET_SendMessage(host_client->netconnection, data); | |
| } | |
| else | |
| { | |
| NET_GetMessage(host_client->netconnection); | |
| } | |
| count++; | |
| continue; | |
| } | |
| if (!state2[i]) | |
| { | |
| if (NET_CanSendMessage(host_client->netconnection)) | |
| { | |
| state2[i] = 1; | |
| } | |
| else | |
| { | |
| NET_GetMessage(host_client->netconnection); | |
| } | |
| count++; | |
| continue; | |
| } | |
| } | |
| if ((Sys_FloatTime() - start) > blocktime) | |
| break; | |
| } | |
| return count; | |
| } | |
| void NET_Init(void) | |
| { | |
| int32_t i; | |
| int32_t controlSocket; | |
| qsocket_t *s; | |
| if (COM_CheckParm("-playback")) | |
| { | |
| net_numdrivers = 1; | |
| net_drivers[0].Init = VCR_Init; | |
| } | |
| if (COM_CheckParm("-record")) | |
| recording = 1; | |
| i = COM_CheckParm("-port"); | |
| if (!i) | |
| i = COM_CheckParm("-udpport"); | |
| if (!i) | |
| i = COM_CheckParm("-ipxport"); | |
| if (i) | |
| { | |
| if (i < (com_argc - 1)) | |
| DEFAULTnet_hostport = (int32_t) strtol(com_argv[i + 1], 0, 0); | |
| else | |
| Sys_Error("NET_Init: you must specify a number after -port"); | |
| } | |
| net_hostport = DEFAULTnet_hostport; | |
| if (COM_CheckParm("-listen") || (cls.state == ca_dedicated)) | |
| listening = 1; | |
| net_numsockets = svs.maxclientslimit; | |
| if (cls.state != ca_dedicated) | |
| net_numsockets++; | |
| SetNetTime(); | |
| for (i = 0; i < net_numsockets; i++) | |
| { | |
| s = (qsocket_t *) Hunk_AllocName(sizeof(qsocket_t), "qsocket"); | |
| s->next = net_freeSockets; | |
| net_freeSockets = s; | |
| s->disconnected = 1; | |
| } | |
| SZ_Alloc(&net_message, NET_MAXMESSAGE); | |
| Cvar_RegisterVariable(&net_messagetimeout); | |
| Cvar_RegisterVariable(&hostname); | |
| Cvar_RegisterVariable(&config_com_port); | |
| Cvar_RegisterVariable(&config_com_irq); | |
| Cvar_RegisterVariable(&config_com_baud); | |
| Cvar_RegisterVariable(&config_com_modem); | |
| Cvar_RegisterVariable(&config_modem_dialtype); | |
| Cvar_RegisterVariable(&config_modem_clear); | |
| Cvar_RegisterVariable(&config_modem_init); | |
| Cvar_RegisterVariable(&config_modem_hangup); | |
| Cmd_AddCommand("slist", NET_Slist_f); | |
| Cmd_AddCommand("listen", NET_Listen_f); | |
| Cmd_AddCommand("maxplayers", MaxPlayers_f); | |
| Cmd_AddCommand("port", NET_Port_f); | |
| for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++) | |
| { | |
| controlSocket = net_drivers[net_driverlevel].Init(); | |
| if (controlSocket == (-1)) | |
| continue; | |
| net_drivers[net_driverlevel].initialized = 1; | |
| net_drivers[net_driverlevel].controlSock = controlSocket; | |
| if (listening) | |
| net_drivers[net_driverlevel].Listen(1); | |
| } | |
| if (*my_ipx_address) | |
| Con_DPrintf("IPX address %s\n", my_ipx_address); | |
| if (*my_tcpip_address) | |
| Con_DPrintf("TCP/IP address %s\n", my_tcpip_address); | |
| } | |
| void NET_Shutdown(void) | |
| { | |
| qsocket_t *sock; | |
| SetNetTime(); | |
| for (sock = net_activeSockets; sock; sock = sock->next) | |
| NET_Close(sock); | |
| for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++) | |
| { | |
| if (net_drivers[net_driverlevel].initialized == 1) | |
| { | |
| net_drivers[net_driverlevel].Shutdown(); | |
| net_drivers[net_driverlevel].initialized = 0; | |
| } | |
| } | |
| if (vcrFile != (-1)) | |
| { | |
| Con_Printf("Closing vcrfile.\n"); | |
| Sys_FileClose(vcrFile); | |
| } | |
| } | |
| void NET_Poll(void) | |
| { | |
| PollProcedure *pp; | |
| bool useModem; | |
| if (!configRestored) | |
| { | |
| if (serialAvailable) | |
| { | |
| if (config_com_modem.value == 1.0) | |
| useModem = 1; | |
| else | |
| useModem = 0; | |
| SetComPortConfig(0, (int32_t) config_com_port.value, (int32_t) config_com_irq.value, (int32_t) config_com_baud.value, useModem); | |
| SetModemConfig(0, config_modem_dialtype.string, config_modem_clear.string, config_modem_init.string, config_modem_hangup.string); | |
| } | |
| configRestored = 1; | |
| } | |
| SetNetTime(); | |
| for (pp = pollProcedureList; pp; pp = pp->next) | |
| { | |
| if (pp->nextTime > net_time) | |
| break; | |
| pollProcedureList = pp->next; | |
| pp->procedure(pp->arg); | |
| } | |
| } | |
| void SchedulePollProcedure(PollProcedure *proc, double timeOffset) | |
| { | |
| PollProcedure *pp; | |
| PollProcedure *prev; | |
| proc->nextTime = Sys_FloatTime() + timeOffset; | |
| for (pp = pollProcedureList, prev = 0; pp; pp = pp->next) | |
| { | |
| if (pp->nextTime >= proc->nextTime) | |
| break; | |
| prev = pp; | |
| } | |
| if (prev == 0) | |
| { | |
| proc->next = pollProcedureList; | |
| pollProcedureList = proc; | |
| return; | |
| } | |
| proc->next = pp; | |
| prev->next = proc; | |
| } | |
| int32_t VCR_Init(void) | |
| { | |
| net_drivers[0].Init = VCR_Init; | |
| net_drivers[0].SearchForHosts = VCR_SearchForHosts; | |
| net_drivers[0].Connect = VCR_Connect; | |
| net_drivers[0].CheckNewConnections = VCR_CheckNewConnections; | |
| net_drivers[0].QGetMessage = VCR_GetMessage; | |
| net_drivers[0].QSendMessage = VCR_SendMessage; | |
| net_drivers[0].CanSendMessage = VCR_CanSendMessage; | |
| net_drivers[0].Close = VCR_Close; | |
| net_drivers[0].Shutdown = VCR_Shutdown; | |
| Sys_FileRead(vcrFile, &next, sizeof(next)); | |
| return 0; | |
| } | |
| void VCR_ReadNext(void) | |
| { | |
| if (Sys_FileRead(vcrFile, &next, sizeof(next)) == 0) | |
| { | |
| next.op = 255; | |
| Sys_Error("=== END OF PLAYBACK===\n"); | |
| } | |
| if ((next.op < 1) || (next.op > VCR_MAX_MESSAGE)) | |
| Sys_Error("VCR_ReadNext: bad op"); | |
| } | |
| void VCR_Listen(bool state) | |
| { | |
| } | |
| void VCR_Shutdown(void) | |
| { | |
| } | |
| int32_t VCR_GetMessage(qsocket_t *sock) | |
| { | |
| int32_t ret; | |
| if (((host_time != next.time) || (next.op != VCR_OP_GETMESSAGE)) || (next.session != (*((int32_t *) (&sock->driverdata))))) | |
| Sys_Error("VCR missmatch"); | |
| Sys_FileRead(vcrFile, &ret, sizeof(int32_t)); | |
| if (ret != 1) | |
| { | |
| VCR_ReadNext(); | |
| return ret; | |
| } | |
| Sys_FileRead(vcrFile, &net_message.cursize, sizeof(int32_t)); | |
| Sys_FileRead(vcrFile, net_message.data, net_message.cursize); | |
| VCR_ReadNext(); | |
| return 1; | |
| } | |
| int32_t VCR_SendMessage(qsocket_t *sock, sizebuf_t *data) | |
| { | |
| int32_t ret; | |
| if (((host_time != next.time) || (next.op != VCR_OP_SENDMESSAGE)) || (next.session != (*((int32_t *) (&sock->driverdata))))) | |
| Sys_Error("VCR missmatch"); | |
| Sys_FileRead(vcrFile, &ret, sizeof(int32_t)); | |
| VCR_ReadNext(); | |
| return ret; | |
| } | |
| bool VCR_CanSendMessage(qsocket_t *sock) | |
| { | |
| bool ret; | |
| if (((host_time != next.time) || (next.op != VCR_OP_CANSENDMESSAGE)) || (next.session != (*((int32_t *) (&sock->driverdata))))) | |
| Sys_Error("VCR missmatch"); | |
| Sys_FileRead(vcrFile, &ret, sizeof(int32_t)); | |
| VCR_ReadNext(); | |
| return ret; | |
| } | |
| void VCR_Close(qsocket_t *sock) | |
| { | |
| } | |
| void VCR_SearchForHosts(bool xmit) | |
| { | |
| } | |
| qsocket_t *VCR_Connect(char *host) | |
| { | |
| return 0; | |
| } | |
| qsocket_t *VCR_CheckNewConnections(void) | |
| { | |
| qsocket_t *sock; | |
| if ((host_time != next.time) || (next.op != VCR_OP_CONNECT)) | |
| Sys_Error("VCR missmatch"); | |
| if (!next.session) | |
| { | |
| VCR_ReadNext(); | |
| return 0; | |
| } | |
| sock = NET_NewQSocket(); | |
| *((int32_t *) (&sock->driverdata)) = next.session; | |
| Sys_FileRead(vcrFile, sock->address, NET_NAMELEN); | |
| VCR_ReadNext(); | |
| return sock; | |
| } | |
| void R_Surf8Patch() | |
| { | |
| } | |
| void R_Surf16Patch() | |
| { | |
| } | |
| void R_SurfacePatch(void) | |
| { | |
| } | |
| char *PF_VarString(int32_t first) | |
| { | |
| int32_t i; | |
| static char out[256]; | |
| out[0] = 0; | |
| for (i = first; i < pr_argc; i++) | |
| { | |
| strcat(out, G_STRING(OFS_PARM0 + (i * 3))); | |
| } | |
| return out; | |
| } | |
| void PF_error(void) | |
| { | |
| char *s; | |
| edict_t *ed; | |
| s = PF_VarString(0); | |
| Con_Printf("======SERVER ERROR in %s:\n%s\n", pr_strings + pr_xfunction->s_name, s); | |
| ed = PROG_TO_EDICT(pr_global_struct->self); | |
| ED_Print(ed); | |
| Host_Error("Program error"); | |
| } | |
| void PF_objerror(void) | |
| { | |
| char *s; | |
| edict_t *ed; | |
| s = PF_VarString(0); | |
| Con_Printf("======OBJECT ERROR in %s:\n%s\n", pr_strings + pr_xfunction->s_name, s); | |
| ed = PROG_TO_EDICT(pr_global_struct->self); | |
| ED_Print(ed); | |
| ED_Free(ed); | |
| Host_Error("Program error"); | |
| } | |
| void PF_makevectors(void) | |
| { | |
| AngleVectors(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up); | |
| } | |
| void PF_setorigin(void) | |
| { | |
| edict_t *e; | |
| float *org; | |
| e = G_EDICT(OFS_PARM0); | |
| org = G_VECTOR(OFS_PARM1); | |
| VectorCopy(org, e->v.origin); | |
| SV_LinkEdict(e, 0); | |
| } | |
| void SetMinMaxSize(edict_t *e, float *min, float *max, bool rotate) | |
| { | |
| float *angles; | |
| vec3_t rmin; | |
| vec3_t rmax; | |
| float bounds[2][3]; | |
| float xvector[2]; | |
| float yvector[2]; | |
| float a; | |
| vec3_t base; | |
| vec3_t transformed; | |
| int32_t i; | |
| int32_t j; | |
| int32_t k; | |
| int32_t l; | |
| for (i = 0; i < 3; i++) | |
| if (min[i] > max[i]) | |
| PR_RunError("backwards mins/maxs"); | |
| rotate = 0; | |
| if (!rotate) | |
| { | |
| VectorCopy(min, rmin); | |
| VectorCopy(max, rmax); | |
| } | |
| else | |
| { | |
| angles = e->v.angles; | |
| a = (angles[1] / 180) * M_PI; | |
| xvector[0] = cos(a); | |
| xvector[1] = sin(a); | |
| yvector[0] = -sin(a); | |
| yvector[1] = cos(a); | |
| VectorCopy(min, bounds[0]); | |
| VectorCopy(max, bounds[1]); | |
| rmin[0] = (rmin[1] = (rmin[2] = 9999)); | |
| rmax[0] = (rmax[1] = (rmax[2] = -9999)); | |
| for (i = 0; i <= 1; i++) | |
| { | |
| base[0] = bounds[i][0]; | |
| for (j = 0; j <= 1; j++) | |
| { | |
| base[1] = bounds[j][1]; | |
| for (k = 0; k <= 1; k++) | |
| { | |
| base[2] = bounds[k][2]; | |
| transformed[0] = (xvector[0] * base[0]) + (yvector[0] * base[1]); | |
| transformed[1] = (xvector[1] * base[0]) + (yvector[1] * base[1]); | |
| transformed[2] = base[2]; | |
| for (l = 0; l < 3; l++) | |
| { | |
| if (transformed[l] < rmin[l]) | |
| rmin[l] = transformed[l]; | |
| if (transformed[l] > rmax[l]) | |
| rmax[l] = transformed[l]; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| VectorCopy(rmin, e->v.mins); | |
| VectorCopy(rmax, e->v.maxs); | |
| VectorSubtract(max, min, e->v.size); | |
| SV_LinkEdict(e, 0); | |
| } | |
| void PF_setsize(void) | |
| { | |
| edict_t *e; | |
| float *min; | |
| float *max; | |
| e = G_EDICT(OFS_PARM0); | |
| min = G_VECTOR(OFS_PARM1); | |
| max = G_VECTOR(OFS_PARM2); | |
| SetMinMaxSize(e, min, max, 0); | |
| } | |
| void PF_setmodel(void) | |
| { | |
| edict_t *e; | |
| char *m; | |
| char **check; | |
| model_t *mod; | |
| int32_t i; | |
| e = G_EDICT(OFS_PARM0); | |
| m = G_STRING(OFS_PARM1); | |
| for (i = 0, check = sv.model_precache; *check; i++, check++) | |
| if (!strcmp(*check, m)) | |
| break; | |
| if (!(*check)) | |
| PR_RunError("no precache: %s\n", m); | |
| e->v.model = m - pr_strings; | |
| e->v.modelindex = i; | |
| mod = sv.models[(int32_t) e->v.modelindex]; | |
| if (mod) | |
| SetMinMaxSize(e, mod->mins, mod->maxs, 1); | |
| else | |
| SetMinMaxSize(e, vec3_origin, vec3_origin, 1); | |
| } | |
| void PF_bprint(void) | |
| { | |
| char *s; | |
| s = PF_VarString(0); | |
| SV_BroadcastPrintf("%s", s); | |
| } | |
| void PF_sprint(void) | |
| { | |
| char *s; | |
| client_t *client; | |
| int32_t entnum; | |
| entnum = G_EDICTNUM(OFS_PARM0); | |
| s = PF_VarString(1); | |
| if ((entnum < 1) || (entnum > svs.maxclients)) | |
| { | |
| Con_Printf("tried to sprint to a non-client\n"); | |
| return; | |
| } | |
| client = &svs.clients[entnum - 1]; | |
| MSG_WriteChar(&client->message, svc_print); | |
| MSG_WriteString(&client->message, s); | |
| } | |
| void PF_centerprint(void) | |
| { | |
| char *s; | |
| client_t *client; | |
| int32_t entnum; | |
| entnum = G_EDICTNUM(OFS_PARM0); | |
| s = PF_VarString(1); | |
| if ((entnum < 1) || (entnum > svs.maxclients)) | |
| { | |
| Con_Printf("tried to sprint to a non-client\n"); | |
| return; | |
| } | |
| client = &svs.clients[entnum - 1]; | |
| MSG_WriteChar(&client->message, svc_centerprint); | |
| MSG_WriteString(&client->message, s); | |
| } | |
| void PF_normalize(void) | |
| { | |
| float *value1; | |
| vec3_t newvalue; | |
| float new; | |
| value1 = G_VECTOR(OFS_PARM0); | |
| new = ((value1[0] * value1[0]) + (value1[1] * value1[1])) + (value1[2] * value1[2]); | |
| new = sqrt(new); | |
| if (new == 0) | |
| newvalue[0] = (newvalue[1] = (newvalue[2] = 0)); | |
| else | |
| { | |
| new = 1 / new; | |
| newvalue[0] = value1[0] * new; | |
| newvalue[1] = value1[1] * new; | |
| newvalue[2] = value1[2] * new; | |
| } | |
| VectorCopy(newvalue, G_VECTOR(OFS_RETURN)); | |
| } | |
| void PF_vlen(void) | |
| { | |
| float *value1; | |
| float new; | |
| value1 = G_VECTOR(OFS_PARM0); | |
| new = ((value1[0] * value1[0]) + (value1[1] * value1[1])) + (value1[2] * value1[2]); | |
| new = sqrt(new); | |
| G_FLOAT(OFS_RETURN) = new; | |
| } | |
| void PF_vectoyaw(void) | |
| { | |
| float *value1; | |
| float yaw; | |
| value1 = G_VECTOR(OFS_PARM0); | |
| if ((value1[1] == 0) && (value1[0] == 0)) | |
| yaw = 0; | |
| else | |
| { | |
| yaw = (int32_t) ((atan2(value1[1], value1[0]) * 180) / M_PI); | |
| if (yaw < 0) | |
| yaw += 360; | |
| } | |
| G_FLOAT(OFS_RETURN) = yaw; | |
| } | |
| void PF_vectoangles(void) | |
| { | |
| float *value1; | |
| float forward; | |
| float yaw; | |
| float pitch; | |
| value1 = G_VECTOR(OFS_PARM0); | |
| if ((value1[1] == 0) && (value1[0] == 0)) | |
| { | |
| yaw = 0; | |
| if (value1[2] > 0) | |
| pitch = 90; | |
| else | |
| pitch = 270; | |
| } | |
| else | |
| { | |
| yaw = (int32_t) ((atan2(value1[1], value1[0]) * 180) / M_PI); | |
| if (yaw < 0) | |
| yaw += 360; | |
| forward = sqrt((value1[0] * value1[0]) + (value1[1] * value1[1])); | |
| pitch = (int32_t) ((atan2(value1[2], forward) * 180) / M_PI); | |
| if (pitch < 0) | |
| pitch += 360; | |
| } | |
| G_FLOAT(OFS_RETURN + 0) = pitch; | |
| G_FLOAT(OFS_RETURN + 1) = yaw; | |
| G_FLOAT(OFS_RETURN + 2) = 0; | |
| } | |
| void PF_random(void) | |
| { | |
| float num; | |
| num = (rand() & 0x7fff) / ((float) 0x7fff); | |
| G_FLOAT(OFS_RETURN) = num; | |
| } | |
| void PF_particle(void) | |
| { | |
| float *org; | |
| float *dir; | |
| float color; | |
| float count; | |
| org = G_VECTOR(OFS_PARM0); | |
| dir = G_VECTOR(OFS_PARM1); | |
| color = G_FLOAT(OFS_PARM2); | |
| count = G_FLOAT(OFS_PARM3); | |
| SV_StartParticle(org, dir, color, count); | |
| } | |
| void PF_ambientsound(void) | |
| { | |
| char **check; | |
| char *samp; | |
| float *pos; | |
| float vol; | |
| float attenuation; | |
| int32_t i; | |
| int32_t soundnum; | |
| pos = G_VECTOR(OFS_PARM0); | |
| samp = G_STRING(OFS_PARM1); | |
| vol = G_FLOAT(OFS_PARM2); | |
| attenuation = G_FLOAT(OFS_PARM3); | |
| for (soundnum = 0, check = sv.sound_precache; *check; check++, soundnum++) | |
| if (!strcmp(*check, samp)) | |
| break; | |
| if (!(*check)) | |
| { | |
| Con_Printf("no precache: %s\n", samp); | |
| return; | |
| } | |
| MSG_WriteByte(&sv.signon, svc_spawnstaticsound); | |
| for (i = 0; i < 3; i++) | |
| MSG_WriteCoord(&sv.signon, pos[i]); | |
| MSG_WriteByte(&sv.signon, soundnum); | |
| MSG_WriteByte(&sv.signon, vol * 255); | |
| MSG_WriteByte(&sv.signon, attenuation * 64); | |
| } | |
| void PF_sound(void) | |
| { | |
| char *sample; | |
| int32_t channel; | |
| edict_t *entity; | |
| int32_t volume; | |
| float attenuation; | |
| entity = G_EDICT(OFS_PARM0); | |
| channel = G_FLOAT(OFS_PARM1); | |
| sample = G_STRING(OFS_PARM2); | |
| volume = G_FLOAT(OFS_PARM3) * 255; | |
| attenuation = G_FLOAT(OFS_PARM4); | |
| if ((volume < 0) || (volume > 255)) | |
| Sys_Error("SV_StartSound: volume = %i", volume); | |
| if ((attenuation < 0) || (attenuation > 4)) | |
| Sys_Error("SV_StartSound: attenuation = %f", attenuation); | |
| if ((channel < 0) || (channel > 7)) | |
| Sys_Error("SV_StartSound: channel = %i", channel); | |
| SV_StartSound(entity, channel, sample, volume, attenuation); | |
| } | |
| void PF_break(void) | |
| { | |
| Con_Printf("break statement\n"); | |
| *((int32_t *) (-4)) = 0; | |
| } | |
| void PF_traceline(void) | |
| { | |
| float *v1; | |
| float *v2; | |
| trace_t trace; | |
| int32_t nomonsters; | |
| edict_t *ent; | |
| v1 = G_VECTOR(OFS_PARM0); | |
| v2 = G_VECTOR(OFS_PARM1); | |
| nomonsters = G_FLOAT(OFS_PARM2); | |
| ent = G_EDICT(OFS_PARM3); | |
| trace = SV_Move(v1, vec3_origin, vec3_origin, v2, nomonsters, ent); | |
| pr_global_struct->trace_allsolid = trace.allsolid; | |
| pr_global_struct->trace_startsolid = trace.startsolid; | |
| pr_global_struct->trace_fraction = trace.fraction; | |
| pr_global_struct->trace_inwater = trace.inwater; | |
| pr_global_struct->trace_inopen = trace.inopen; | |
| VectorCopy(trace.endpos, pr_global_struct->trace_endpos); | |
| VectorCopy(trace.plane.normal, pr_global_struct->trace_plane_normal); | |
| pr_global_struct->trace_plane_dist = trace.plane.dist; | |
| if (trace.ent) | |
| pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent); | |
| else | |
| pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts); | |
| } | |
| void PF_checkpos(void) | |
| { | |
| } | |
| int32_t PF_newcheckclient(int32_t check) | |
| { | |
| int32_t i; | |
| uint8_t *pvs; | |
| edict_t *ent; | |
| mleaf_t *leaf; | |
| vec3_t org; | |
| if (check < 1) | |
| check = 1; | |
| if (check > svs.maxclients) | |
| check = svs.maxclients; | |
| if (check == svs.maxclients) | |
| i = 1; | |
| else | |
| i = check + 1; | |
| for (;; i++) | |
| { | |
| if (i == (svs.maxclients + 1)) | |
| i = 1; | |
| ent = EDICT_NUM(i); | |
| if (i == check) | |
| break; | |
| if (ent->free) | |
| continue; | |
| if (ent->v.health <= 0) | |
| continue; | |
| if (((int32_t) ent->v.flags) & FL_NOTARGET) | |
| continue; | |
| break; | |
| } | |
| VectorAdd(ent->v.origin, ent->v.view_ofs, org); | |
| leaf = Mod_PointInLeaf(org, sv.worldmodel); | |
| pvs = Mod_LeafPVS(leaf, sv.worldmodel); | |
| memcpy(checkpvs, pvs, (sv.worldmodel->numleafs + 7) >> 3); | |
| return i; | |
| } | |
| void PF_checkclient(void) | |
| { | |
| edict_t *ent; | |
| edict_t *self; | |
| mleaf_t *leaf; | |
| int32_t l; | |
| vec3_t view; | |
| if ((sv.time - sv.lastchecktime) >= 0.1) | |
| { | |
| sv.lastcheck = PF_newcheckclient(sv.lastcheck); | |
| sv.lastchecktime = sv.time; | |
| } | |
| ent = EDICT_NUM(sv.lastcheck); | |
| if (ent->free || (ent->v.health <= 0)) | |
| { | |
| RETURN_EDICT(sv.edicts); | |
| return; | |
| } | |
| self = PROG_TO_EDICT(pr_global_struct->self); | |
| VectorAdd(self->v.origin, self->v.view_ofs, view); | |
| leaf = Mod_PointInLeaf(view, sv.worldmodel); | |
| l = (leaf - sv.worldmodel->leafs) - 1; | |
| if ((l < 0) || (!(checkpvs[l >> 3] & (1 << (l & 7))))) | |
| { | |
| c_notvis++; | |
| RETURN_EDICT(sv.edicts); | |
| return; | |
| } | |
| c_invis++; | |
| RETURN_EDICT(ent); | |
| } | |
| void PF_stuffcmd(void) | |
| { | |
| int32_t entnum; | |
| char *str; | |
| client_t *old; | |
| entnum = G_EDICTNUM(OFS_PARM0); | |
| if ((entnum < 1) || (entnum > svs.maxclients)) | |
| PR_RunError("Parm 0 not a client"); | |
| str = G_STRING(OFS_PARM1); | |
| old = host_client; | |
| host_client = &svs.clients[entnum - 1]; | |
| Host_ClientCommands("%s", str); | |
| host_client = old; | |
| } | |
| void PF_localcmd(void) | |
| { | |
| char *str; | |
| str = G_STRING(OFS_PARM0); | |
| Cbuf_AddText(str); | |
| } | |
| void PF_cvar(void) | |
| { | |
| char *str; | |
| str = G_STRING(OFS_PARM0); | |
| G_FLOAT(OFS_RETURN) = Cvar_VariableValue(str); | |
| } | |
| void PF_cvar_set(void) | |
| { | |
| char *var; | |
| char *val; | |
| var = G_STRING(OFS_PARM0); | |
| val = G_STRING(OFS_PARM1); | |
| Cvar_Set(var, val); | |
| } | |
| void PF_findradius(void) | |
| { | |
| edict_t *ent; | |
| edict_t *chain; | |
| float rad; | |
| float *org; | |
| vec3_t eorg; | |
| int32_t i; | |
| int32_t j; | |
| chain = (edict_t *) sv.edicts; | |
| org = G_VECTOR(OFS_PARM0); | |
| rad = G_FLOAT(OFS_PARM1); | |
| ent = NEXT_EDICT(sv.edicts); | |
| for (i = 1; i < sv.num_edicts; i++, ent = NEXT_EDICT(ent)) | |
| { | |
| if (ent->free) | |
| continue; | |
| if (ent->v.solid == SOLID_NOT) | |
| continue; | |
| for (j = 0; j < 3; j++) | |
| eorg[j] = org[j] - (ent->v.origin[j] + ((ent->v.mins[j] + ent->v.maxs[j]) * 0.5)); | |
| if (Length(eorg) > rad) | |
| continue; | |
| ent->v.chain = EDICT_TO_PROG(chain); | |
| chain = ent; | |
| } | |
| RETURN_EDICT(chain); | |
| } | |
| void PF_dprint(void) | |
| { | |
| Con_DPrintf("%s", PF_VarString(0)); | |
| } | |
| void PF_ftos(void) | |
| { | |
| float v; | |
| v = G_FLOAT(OFS_PARM0); | |
| if (v == ((int32_t) v)) | |
| sprintf(pr_string_temp, "%d", (int32_t) v); | |
| else | |
| sprintf(pr_string_temp, "%5.1f", v); | |
| G_INT(OFS_RETURN) = pr_string_temp - pr_strings; | |
| } | |
| void PF_fabs(void) | |
| { | |
| float v; | |
| v = G_FLOAT(OFS_PARM0); | |
| G_FLOAT(OFS_RETURN) = fabs(v); | |
| } | |
| void PF_vtos(void) | |
| { | |
| sprintf(pr_string_temp, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]); | |
| G_INT(OFS_RETURN) = pr_string_temp - pr_strings; | |
| } | |
| void PF_Spawn(void) | |
| { | |
| edict_t *ed; | |
| ed = ED_Alloc(); | |
| RETURN_EDICT(ed); | |
| } | |
| void PF_Remove(void) | |
| { | |
| edict_t *ed; | |
| ed = G_EDICT(OFS_PARM0); | |
| ED_Free(ed); | |
| } | |
| void PF_Find(void) | |
| { | |
| int32_t e; | |
| int32_t f; | |
| char *s; | |
| char *t; | |
| edict_t *ed; | |
| e = G_EDICTNUM(OFS_PARM0); | |
| f = G_INT(OFS_PARM1); | |
| s = G_STRING(OFS_PARM2); | |
| if (!s) | |
| PR_RunError("PF_Find: bad search string"); | |
| for (e++; e < sv.num_edicts; e++) | |
| { | |
| ed = EDICT_NUM(e); | |
| if (ed->free) | |
| continue; | |
| t = E_STRING(ed, f); | |
| if (!t) | |
| continue; | |
| if (!strcmp(t, s)) | |
| { | |
| RETURN_EDICT(ed); | |
| return; | |
| } | |
| } | |
| RETURN_EDICT(sv.edicts); | |
| } | |
| void PR_CheckEmptyString(char *s) | |
| { | |
| if (s[0] <= ' ') | |
| PR_RunError("Bad string"); | |
| } | |
| void PF_precache_file(void) | |
| { | |
| G_INT(OFS_RETURN) = G_INT(OFS_PARM0); | |
| } | |
| void PF_precache_sound(void) | |
| { | |
| char *s; | |
| int32_t i; | |
| if (sv.state != ss_loading) | |
| PR_RunError("PF_Precache_*: Precache can only be done in spawn functions"); | |
| s = G_STRING(OFS_PARM0); | |
| G_INT(OFS_RETURN) = G_INT(OFS_PARM0); | |
| PR_CheckEmptyString(s); | |
| for (i = 0; i < MAX_SOUNDS; i++) | |
| { | |
| if (!sv.sound_precache[i]) | |
| { | |
| sv.sound_precache[i] = s; | |
| return; | |
| } | |
| if (!strcmp(sv.sound_precache[i], s)) | |
| return; | |
| } | |
| PR_RunError("PF_precache_sound: overflow"); | |
| } | |
| void PF_precache_model(void) | |
| { | |
| char *s; | |
| int32_t i; | |
| if (sv.state != ss_loading) | |
| PR_RunError("PF_Precache_*: Precache can only be done in spawn functions"); | |
| s = G_STRING(OFS_PARM0); | |
| G_INT(OFS_RETURN) = G_INT(OFS_PARM0); | |
| PR_CheckEmptyString(s); | |
| for (i = 0; i < MAX_MODELS; i++) | |
| { | |
| if (!sv.model_precache[i]) | |
| { | |
| sv.model_precache[i] = s; | |
| sv.models[i] = Mod_ForName(s, 1); | |
| return; | |
| } | |
| if (!strcmp(sv.model_precache[i], s)) | |
| return; | |
| } | |
| PR_RunError("PF_precache_model: overflow"); | |
| } | |
| void PF_coredump(void) | |
| { | |
| ED_PrintEdicts(); | |
| } | |
| void PF_traceon(void) | |
| { | |
| pr_trace = 1; | |
| } | |
| void PF_traceoff(void) | |
| { | |
| pr_trace = 0; | |
| } | |
| void PF_eprint(void) | |
| { | |
| ED_PrintNum(G_EDICTNUM(OFS_PARM0)); | |
| } | |
| void PF_walkmove(void) | |
| { | |
| edict_t *ent; | |
| float yaw; | |
| float dist; | |
| vec3_t move; | |
| dfunction_t *oldf; | |
| int32_t oldself; | |
| ent = PROG_TO_EDICT(pr_global_struct->self); | |
| yaw = G_FLOAT(OFS_PARM0); | |
| dist = G_FLOAT(OFS_PARM1); | |
| if (!(((int32_t) ent->v.flags) & ((FL_ONGROUND | FL_FLY) | FL_SWIM))) | |
| { | |
| G_FLOAT(OFS_RETURN) = 0; | |
| return; | |
| } | |
| yaw = ((yaw * M_PI) * 2) / 360; | |
| move[0] = cos(yaw) * dist; | |
| move[1] = sin(yaw) * dist; | |
| move[2] = 0; | |
| oldf = pr_xfunction; | |
| oldself = pr_global_struct->self; | |
| G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, 1); | |
| pr_xfunction = oldf; | |
| pr_global_struct->self = oldself; | |
| } | |
| void PF_droptofloor(void) | |
| { | |
| edict_t *ent; | |
| vec3_t end; | |
| trace_t trace; | |
| ent = PROG_TO_EDICT(pr_global_struct->self); | |
| VectorCopy(ent->v.origin, end); | |
| end[2] -= 256; | |
| trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, 0, ent); | |
| if ((trace.fraction == 1) || trace.allsolid) | |
| G_FLOAT(OFS_RETURN) = 0; | |
| else | |
| { | |
| VectorCopy(trace.endpos, ent->v.origin); | |
| SV_LinkEdict(ent, 0); | |
| ent->v.flags = ((int32_t) ent->v.flags) | FL_ONGROUND; | |
| ent->v.groundentity = EDICT_TO_PROG(trace.ent); | |
| G_FLOAT(OFS_RETURN) = 1; | |
| } | |
| } | |
| void PF_lightstyle(void) | |
| { | |
| int32_t style; | |
| char *val; | |
| client_t *client; | |
| int32_t j; | |
| style = G_FLOAT(OFS_PARM0); | |
| val = G_STRING(OFS_PARM1); | |
| sv.lightstyles[style] = val; | |
| if (sv.state != ss_active) | |
| return; | |
| for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++) | |
| if (client->active || client->spawned) | |
| { | |
| MSG_WriteChar(&client->message, svc_lightstyle); | |
| MSG_WriteChar(&client->message, style); | |
| MSG_WriteString(&client->message, val); | |
| } | |
| } | |
| void PF_rint(void) | |
| { | |
| float f; | |
| f = G_FLOAT(OFS_PARM0); | |
| if (f > 0) | |
| G_FLOAT(OFS_RETURN) = (int32_t) (f + 0.5); | |
| else | |
| G_FLOAT(OFS_RETURN) = (int32_t) (f - 0.5); | |
| } | |
| void PF_floor(void) | |
| { | |
| G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0)); | |
| } | |
| void PF_ceil(void) | |
| { | |
| G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0)); | |
| } | |
| void PF_checkbottom(void) | |
| { | |
| edict_t *ent; | |
| ent = G_EDICT(OFS_PARM0); | |
| G_FLOAT(OFS_RETURN) = SV_CheckBottom(ent); | |
| } | |
| void PF_pointcontents(void) | |
| { | |
| float *v; | |
| v = G_VECTOR(OFS_PARM0); | |
| G_FLOAT(OFS_RETURN) = SV_PointContents(v); | |
| } | |
| void PF_nextent(void) | |
| { | |
| int32_t i; | |
| edict_t *ent; | |
| i = G_EDICTNUM(OFS_PARM0); | |
| while (1) | |
| { | |
| i++; | |
| if (i == sv.num_edicts) | |
| { | |
| RETURN_EDICT(sv.edicts); | |
| return; | |
| } | |
| ent = EDICT_NUM(i); | |
| if (!ent->free) | |
| { | |
| RETURN_EDICT(ent); | |
| return; | |
| } | |
| } | |
| } | |
| void PF_aim(void) | |
| { | |
| edict_t *ent; | |
| edict_t *check; | |
| edict_t *bestent; | |
| vec3_t start; | |
| vec3_t dir; | |
| vec3_t end; | |
| vec3_t bestdir; | |
| int32_t i; | |
| int32_t j; | |
| trace_t tr; | |
| float dist; | |
| float bestdist; | |
| float speed; | |
| ent = G_EDICT(OFS_PARM0); | |
| speed = G_FLOAT(OFS_PARM1); | |
| VectorCopy(ent->v.origin, start); | |
| start[2] += 20; | |
| VectorCopy(pr_global_struct->v_forward, dir); | |
| VectorMA(start, 2048, dir, end); | |
| tr = SV_Move(start, vec3_origin, vec3_origin, end, 0, ent); | |
| if ((tr.ent && (tr.ent->v.takedamage == DAMAGE_AIM)) && (((!teamplay.value) || (ent->v.team <= 0)) || (ent->v.team != tr.ent->v.team))) | |
| { | |
| VectorCopy(pr_global_struct->v_forward, G_VECTOR(OFS_RETURN)); | |
| return; | |
| } | |
| VectorCopy(dir, bestdir); | |
| bestdist = sv_aim.value; | |
| bestent = 0; | |
| check = NEXT_EDICT(sv.edicts); | |
| for (i = 1; i < sv.num_edicts; i++, check = NEXT_EDICT(check)) | |
| { | |
| if (check->v.takedamage != DAMAGE_AIM) | |
| continue; | |
| if (check == ent) | |
| continue; | |
| if ((teamplay.value && (ent->v.team > 0)) && (ent->v.team == check->v.team)) | |
| continue; | |
| for (j = 0; j < 3; j++) | |
| end[j] = check->v.origin[j] + (0.5 * (check->v.mins[j] + check->v.maxs[j])); | |
| VectorSubtract(end, start, dir); | |
| VectorNormalize(dir); | |
| dist = DotProduct(dir, pr_global_struct->v_forward); | |
| if (dist < bestdist) | |
| continue; | |
| tr = SV_Move(start, vec3_origin, vec3_origin, end, 0, ent); | |
| if (tr.ent == check) | |
| { | |
| bestdist = dist; | |
| bestent = check; | |
| } | |
| } | |
| if (bestent) | |
| { | |
| VectorSubtract(bestent->v.origin, ent->v.origin, dir); | |
| dist = DotProduct(dir, pr_global_struct->v_forward); | |
| VectorScale(pr_global_struct->v_forward, dist, end); | |
| end[2] = dir[2]; | |
| VectorNormalize(end); | |
| VectorCopy(end, G_VECTOR(OFS_RETURN)); | |
| } | |
| else | |
| { | |
| VectorCopy(bestdir, G_VECTOR(OFS_RETURN)); | |
| } | |
| } | |
| void PF_changeyaw(void) | |
| { | |
| edict_t *ent; | |
| float ideal; | |
| float current; | |
| float move; | |
| float speed; | |
| ent = PROG_TO_EDICT(pr_global_struct->self); | |
| current = anglemod(ent->v.angles[1]); | |
| ideal = ent->v.ideal_yaw; | |
| speed = ent->v.yaw_speed; | |
| if (current == ideal) | |
| return; | |
| move = ideal - current; | |
| if (ideal > current) | |
| { | |
| if (move >= 180) | |
| move = move - 360; | |
| } | |
| else | |
| { | |
| if (move <= (-180)) | |
| move = move + 360; | |
| } | |
| if (move > 0) | |
| { | |
| if (move > speed) | |
| move = speed; | |
| } | |
| else | |
| { | |
| if (move < (-speed)) | |
| move = -speed; | |
| } | |
| ent->v.angles[1] = anglemod(current + move); | |
| } | |
| sizebuf_t *WriteDest(void) | |
| { | |
| int32_t entnum; | |
| int32_t dest; | |
| edict_t *ent; | |
| dest = G_FLOAT(OFS_PARM0); | |
| switch (dest) | |
| { | |
| case MSG_BROADCAST: | |
| return &sv.datagram; | |
| case MSG_ONE: | |
| ent = PROG_TO_EDICT(pr_global_struct->msg_entity); | |
| entnum = NUM_FOR_EDICT(ent); | |
| if ((entnum < 1) || (entnum > svs.maxclients)) | |
| PR_RunError("WriteDest: not a client"); | |
| return &svs.clients[entnum - 1].message; | |
| case MSG_ALL: | |
| return &sv.reliable_datagram; | |
| case MSG_INIT: | |
| return &sv.signon; | |
| default: | |
| PR_RunError("WriteDest: bad destination"); | |
| break; | |
| } | |
| return 0; | |
| } | |
| void PF_WriteByte(void) | |
| { | |
| MSG_WriteByte(WriteDest(), G_FLOAT(OFS_PARM1)); | |
| } | |
| void PF_WriteChar(void) | |
| { | |
| MSG_WriteChar(WriteDest(), G_FLOAT(OFS_PARM1)); | |
| } | |
| void PF_WriteShort(void) | |
| { | |
| MSG_WriteShort(WriteDest(), G_FLOAT(OFS_PARM1)); | |
| } | |
| void PF_WriteLong(void) | |
| { | |
| MSG_WriteLong(WriteDest(), G_FLOAT(OFS_PARM1)); | |
| } | |
| void PF_WriteAngle(void) | |
| { | |
| MSG_WriteAngle(WriteDest(), G_FLOAT(OFS_PARM1)); | |
| } | |
| void PF_WriteCoord(void) | |
| { | |
| MSG_WriteCoord(WriteDest(), G_FLOAT(OFS_PARM1)); | |
| } | |
| void PF_WriteString(void) | |
| { | |
| MSG_WriteString(WriteDest(), G_STRING(OFS_PARM1)); | |
| } | |
| void PF_WriteEntity(void) | |
| { | |
| MSG_WriteShort(WriteDest(), G_EDICTNUM(OFS_PARM1)); | |
| } | |
| void PF_makestatic(void) | |
| { | |
| edict_t *ent; | |
| int32_t i; | |
| ent = G_EDICT(OFS_PARM0); | |
| MSG_WriteByte(&sv.signon, svc_spawnstatic); | |
| MSG_WriteByte(&sv.signon, SV_ModelIndex(pr_strings + ent->v.model)); | |
| MSG_WriteByte(&sv.signon, ent->v.frame); | |
| MSG_WriteByte(&sv.signon, ent->v.colormap); | |
| MSG_WriteByte(&sv.signon, ent->v.skin); | |
| for (i = 0; i < 3; i++) | |
| { | |
| MSG_WriteCoord(&sv.signon, ent->v.origin[i]); | |
| MSG_WriteAngle(&sv.signon, ent->v.angles[i]); | |
| } | |
| ED_Free(ent); | |
| } | |
| void PF_setspawnparms(void) | |
| { | |
| edict_t *ent; | |
| int32_t i; | |
| client_t *client; | |
| ent = G_EDICT(OFS_PARM0); | |
| i = NUM_FOR_EDICT(ent); | |
| if ((i < 1) || (i > svs.maxclients)) | |
| PR_RunError("Entity is not a client"); | |
| client = svs.clients + (i - 1); | |
| for (i = 0; i < NUM_SPAWN_PARMS; i++) | |
| (&pr_global_struct->parm1)[i] = client->spawn_parms[i]; | |
| } | |
| void PF_changelevel(void) | |
| { | |
| char *s; | |
| if (svs.changelevel_issued) | |
| return; | |
| svs.changelevel_issued = 1; | |
| s = G_STRING(OFS_PARM0); | |
| Cbuf_AddText(va("changelevel %s\n", s)); | |
| } | |
| void PF_Fixme(void) | |
| { | |
| PR_RunError("unimplemented bulitin"); | |
| } | |
| void ED_ClearEdict(edict_t *e) | |
| { | |
| memset(&e->v, 0, progs->entityfields * 4); | |
| e->free = 0; | |
| } | |
| edict_t *ED_Alloc(void) | |
| { | |
| int32_t i; | |
| edict_t *e; | |
| for (i = svs.maxclients + 1; i < sv.num_edicts; i++) | |
| { | |
| e = EDICT_NUM(i); | |
| if (e->free && ((e->freetime < 2) || ((sv.time - e->freetime) > 0.5))) | |
| { | |
| ED_ClearEdict(e); | |
| return e; | |
| } | |
| } | |
| if (i == MAX_EDICTS) | |
| Sys_Error("ED_Alloc: no free edicts"); | |
| sv.num_edicts++; | |
| e = EDICT_NUM(i); | |
| ED_ClearEdict(e); | |
| return e; | |
| } | |
| void ED_Free(edict_t *ed) | |
| { | |
| SV_UnlinkEdict(ed); | |
| ed->free = 1; | |
| ed->v.model = 0; | |
| ed->v.takedamage = 0; | |
| ed->v.modelindex = 0; | |
| ed->v.colormap = 0; | |
| ed->v.skin = 0; | |
| ed->v.frame = 0; | |
| VectorCopy(vec3_origin, ed->v.origin); | |
| VectorCopy(vec3_origin, ed->v.angles); | |
| ed->v.nextthink = -1; | |
| ed->v.solid = 0; | |
| ed->freetime = sv.time; | |
| } | |
| ddef_t *ED_GlobalAtOfs(int32_t ofs) | |
| { | |
| ddef_t *def; | |
| int32_t i; | |
| for (i = 0; i < progs->numglobaldefs; i++) | |
| { | |
| def = &pr_globaldefs[i]; | |
| if (def->ofs == ofs) | |
| return def; | |
| } | |
| return 0; | |
| } | |
| ddef_t *ED_FieldAtOfs(int32_t ofs) | |
| { | |
| ddef_t *def; | |
| int32_t i; | |
| for (i = 0; i < progs->numfielddefs; i++) | |
| { | |
| def = &pr_fielddefs[i]; | |
| if (def->ofs == ofs) | |
| return def; | |
| } | |
| return 0; | |
| } | |
| ddef_t *ED_FindField(char *name) | |
| { | |
| ddef_t *def; | |
| int32_t i; | |
| for (i = 0; i < progs->numfielddefs; i++) | |
| { | |
| def = &pr_fielddefs[i]; | |
| if (!strcmp(pr_strings + def->s_name, name)) | |
| return def; | |
| } | |
| return 0; | |
| } | |
| ddef_t *ED_FindGlobal(char *name) | |
| { | |
| ddef_t *def; | |
| int32_t i; | |
| for (i = 0; i < progs->numglobaldefs; i++) | |
| { | |
| def = &pr_globaldefs[i]; | |
| if (!strcmp(pr_strings + def->s_name, name)) | |
| return def; | |
| } | |
| return 0; | |
| } | |
| dfunction_t *ED_FindFunction(char *name) | |
| { | |
| dfunction_t *func; | |
| int32_t i; | |
| for (i = 0; i < progs->numfunctions; i++) | |
| { | |
| func = &pr_functions[i]; | |
| if (!strcmp(pr_strings + func->s_name, name)) | |
| return func; | |
| } | |
| return 0; | |
| } | |
| eval_t *GetEdictFieldValue(edict_t *ed, char *field) | |
| { | |
| ddef_t *def = 0; | |
| int32_t i; | |
| static int32_t rep = 0; | |
| for (i = 0; i < GEFV_CACHESIZE; i++) | |
| { | |
| if (!strcmp(field, gefvCache[i].field)) | |
| { | |
| def = gefvCache[i].pcache; | |
| goto Done; | |
| } | |
| } | |
| def = ED_FindField(field); | |
| if (strlen(field) < MAX_FIELD_LEN) | |
| { | |
| gefvCache[rep].pcache = def; | |
| strcpy(gefvCache[rep].field, field); | |
| rep ^= 1; | |
| } | |
| Done: | |
| if (!def) | |
| return 0; | |
| return (eval_t *) (((char *) (&ed->v)) + (def->ofs * 4)); | |
| } | |
| char *PR_ValueString(etype_t type, eval_t *val) | |
| { | |
| static char line[256]; | |
| ddef_t *def; | |
| dfunction_t *f; | |
| type &= ~DEF_SAVEGLOBAL; | |
| switch (type) | |
| { | |
| case ev_string: | |
| sprintf(line, "%s", pr_strings + val->string); | |
| break; | |
| case ev_entity: | |
| sprintf(line, "entity %i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict))); | |
| break; | |
| case ev_function: | |
| f = pr_functions + val->function; | |
| sprintf(line, "%s()", pr_strings + f->s_name); | |
| break; | |
| case ev_field: | |
| def = ED_FieldAtOfs(val->_int); | |
| sprintf(line, ".%s", pr_strings + def->s_name); | |
| break; | |
| case ev_void: | |
| sprintf(line, "void"); | |
| break; | |
| case ev_float: | |
| sprintf(line, "%5.1f", val->_float); | |
| break; | |
| case ev_vector: | |
| sprintf(line, "'%5.1f %5.1f %5.1f'", val->vector[0], val->vector[1], val->vector[2]); | |
| break; | |
| case ev_pointer: | |
| sprintf(line, "pointer"); | |
| break; | |
| default: | |
| sprintf(line, "bad type %i", type); | |
| break; | |
| } | |
| return line; | |
| } | |
| char *PR_UglyValueString(etype_t type, eval_t *val) | |
| { | |
| static char line[256]; | |
| ddef_t *def; | |
| dfunction_t *f; | |
| type &= ~DEF_SAVEGLOBAL; | |
| switch (type) | |
| { | |
| case ev_string: | |
| sprintf(line, "%s", pr_strings + val->string); | |
| break; | |
| case ev_entity: | |
| sprintf(line, "%i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict))); | |
| break; | |
| case ev_function: | |
| f = pr_functions + val->function; | |
| sprintf(line, "%s", pr_strings + f->s_name); | |
| break; | |
| case ev_field: | |
| def = ED_FieldAtOfs(val->_int); | |
| sprintf(line, "%s", pr_strings + def->s_name); | |
| break; | |
| case ev_void: | |
| sprintf(line, "void"); | |
| break; | |
| case ev_float: | |
| sprintf(line, "%f", val->_float); | |
| break; | |
| case ev_vector: | |
| sprintf(line, "%f %f %f", val->vector[0], val->vector[1], val->vector[2]); | |
| break; | |
| default: | |
| sprintf(line, "bad type %i", type); | |
| break; | |
| } | |
| return line; | |
| } | |
| char *PR_GlobalString(int32_t ofs) | |
| { | |
| char *s; | |
| int32_t i; | |
| ddef_t *def; | |
| void *val; | |
| static char line[128]; | |
| val = (void *) (&pr_globals[ofs]); | |
| def = ED_GlobalAtOfs(ofs); | |
| if (!def) | |
| sprintf(line, "%i(?]", ofs); | |
| else | |
| { | |
| s = PR_ValueString(def->type, val); | |
| sprintf(line, "%i(%s)%s", ofs, pr_strings + def->s_name, s); | |
| } | |
| i = strlen(line); | |
| for (; i < 20; i++) | |
| strcat(line, " "); | |
| strcat(line, " "); | |
| return line; | |
| } | |
| char *PR_GlobalStringNoContents(int32_t ofs) | |
| { | |
| int32_t i; | |
| ddef_t *def; | |
| static char line[128]; | |
| def = ED_GlobalAtOfs(ofs); | |
| if (!def) | |
| sprintf(line, "%i(?]", ofs); | |
| else | |
| sprintf(line, "%i(%s)", ofs, pr_strings + def->s_name); | |
| i = strlen(line); | |
| for (; i < 20; i++) | |
| strcat(line, " "); | |
| strcat(line, " "); | |
| return line; | |
| } | |
| void ED_Print(edict_t *ed) | |
| { | |
| int32_t l; | |
| ddef_t *d; | |
| int32_t *v; | |
| int32_t i; | |
| int32_t j; | |
| char *name; | |
| int32_t type; | |
| if (ed->free) | |
| { | |
| Con_Printf("FREE\n"); | |
| return; | |
| } | |
| Con_Printf("\nEDICT %i:\n", NUM_FOR_EDICT(ed)); | |
| for (i = 1; i < progs->numfielddefs; i++) | |
| { | |
| d = &pr_fielddefs[i]; | |
| name = pr_strings + d->s_name; | |
| if (name[strlen(name) - 2] == '_') | |
| continue; | |
| v = (int32_t *) (((char *) (&ed->v)) + (d->ofs * 4)); | |
| type = d->type & (~DEF_SAVEGLOBAL); | |
| for (j = 0; j < type_size[type]; j++) | |
| if (v[j]) | |
| break; | |
| if (j == type_size[type]) | |
| continue; | |
| Con_Printf("%s", name); | |
| l = strlen(name); | |
| while ((l++) < 15) | |
| Con_Printf(" "); | |
| Con_Printf("%s\n", PR_ValueString(d->type, (eval_t *) v)); | |
| } | |
| } | |
| void ED_Write(FILE *f, edict_t *ed) | |
| { | |
| ddef_t *d; | |
| int32_t *v; | |
| int32_t i; | |
| int32_t j; | |
| char *name; | |
| int32_t type; | |
| fprintf(f, "{\n"); | |
| if (ed->free) | |
| { | |
| fprintf(f, "}\n"); | |
| return; | |
| } | |
| for (i = 1; i < progs->numfielddefs; i++) | |
| { | |
| d = &pr_fielddefs[i]; | |
| name = pr_strings + d->s_name; | |
| if (name[strlen(name) - 2] == '_') | |
| continue; | |
| v = (int32_t *) (((char *) (&ed->v)) + (d->ofs * 4)); | |
| type = d->type & (~DEF_SAVEGLOBAL); | |
| for (j = 0; j < type_size[type]; j++) | |
| if (v[j]) | |
| break; | |
| if (j == type_size[type]) | |
| continue; | |
| fprintf(f, "\"%s\" ", name); | |
| fprintf(f, "\"%s\"\n", PR_UglyValueString(d->type, (eval_t *) v)); | |
| } | |
| fprintf(f, "}\n"); | |
| } | |
| void ED_PrintNum(int32_t ent) | |
| { | |
| ED_Print(EDICT_NUM(ent)); | |
| } | |
| void ED_PrintEdicts(void) | |
| { | |
| int32_t i; | |
| Con_Printf("%i entities\n", sv.num_edicts); | |
| for (i = 0; i < sv.num_edicts; i++) | |
| ED_PrintNum(i); | |
| } | |
| void ED_PrintEdict_f(void) | |
| { | |
| int32_t i; | |
| i = (int32_t) strtol(Cmd_Argv(1), 0, 0); | |
| if (i >= sv.num_edicts) | |
| { | |
| Con_Printf("Bad edict number\n"); | |
| return; | |
| } | |
| ED_PrintNum(i); | |
| } | |
| void ED_Count(void) | |
| { | |
| int32_t i; | |
| edict_t *ent; | |
| int32_t active; | |
| int32_t models; | |
| int32_t solid; | |
| int32_t step; | |
| active = (models = (solid = (step = 0))); | |
| for (i = 0; i < sv.num_edicts; i++) | |
| { | |
| ent = EDICT_NUM(i); | |
| if (ent->free) | |
| continue; | |
| active++; | |
| if (ent->v.solid) | |
| solid++; | |
| if (ent->v.model) | |
| models++; | |
| if (ent->v.movetype == MOVETYPE_STEP) | |
| step++; | |
| } | |
| Con_Printf("num_edicts:%3i\n", sv.num_edicts); | |
| Con_Printf("active :%3i\n", active); | |
| Con_Printf("view :%3i\n", models); | |
| Con_Printf("touch :%3i\n", solid); | |
| Con_Printf("step :%3i\n", step); | |
| } | |
| void ED_WriteGlobals(FILE *f) | |
| { | |
| ddef_t *def; | |
| int32_t i; | |
| char *name; | |
| int32_t type; | |
| fprintf(f, "{\n"); | |
| for (i = 0; i < progs->numglobaldefs; i++) | |
| { | |
| def = &pr_globaldefs[i]; | |
| type = def->type; | |
| if (!(def->type & DEF_SAVEGLOBAL)) | |
| continue; | |
| type &= ~DEF_SAVEGLOBAL; | |
| if (((type != ev_string) && (type != ev_float)) && (type != ev_entity)) | |
| continue; | |
| name = pr_strings + def->s_name; | |
| fprintf(f, "\"%s\" ", name); | |
| fprintf(f, "\"%s\"\n", PR_UglyValueString(type, (eval_t *) (&pr_globals[def->ofs]))); | |
| } | |
| fprintf(f, "}\n"); | |
| } | |
| void ED_ParseGlobals(char *data) | |
| { | |
| char keyname[64]; | |
| ddef_t *key; | |
| while (1) | |
| { | |
| data = COM_Parse(data); | |
| if (com_token[0] == '}') | |
| break; | |
| if (!data) | |
| Sys_Error("ED_ParseEntity: EOF without closing brace"); | |
| strcpy(keyname, com_token); | |
| data = COM_Parse(data); | |
| if (!data) | |
| Sys_Error("ED_ParseEntity: EOF without closing brace"); | |
| if (com_token[0] == '}') | |
| Sys_Error("ED_ParseEntity: closing brace without data"); | |
| key = ED_FindGlobal(keyname); | |
| if (!key) | |
| { | |
| Con_Printf("'%s' is not a global\n", keyname); | |
| continue; | |
| } | |
| if (!ED_ParseEpair((void *) pr_globals, key, com_token)) | |
| Host_Error("ED_ParseGlobals: parse error"); | |
| } | |
| } | |
| char *ED_NewString(char *string) | |
| { | |
| char *new; | |
| char *new_p; | |
| int32_t i; | |
| int32_t l; | |
| l = strlen(string) + 1; | |
| new = Hunk_Alloc(l); | |
| new_p = new; | |
| for (i = 0; i < l; i++) | |
| { | |
| if ((string[i] == '\\') && (i < (l - 1))) | |
| { | |
| i++; | |
| if (string[i] == 'n') | |
| *(new_p++) = '\n'; | |
| else | |
| *(new_p++) = '\\'; | |
| } | |
| else | |
| *(new_p++) = string[i]; | |
| } | |
| return new; | |
| } | |
| bool ED_ParseEpair(void *base, ddef_t *key, char *s) | |
| { | |
| int32_t i; | |
| char string[128]; | |
| ddef_t *def; | |
| char *v; | |
| char *w; | |
| void *d; | |
| dfunction_t *func; | |
| d = (void *) (((int32_t *) base) + key->ofs); | |
| switch (key->type & (~DEF_SAVEGLOBAL)) | |
| { | |
| case ev_string: | |
| *((string_t *) d) = ED_NewString(s) - pr_strings; | |
| break; | |
| case ev_float: | |
| *((float *) d) = atof(s); | |
| break; | |
| case ev_vector: | |
| strcpy(string, s); | |
| v = string; | |
| w = string; | |
| for (i = 0; i < 3; i++) | |
| { | |
| while ((*v) && ((*v) != ' ')) | |
| v++; | |
| *v = 0; | |
| ((float *) d)[i] = atof(w); | |
| w = (v = v + 1); | |
| } | |
| break; | |
| case ev_entity: | |
| *((int32_t *) d) = EDICT_TO_PROG(EDICT_NUM(atoi(s))); | |
| break; | |
| case ev_field: | |
| def = ED_FindField(s); | |
| if (!def) | |
| { | |
| Con_Printf("Can't find field %s\n", s); | |
| return 0; | |
| } | |
| *((int32_t *) d) = G_INT(def->ofs); | |
| break; | |
| case ev_function: | |
| func = ED_FindFunction(s); | |
| if (!func) | |
| { | |
| Con_Printf("Can't find function %s\n", s); | |
| return 0; | |
| } | |
| *((func_t *) d) = func - pr_functions; | |
| break; | |
| default: | |
| break; | |
| } | |
| return 1; | |
| } | |
| char *ED_ParseEdict(char *data, edict_t *ent) | |
| { | |
| ddef_t *key; | |
| bool anglehack; | |
| bool init; | |
| char keyname[256]; | |
| int32_t n; | |
| init = 0; | |
| if (ent != sv.edicts) | |
| memset(&ent->v, 0, progs->entityfields * 4); | |
| while (1) | |
| { | |
| data = COM_Parse(data); | |
| if (com_token[0] == '}') | |
| break; | |
| if (!data) | |
| Sys_Error("ED_ParseEntity: EOF without closing brace"); | |
| if (!strcmp(com_token, "angle")) | |
| { | |
| strcpy(com_token, "angles"); | |
| anglehack = 1; | |
| } | |
| else | |
| anglehack = 0; | |
| if (!strcmp(com_token, "light")) | |
| strcpy(com_token, "light_lev"); | |
| strcpy(keyname, com_token); | |
| n = strlen(keyname); | |
| while (n && (keyname[n - 1] == ' ')) | |
| { | |
| keyname[n - 1] = 0; | |
| n--; | |
| } | |
| data = COM_Parse(data); | |
| if (!data) | |
| Sys_Error("ED_ParseEntity: EOF without closing brace"); | |
| if (com_token[0] == '}') | |
| Sys_Error("ED_ParseEntity: closing brace without data"); | |
| init = 1; | |
| if (keyname[0] == '_') | |
| continue; | |
| key = ED_FindField(keyname); | |
| if (!key) | |
| { | |
| Con_Printf("'%s' is not a field\n", keyname); | |
| continue; | |
| } | |
| if (anglehack) | |
| { | |
| char temp[32]; | |
| strcpy(temp, com_token); | |
| sprintf(com_token, "0 %s 0", temp); | |
| } | |
| if (!ED_ParseEpair((void *) (&ent->v), key, com_token)) | |
| Host_Error("ED_ParseEdict: parse error"); | |
| } | |
| if (!init) | |
| ent->free = 1; | |
| return data; | |
| } | |
| void ED_LoadFromFile(char *data) | |
| { | |
| edict_t *ent; | |
| int32_t inhibit; | |
| dfunction_t *func; | |
| ent = 0; | |
| inhibit = 0; | |
| pr_global_struct->time = sv.time; | |
| while (1) | |
| { | |
| data = COM_Parse(data); | |
| if (!data) | |
| break; | |
| if (com_token[0] != '{') | |
| Sys_Error("ED_LoadFromFile: found %s when expecting {", com_token); | |
| if (!ent) | |
| ent = EDICT_NUM(0); | |
| else | |
| ent = ED_Alloc(); | |
| data = ED_ParseEdict(data, ent); | |
| if (deathmatch.value) | |
| { | |
| if (((int32_t) ent->v.spawnflags) & SPAWNFLAG_NOT_DEATHMATCH) | |
| { | |
| ED_Free(ent); | |
| inhibit++; | |
| continue; | |
| } | |
| } | |
| else | |
| if ((((current_skill == 0) && (((int32_t) ent->v.spawnflags) & SPAWNFLAG_NOT_EASY)) || ((current_skill == 1) && (((int32_t) ent->v.spawnflags) & SPAWNFLAG_NOT_MEDIUM))) || ((current_skill >= 2) && (((int32_t) ent->v.spawnflags) & SPAWNFLAG_NOT_HARD))) | |
| { | |
| ED_Free(ent); | |
| inhibit++; | |
| continue; | |
| } | |
| if (!ent->v.classname) | |
| { | |
| Con_Printf("No classname for:\n"); | |
| ED_Print(ent); | |
| ED_Free(ent); | |
| continue; | |
| } | |
| func = ED_FindFunction(pr_strings + ent->v.classname); | |
| if (!func) | |
| { | |
| Con_Printf("No spawn function for:\n"); | |
| ED_Print(ent); | |
| ED_Free(ent); | |
| continue; | |
| } | |
| pr_global_struct->self = EDICT_TO_PROG(ent); | |
| PR_ExecuteProgram(func - pr_functions); | |
| } | |
| Con_DPrintf("%i entities inhibited\n", inhibit); | |
| } | |
| void PR_LoadProgs(void) | |
| { | |
| int32_t i; | |
| for (i = 0; i < GEFV_CACHESIZE; i++) | |
| gefvCache[i].field[0] = 0; | |
| CRC_Init(&pr_crc); | |
| progs = (dprograms_t *) COM_LoadHunkFile("progs.dat"); | |
| if (!progs) | |
| Sys_Error("PR_LoadProgs: couldn't load progs.dat"); | |
| Con_DPrintf("Programs occupy %iK.\n", com_filesize / 1024); | |
| for (i = 0; i < com_filesize; i++) | |
| CRC_ProcessByte(&pr_crc, ((uint8_t *) progs)[i]); | |
| for (i = 0; i < ((sizeof(*progs)) / 4); i++) | |
| ((int32_t *) progs)[i] = ((int32_t *) progs)[i]; | |
| if (progs->version != PROG_VERSION) | |
| Sys_Error("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION); | |
| if (progs->crc != PROGHEADER_CRC) | |
| Sys_Error("progs.dat system vars have been modified, progdefs.h is out of date"); | |
| pr_functions = (dfunction_t *) (((uint8_t *) progs) + progs->ofs_functions); | |
| pr_strings = ((char *) progs) + progs->ofs_strings; | |
| pr_globaldefs = (ddef_t *) (((uint8_t *) progs) + progs->ofs_globaldefs); | |
| pr_fielddefs = (ddef_t *) (((uint8_t *) progs) + progs->ofs_fielddefs); | |
| pr_statements = (dstatement_t *) (((uint8_t *) progs) + progs->ofs_statements); | |
| pr_global_struct = (globalvars_t *) (((uint8_t *) progs) + progs->ofs_globals); | |
| pr_globals = (float *) pr_global_struct; | |
| pr_edict_size = ((progs->entityfields * 4) + (sizeof(edict_t))) - (sizeof(entvars_t)); | |
| for (i = 0; i < progs->numstatements; i++) | |
| { | |
| pr_statements[i].op = pr_statements[i].op; | |
| pr_statements[i].a = pr_statements[i].a; | |
| pr_statements[i].b = pr_statements[i].b; | |
| pr_statements[i].c = pr_statements[i].c; | |
| } | |
| for (i = 0; i < progs->numfunctions; i++) | |
| { | |
| pr_functions[i].first_statement = pr_functions[i].first_statement; | |
| pr_functions[i].parm_start = pr_functions[i].parm_start; | |
| pr_functions[i].s_name = pr_functions[i].s_name; | |
| pr_functions[i].s_file = pr_functions[i].s_file; | |
| pr_functions[i].numparms = pr_functions[i].numparms; | |
| pr_functions[i].locals = pr_functions[i].locals; | |
| } | |
| for (i = 0; i < progs->numglobaldefs; i++) | |
| { | |
| pr_globaldefs[i].type = pr_globaldefs[i].type; | |
| pr_globaldefs[i].ofs = pr_globaldefs[i].ofs; | |
| pr_globaldefs[i].s_name = pr_globaldefs[i].s_name; | |
| } | |
| for (i = 0; i < progs->numfielddefs; i++) | |
| { | |
| pr_fielddefs[i].type = pr_fielddefs[i].type; | |
| if (pr_fielddefs[i].type & DEF_SAVEGLOBAL) | |
| Sys_Error("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL"); | |
| pr_fielddefs[i].ofs = pr_fielddefs[i].ofs; | |
| pr_fielddefs[i].s_name = pr_fielddefs[i].s_name; | |
| } | |
| for (i = 0; i < progs->numglobals; i++) | |
| ((int32_t *) pr_globals)[i] = ((int32_t *) pr_globals)[i]; | |
| } | |
| void PR_Init(void) | |
| { | |
| Cmd_AddCommand("edict", ED_PrintEdict_f); | |
| Cmd_AddCommand("edicts", ED_PrintEdicts); | |
| Cmd_AddCommand("edictcount", ED_Count); | |
| Cmd_AddCommand("profile", PR_Profile_f); | |
| Cvar_RegisterVariable(&nomonsters); | |
| Cvar_RegisterVariable(&gamecfg); | |
| Cvar_RegisterVariable(&scratch1); | |
| Cvar_RegisterVariable(&scratch2); | |
| Cvar_RegisterVariable(&scratch3); | |
| Cvar_RegisterVariable(&scratch4); | |
| Cvar_RegisterVariable(&savedgamecfg); | |
| Cvar_RegisterVariable(&saved1); | |
| Cvar_RegisterVariable(&saved2); | |
| Cvar_RegisterVariable(&saved3); | |
| Cvar_RegisterVariable(&saved4); | |
| } | |
| edict_t *EDICT_NUM(int32_t n) | |
| { | |
| if ((n < 0) || (n >= sv.max_edicts)) | |
| Sys_Error("EDICT_NUM: bad number %i", n); | |
| return (edict_t *) (((uint8_t *) sv.edicts) + (n * pr_edict_size)); | |
| } | |
| int32_t NUM_FOR_EDICT(edict_t *e) | |
| { | |
| int32_t b; | |
| b = ((uint8_t *) e) - ((uint8_t *) sv.edicts); | |
| b = b / pr_edict_size; | |
| if ((b < 0) || (b >= sv.num_edicts)) | |
| Sys_Error("NUM_FOR_EDICT: bad pointer"); | |
| return b; | |
| } | |
| void PR_PrintStatement(dstatement_t *s) | |
| { | |
| int32_t i; | |
| if (((uint32_t) s->op) < ((sizeof(pr_opnames)) / (sizeof(pr_opnames[0])))) | |
| { | |
| Con_Printf("%s ", pr_opnames[s->op]); | |
| i = strlen(pr_opnames[s->op]); | |
| for (; i < 10; i++) | |
| Con_Printf(" "); | |
| } | |
| if ((s->op == OP_IF) || (s->op == OP_IFNOT)) | |
| Con_Printf("%sbranch %i", PR_GlobalString(s->a), s->b); | |
| else | |
| if (s->op == OP_GOTO) | |
| { | |
| Con_Printf("branch %i", s->a); | |
| } | |
| else | |
| if (((uint32_t) (s->op - OP_STORE_F)) < 6) | |
| { | |
| Con_Printf("%s", PR_GlobalString(s->a)); | |
| Con_Printf("%s", PR_GlobalStringNoContents(s->b)); | |
| } | |
| else | |
| { | |
| if (s->a) | |
| Con_Printf("%s", PR_GlobalString(s->a)); | |
| if (s->b) | |
| Con_Printf("%s", PR_GlobalString(s->b)); | |
| if (s->c) | |
| Con_Printf("%s", PR_GlobalStringNoContents(s->c)); | |
| } | |
| Con_Printf("\n"); | |
| } | |
| void PR_StackTrace(void) | |
| { | |
| dfunction_t *f; | |
| int32_t i; | |
| if (pr_depth == 0) | |
| { | |
| Con_Printf("<NO STACK>\n"); | |
| return; | |
| } | |
| pr_stack[pr_depth].f = pr_xfunction; | |
| for (i = pr_depth; i >= 0; i--) | |
| { | |
| f = pr_stack[i].f; | |
| if (!f) | |
| { | |
| Con_Printf("<NO FUNCTION>\n"); | |
| } | |
| else | |
| Con_Printf("%12s : %s\n", pr_strings + f->s_file, pr_strings + f->s_name); | |
| } | |
| } | |
| void PR_Profile_f(void) | |
| { | |
| dfunction_t *f; | |
| dfunction_t *best; | |
| int32_t max; | |
| int32_t num; | |
| int32_t i; | |
| num = 0; | |
| do | |
| { | |
| max = 0; | |
| best = 0; | |
| for (i = 0; i < progs->numfunctions; i++) | |
| { | |
| f = &pr_functions[i]; | |
| if (f->profile > max) | |
| { | |
| max = f->profile; | |
| best = f; | |
| } | |
| } | |
| if (best) | |
| { | |
| if (num < 10) | |
| Con_Printf("%7i %s\n", best->profile, pr_strings + best->s_name); | |
| num++; | |
| best->profile = 0; | |
| } | |
| } | |
| while (best); | |
| } | |
| void PR_RunError(char *error, ...) | |
| { | |
| va_list argptr; | |
| char string[1024]; | |
| va_start(argptr, error); | |
| vsprintf(string, error, argptr); | |
| va_end(argptr); | |
| PR_PrintStatement(pr_statements + pr_xstatement); | |
| PR_StackTrace(); | |
| Con_Printf("%s\n", string); | |
| pr_depth = 0; | |
| Host_Error("Program error"); | |
| } | |
| int32_t PR_EnterFunction(dfunction_t *f) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| int32_t c; | |
| int32_t o; | |
| pr_stack[pr_depth].s = pr_xstatement; | |
| pr_stack[pr_depth].f = pr_xfunction; | |
| pr_depth++; | |
| if (pr_depth >= MAX_STACK_DEPTH) | |
| PR_RunError("stack overflow"); | |
| c = f->locals; | |
| if ((localstack_used + c) > LOCALSTACK_SIZE) | |
| PR_RunError("PR_ExecuteProgram: locals stack overflow\n"); | |
| for (i = 0; i < c; i++) | |
| localstack[localstack_used + i] = ((int32_t *) pr_globals)[f->parm_start + i]; | |
| localstack_used += c; | |
| o = f->parm_start; | |
| for (i = 0; i < f->numparms; i++) | |
| { | |
| for (j = 0; j < f->parm_size[i]; j++) | |
| { | |
| ((int32_t *) pr_globals)[o] = ((int32_t *) pr_globals)[(OFS_PARM0 + (i * 3)) + j]; | |
| o++; | |
| } | |
| } | |
| pr_xfunction = f; | |
| return f->first_statement - 1; | |
| } | |
| int32_t PR_LeaveFunction(void) | |
| { | |
| int32_t i; | |
| int32_t c; | |
| if (pr_depth <= 0) | |
| Sys_Error("prog stack underflow"); | |
| c = pr_xfunction->locals; | |
| localstack_used -= c; | |
| if (localstack_used < 0) | |
| PR_RunError("PR_ExecuteProgram: locals stack underflow\n"); | |
| for (i = 0; i < c; i++) | |
| ((int32_t *) pr_globals)[pr_xfunction->parm_start + i] = localstack[localstack_used + i]; | |
| pr_depth--; | |
| pr_xfunction = pr_stack[pr_depth].f; | |
| return pr_stack[pr_depth].s; | |
| } | |
| void PR_ExecuteProgram(func_t fnum) | |
| { | |
| eval_t *a; | |
| eval_t *b; | |
| eval_t *c; | |
| int32_t s; | |
| dstatement_t *st; | |
| dfunction_t *f; | |
| dfunction_t *newf; | |
| int32_t runaway; | |
| int32_t i; | |
| edict_t *ed; | |
| int32_t exitdepth; | |
| eval_t *ptr; | |
| if ((!fnum) || (fnum >= progs->numfunctions)) | |
| { | |
| if (pr_global_struct->self) | |
| ED_Print(PROG_TO_EDICT(pr_global_struct->self)); | |
| Host_Error("PR_ExecuteProgram: NULL function"); | |
| } | |
| f = &pr_functions[fnum]; | |
| runaway = 100000; | |
| pr_trace = 0; | |
| exitdepth = pr_depth; | |
| s = PR_EnterFunction(f); | |
| while (1) | |
| { | |
| s++; | |
| st = &pr_statements[s]; | |
| a = (eval_t *) (&pr_globals[st->a]); | |
| b = (eval_t *) (&pr_globals[st->b]); | |
| c = (eval_t *) (&pr_globals[st->c]); | |
| if (!(--runaway)) | |
| PR_RunError("runaway loop error"); | |
| pr_xfunction->profile++; | |
| pr_xstatement = s; | |
| if (pr_trace) | |
| PR_PrintStatement(st); | |
| switch (st->op) | |
| { | |
| case OP_ADD_F: | |
| c->_float = a->_float + b->_float; | |
| break; | |
| case OP_ADD_V: | |
| c->vector[0] = a->vector[0] + b->vector[0]; | |
| c->vector[1] = a->vector[1] + b->vector[1]; | |
| c->vector[2] = a->vector[2] + b->vector[2]; | |
| break; | |
| case OP_SUB_F: | |
| c->_float = a->_float - b->_float; | |
| break; | |
| case OP_SUB_V: | |
| c->vector[0] = a->vector[0] - b->vector[0]; | |
| c->vector[1] = a->vector[1] - b->vector[1]; | |
| c->vector[2] = a->vector[2] - b->vector[2]; | |
| break; | |
| case OP_MUL_F: | |
| c->_float = a->_float * b->_float; | |
| break; | |
| case OP_MUL_V: | |
| c->_float = ((a->vector[0] * b->vector[0]) + (a->vector[1] * b->vector[1])) + (a->vector[2] * b->vector[2]); | |
| break; | |
| case OP_MUL_FV: | |
| c->vector[0] = a->_float * b->vector[0]; | |
| c->vector[1] = a->_float * b->vector[1]; | |
| c->vector[2] = a->_float * b->vector[2]; | |
| break; | |
| case OP_MUL_VF: | |
| c->vector[0] = b->_float * a->vector[0]; | |
| c->vector[1] = b->_float * a->vector[1]; | |
| c->vector[2] = b->_float * a->vector[2]; | |
| break; | |
| case OP_DIV_F: | |
| c->_float = a->_float / b->_float; | |
| break; | |
| case OP_BITAND: | |
| c->_float = ((int32_t) a->_float) & ((int32_t) b->_float); | |
| break; | |
| case OP_BITOR: | |
| c->_float = ((int32_t) a->_float) | ((int32_t) b->_float); | |
| break; | |
| case OP_GE: | |
| c->_float = a->_float >= b->_float; | |
| break; | |
| case OP_LE: | |
| c->_float = a->_float <= b->_float; | |
| break; | |
| case OP_GT: | |
| c->_float = a->_float > b->_float; | |
| break; | |
| case OP_LT: | |
| c->_float = a->_float < b->_float; | |
| break; | |
| case OP_AND: | |
| c->_float = a->_float && b->_float; | |
| break; | |
| case OP_OR: | |
| c->_float = a->_float || b->_float; | |
| break; | |
| case OP_NOT_F: | |
| c->_float = !a->_float; | |
| break; | |
| case OP_NOT_V: | |
| c->_float = ((!a->vector[0]) && (!a->vector[1])) && (!a->vector[2]); | |
| break; | |
| case OP_NOT_S: | |
| c->_float = (!a->string) || (!pr_strings[a->string]); | |
| break; | |
| case OP_NOT_FNC: | |
| c->_float = !a->function; | |
| break; | |
| case OP_NOT_ENT: | |
| c->_float = PROG_TO_EDICT(a->edict) == sv.edicts; | |
| break; | |
| case OP_EQ_F: | |
| c->_float = a->_float == b->_float; | |
| break; | |
| case OP_EQ_V: | |
| c->_float = ((a->vector[0] == b->vector[0]) && (a->vector[1] == b->vector[1])) && (a->vector[2] == b->vector[2]); | |
| break; | |
| case OP_EQ_S: | |
| c->_float = !strcmp(pr_strings + a->string, pr_strings + b->string); | |
| break; | |
| case OP_EQ_E: | |
| c->_float = a->_int == b->_int; | |
| break; | |
| case OP_EQ_FNC: | |
| c->_float = a->function == b->function; | |
| break; | |
| case OP_NE_F: | |
| c->_float = a->_float != b->_float; | |
| break; | |
| case OP_NE_V: | |
| c->_float = ((a->vector[0] != b->vector[0]) || (a->vector[1] != b->vector[1])) || (a->vector[2] != b->vector[2]); | |
| break; | |
| case OP_NE_S: | |
| c->_float = strcmp(pr_strings + a->string, pr_strings + b->string); | |
| break; | |
| case OP_NE_E: | |
| c->_float = a->_int != b->_int; | |
| break; | |
| case OP_NE_FNC: | |
| c->_float = a->function != b->function; | |
| break; | |
| case OP_STORE_F: | |
| case OP_STORE_ENT: | |
| case OP_STORE_FLD: | |
| case OP_STORE_S: | |
| case OP_STORE_FNC: | |
| b->_int = a->_int; | |
| break; | |
| case OP_STORE_V: | |
| b->vector[0] = a->vector[0]; | |
| b->vector[1] = a->vector[1]; | |
| b->vector[2] = a->vector[2]; | |
| break; | |
| case OP_STOREP_F: | |
| case OP_STOREP_ENT: | |
| case OP_STOREP_FLD: | |
| case OP_STOREP_S: | |
| case OP_STOREP_FNC: | |
| ptr = (eval_t *) (((uint8_t *) sv.edicts) + b->_int); | |
| ptr->_int = a->_int; | |
| break; | |
| case OP_STOREP_V: | |
| ptr = (eval_t *) (((uint8_t *) sv.edicts) + b->_int); | |
| ptr->vector[0] = a->vector[0]; | |
| ptr->vector[1] = a->vector[1]; | |
| ptr->vector[2] = a->vector[2]; | |
| break; | |
| case OP_ADDRESS: | |
| ed = PROG_TO_EDICT(a->edict); | |
| if ((ed == ((edict_t *) sv.edicts)) && (sv.state == ss_active)) | |
| PR_RunError("assignment to world entity"); | |
| c->_int = ((uint8_t *) (((int32_t *) (&ed->v)) + b->_int)) - ((uint8_t *) sv.edicts); | |
| break; | |
| case OP_LOAD_F: | |
| case OP_LOAD_FLD: | |
| case OP_LOAD_ENT: | |
| case OP_LOAD_S: | |
| case OP_LOAD_FNC: | |
| ed = PROG_TO_EDICT(a->edict); | |
| a = (eval_t *) (((int32_t *) (&ed->v)) + b->_int); | |
| c->_int = a->_int; | |
| break; | |
| case OP_LOAD_V: | |
| ed = PROG_TO_EDICT(a->edict); | |
| a = (eval_t *) (((int32_t *) (&ed->v)) + b->_int); | |
| c->vector[0] = a->vector[0]; | |
| c->vector[1] = a->vector[1]; | |
| c->vector[2] = a->vector[2]; | |
| break; | |
| case OP_IFNOT: | |
| if (!a->_int) | |
| s += st->b - 1; | |
| break; | |
| case OP_IF: | |
| if (a->_int) | |
| s += st->b - 1; | |
| break; | |
| case OP_GOTO: | |
| s += st->a - 1; | |
| break; | |
| case OP_CALL0: | |
| case OP_CALL1: | |
| case OP_CALL2: | |
| case OP_CALL3: | |
| case OP_CALL4: | |
| case OP_CALL5: | |
| case OP_CALL6: | |
| case OP_CALL7: | |
| case OP_CALL8: | |
| pr_argc = st->op - OP_CALL0; | |
| if (!a->function) | |
| PR_RunError("NULL function"); | |
| newf = &pr_functions[a->function]; | |
| if (newf->first_statement < 0) | |
| { | |
| i = -newf->first_statement; | |
| if (i >= pr_numbuiltins) | |
| PR_RunError("Bad builtin call number"); | |
| pr_builtins[i](); | |
| break; | |
| } | |
| s = PR_EnterFunction(newf); | |
| break; | |
| case OP_DONE: | |
| case OP_RETURN: | |
| pr_globals[OFS_RETURN] = pr_globals[st->a]; | |
| pr_globals[OFS_RETURN + 1] = pr_globals[st->a + 1]; | |
| pr_globals[OFS_RETURN + 2] = pr_globals[st->a + 2]; | |
| s = PR_LeaveFunction(); | |
| if (pr_depth == exitdepth) | |
| return; | |
| break; | |
| case OP_STATE: | |
| ed = PROG_TO_EDICT(pr_global_struct->self); | |
| ed->v.nextthink = pr_global_struct->time + 0.1; | |
| if (a->_float != ed->v.frame) | |
| { | |
| ed->v.frame = a->_float; | |
| } | |
| ed->v.think = b->function; | |
| break; | |
| default: | |
| PR_RunError("Bad opcode %i", st->op); | |
| } | |
| } | |
| } | |
| void R_Alias_clip_z(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) | |
| { | |
| float scale; | |
| auxvert_t *pav0; | |
| auxvert_t *pav1; | |
| auxvert_t avout; | |
| pav0 = &av[pfv0 - (&_fv[0][0])]; | |
| pav1 = &av[pfv1 - (&_fv[0][0])]; | |
| if (pfv0->v[1] >= pfv1->v[1]) | |
| { | |
| scale = (ALIAS_Z_CLIP_PLANE - pav0->fv[2]) / (pav1->fv[2] - pav0->fv[2]); | |
| avout.fv[0] = pav0->fv[0] + ((pav1->fv[0] - pav0->fv[0]) * scale); | |
| avout.fv[1] = pav0->fv[1] + ((pav1->fv[1] - pav0->fv[1]) * scale); | |
| avout.fv[2] = ALIAS_Z_CLIP_PLANE; | |
| out->v[2] = pfv0->v[2] + ((pfv1->v[2] - pfv0->v[2]) * scale); | |
| out->v[3] = pfv0->v[3] + ((pfv1->v[3] - pfv0->v[3]) * scale); | |
| out->v[4] = pfv0->v[4] + ((pfv1->v[4] - pfv0->v[4]) * scale); | |
| } | |
| else | |
| { | |
| scale = (ALIAS_Z_CLIP_PLANE - pav1->fv[2]) / (pav0->fv[2] - pav1->fv[2]); | |
| avout.fv[0] = pav1->fv[0] + ((pav0->fv[0] - pav1->fv[0]) * scale); | |
| avout.fv[1] = pav1->fv[1] + ((pav0->fv[1] - pav1->fv[1]) * scale); | |
| avout.fv[2] = ALIAS_Z_CLIP_PLANE; | |
| out->v[2] = pfv1->v[2] + ((pfv0->v[2] - pfv1->v[2]) * scale); | |
| out->v[3] = pfv1->v[3] + ((pfv0->v[3] - pfv1->v[3]) * scale); | |
| out->v[4] = pfv1->v[4] + ((pfv0->v[4] - pfv1->v[4]) * scale); | |
| } | |
| R_AliasProjectFinalVert(out, &avout); | |
| if (out->v[0] < r_refdef.aliasvrect.x) | |
| out->flags |= ALIAS_LEFT_CLIP; | |
| if (out->v[1] < r_refdef.aliasvrect.y) | |
| out->flags |= ALIAS_TOP_CLIP; | |
| if (out->v[0] > r_refdef.aliasvrectright) | |
| out->flags |= ALIAS_RIGHT_CLIP; | |
| if (out->v[1] > r_refdef.aliasvrectbottom) | |
| out->flags |= ALIAS_BOTTOM_CLIP; | |
| } | |
| void R_Alias_clip_left(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) | |
| { | |
| float scale; | |
| int32_t i; | |
| if (pfv0->v[1] >= pfv1->v[1]) | |
| { | |
| scale = ((float) (r_refdef.aliasvrect.x - pfv0->v[0])) / (pfv1->v[0] - pfv0->v[0]); | |
| for (i = 0; i < 6; i++) | |
| out->v[i] = (pfv0->v[i] + ((pfv1->v[i] - pfv0->v[i]) * scale)) + 0.5; | |
| } | |
| else | |
| { | |
| scale = ((float) (r_refdef.aliasvrect.x - pfv1->v[0])) / (pfv0->v[0] - pfv1->v[0]); | |
| for (i = 0; i < 6; i++) | |
| out->v[i] = (pfv1->v[i] + ((pfv0->v[i] - pfv1->v[i]) * scale)) + 0.5; | |
| } | |
| } | |
| void R_Alias_clip_right(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) | |
| { | |
| float scale; | |
| int32_t i; | |
| if (pfv0->v[1] >= pfv1->v[1]) | |
| { | |
| scale = ((float) (r_refdef.aliasvrectright - pfv0->v[0])) / (pfv1->v[0] - pfv0->v[0]); | |
| for (i = 0; i < 6; i++) | |
| out->v[i] = (pfv0->v[i] + ((pfv1->v[i] - pfv0->v[i]) * scale)) + 0.5; | |
| } | |
| else | |
| { | |
| scale = ((float) (r_refdef.aliasvrectright - pfv1->v[0])) / (pfv0->v[0] - pfv1->v[0]); | |
| for (i = 0; i < 6; i++) | |
| out->v[i] = (pfv1->v[i] + ((pfv0->v[i] - pfv1->v[i]) * scale)) + 0.5; | |
| } | |
| } | |
| void R_Alias_clip_top(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) | |
| { | |
| float scale; | |
| int32_t i; | |
| if (pfv0->v[1] >= pfv1->v[1]) | |
| { | |
| scale = ((float) (r_refdef.aliasvrect.y - pfv0->v[1])) / (pfv1->v[1] - pfv0->v[1]); | |
| for (i = 0; i < 6; i++) | |
| out->v[i] = (pfv0->v[i] + ((pfv1->v[i] - pfv0->v[i]) * scale)) + 0.5; | |
| } | |
| else | |
| { | |
| scale = ((float) (r_refdef.aliasvrect.y - pfv1->v[1])) / (pfv0->v[1] - pfv1->v[1]); | |
| for (i = 0; i < 6; i++) | |
| out->v[i] = (pfv1->v[i] + ((pfv0->v[i] - pfv1->v[i]) * scale)) + 0.5; | |
| } | |
| } | |
| void R_Alias_clip_bottom(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) | |
| { | |
| float scale; | |
| int32_t i; | |
| if (pfv0->v[1] >= pfv1->v[1]) | |
| { | |
| scale = ((float) (r_refdef.aliasvrectbottom - pfv0->v[1])) / (pfv1->v[1] - pfv0->v[1]); | |
| for (i = 0; i < 6; i++) | |
| out->v[i] = (pfv0->v[i] + ((pfv1->v[i] - pfv0->v[i]) * scale)) + 0.5; | |
| } | |
| else | |
| { | |
| scale = ((float) (r_refdef.aliasvrectbottom - pfv1->v[1])) / (pfv0->v[1] - pfv1->v[1]); | |
| for (i = 0; i < 6; i++) | |
| out->v[i] = (pfv1->v[i] + ((pfv0->v[i] - pfv1->v[i]) * scale)) + 0.5; | |
| } | |
| } | |
| int32_t R_AliasClip(finalvert_t *in, finalvert_t *out, int32_t flag, int32_t count, void (*clip)(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| int32_t k; | |
| int32_t flags; | |
| int32_t oldflags; | |
| j = count - 1; | |
| k = 0; | |
| for (i = 0; i < count; j = i, i++) | |
| { | |
| oldflags = in[j].flags & flag; | |
| flags = in[i].flags & flag; | |
| if (flags && oldflags) | |
| continue; | |
| if (oldflags ^ flags) | |
| { | |
| clip(&in[j], &in[i], &out[k]); | |
| out[k].flags = 0; | |
| if (out[k].v[0] < r_refdef.aliasvrect.x) | |
| out[k].flags |= ALIAS_LEFT_CLIP; | |
| if (out[k].v[1] < r_refdef.aliasvrect.y) | |
| out[k].flags |= ALIAS_TOP_CLIP; | |
| if (out[k].v[0] > r_refdef.aliasvrectright) | |
| out[k].flags |= ALIAS_RIGHT_CLIP; | |
| if (out[k].v[1] > r_refdef.aliasvrectbottom) | |
| out[k].flags |= ALIAS_BOTTOM_CLIP; | |
| k++; | |
| } | |
| if (!flags) | |
| { | |
| out[k] = in[i]; | |
| k++; | |
| } | |
| } | |
| return k; | |
| } | |
| void R_AliasClipTriangle(mtriangle_t *ptri) | |
| { | |
| int32_t i; | |
| int32_t k; | |
| int32_t pingpong; | |
| mtriangle_t mtri; | |
| uint32_t clipflags; | |
| if (ptri->facesfront) | |
| { | |
| _fv[0][0] = pfinalverts[ptri->vertindex[0]]; | |
| _fv[0][1] = pfinalverts[ptri->vertindex[1]]; | |
| _fv[0][2] = pfinalverts[ptri->vertindex[2]]; | |
| } | |
| else | |
| { | |
| for (i = 0; i < 3; i++) | |
| { | |
| _fv[0][i] = pfinalverts[ptri->vertindex[i]]; | |
| if ((!ptri->facesfront) && (_fv[0][i].flags & ALIAS_ONSEAM)) | |
| _fv[0][i].v[2] += r_affinetridesc.seamfixupX16; | |
| } | |
| } | |
| clipflags = (_fv[0][0].flags | _fv[0][1].flags) | _fv[0][2].flags; | |
| if (clipflags & ALIAS_Z_CLIP) | |
| { | |
| for (i = 0; i < 3; i++) | |
| av[i] = pauxverts[ptri->vertindex[i]]; | |
| k = R_AliasClip(_fv[0], _fv[1], ALIAS_Z_CLIP, 3, R_Alias_clip_z); | |
| if (k == 0) | |
| return; | |
| pingpong = 1; | |
| clipflags = (_fv[1][0].flags | _fv[1][1].flags) | _fv[1][2].flags; | |
| } | |
| else | |
| { | |
| pingpong = 0; | |
| k = 3; | |
| } | |
| if (clipflags & ALIAS_LEFT_CLIP) | |
| { | |
| k = R_AliasClip(_fv[pingpong], _fv[pingpong ^ 1], ALIAS_LEFT_CLIP, k, R_Alias_clip_left); | |
| if (k == 0) | |
| return; | |
| pingpong ^= 1; | |
| } | |
| if (clipflags & ALIAS_RIGHT_CLIP) | |
| { | |
| k = R_AliasClip(_fv[pingpong], _fv[pingpong ^ 1], ALIAS_RIGHT_CLIP, k, R_Alias_clip_right); | |
| if (k == 0) | |
| return; | |
| pingpong ^= 1; | |
| } | |
| if (clipflags & ALIAS_BOTTOM_CLIP) | |
| { | |
| k = R_AliasClip(_fv[pingpong], _fv[pingpong ^ 1], ALIAS_BOTTOM_CLIP, k, R_Alias_clip_bottom); | |
| if (k == 0) | |
| return; | |
| pingpong ^= 1; | |
| } | |
| if (clipflags & ALIAS_TOP_CLIP) | |
| { | |
| k = R_AliasClip(_fv[pingpong], _fv[pingpong ^ 1], ALIAS_TOP_CLIP, k, R_Alias_clip_top); | |
| if (k == 0) | |
| return; | |
| pingpong ^= 1; | |
| } | |
| for (i = 0; i < k; i++) | |
| { | |
| if (_fv[pingpong][i].v[0] < r_refdef.aliasvrect.x) | |
| _fv[pingpong][i].v[0] = r_refdef.aliasvrect.x; | |
| else | |
| if (_fv[pingpong][i].v[0] > r_refdef.aliasvrectright) | |
| _fv[pingpong][i].v[0] = r_refdef.aliasvrectright; | |
| if (_fv[pingpong][i].v[1] < r_refdef.aliasvrect.y) | |
| _fv[pingpong][i].v[1] = r_refdef.aliasvrect.y; | |
| else | |
| if (_fv[pingpong][i].v[1] > r_refdef.aliasvrectbottom) | |
| _fv[pingpong][i].v[1] = r_refdef.aliasvrectbottom; | |
| _fv[pingpong][i].flags = 0; | |
| } | |
| mtri.facesfront = ptri->facesfront; | |
| r_affinetridesc.ptriangles = &mtri; | |
| r_affinetridesc.pfinalverts = _fv[pingpong]; | |
| mtri.vertindex[0] = 0; | |
| for (i = 1; i < (k - 1); i++) | |
| { | |
| mtri.vertindex[1] = i; | |
| mtri.vertindex[2] = i + 1; | |
| D_PolysetDraw(); | |
| } | |
| } | |
| bool R_AliasCheckBBox(void) | |
| { | |
| int32_t i; | |
| int32_t flags; | |
| int32_t frame; | |
| int32_t numv; | |
| aliashdr_t *pahdr; | |
| float zi; | |
| float basepts[8][3]; | |
| float v0; | |
| float v1; | |
| float frac; | |
| finalvert_t *pv0; | |
| finalvert_t *pv1; | |
| finalvert_t viewpts[16]; | |
| auxvert_t *pa0; | |
| auxvert_t *pa1; | |
| auxvert_t viewaux[16]; | |
| maliasframedesc_t *pframedesc; | |
| bool zclipped; | |
| bool zfullyclipped; | |
| uint32_t anyclip; | |
| uint32_t allclip; | |
| int32_t minz; | |
| currententity->trivial_accept = 0; | |
| pmodel = currententity->model; | |
| pahdr = Mod_Extradata(pmodel); | |
| pmdl = (mdl_t *) (((uint8_t *) pahdr) + pahdr->model); | |
| R_AliasSetUpTransform(0); | |
| frame = currententity->frame; | |
| if ((frame >= pmdl->numframes) || (frame < 0)) | |
| { | |
| Con_DPrintf("No such frame %d %s\n", frame, pmodel->name); | |
| frame = 0; | |
| } | |
| pframedesc = &pahdr->frames[frame]; | |
| basepts[0][0] = (basepts[1][0] = (basepts[2][0] = (basepts[3][0] = (float) pframedesc->bboxmin.v[0]))); | |
| basepts[4][0] = (basepts[5][0] = (basepts[6][0] = (basepts[7][0] = (float) pframedesc->bboxmax.v[0]))); | |
| basepts[0][1] = (basepts[3][1] = (basepts[5][1] = (basepts[6][1] = (float) pframedesc->bboxmin.v[1]))); | |
| basepts[1][1] = (basepts[2][1] = (basepts[4][1] = (basepts[7][1] = (float) pframedesc->bboxmax.v[1]))); | |
| basepts[0][2] = (basepts[1][2] = (basepts[4][2] = (basepts[5][2] = (float) pframedesc->bboxmin.v[2]))); | |
| basepts[2][2] = (basepts[3][2] = (basepts[6][2] = (basepts[7][2] = (float) pframedesc->bboxmax.v[2]))); | |
| zclipped = 0; | |
| zfullyclipped = 1; | |
| minz = 9999; | |
| for (i = 0; i < 8; i++) | |
| { | |
| R_AliasTransformVector(&basepts[i][0], &viewaux[i].fv[0]); | |
| if (viewaux[i].fv[2] < ALIAS_Z_CLIP_PLANE) | |
| { | |
| viewpts[i].flags = ALIAS_Z_CLIP; | |
| zclipped = 1; | |
| } | |
| else | |
| { | |
| if (viewaux[i].fv[2] < minz) | |
| minz = viewaux[i].fv[2]; | |
| viewpts[i].flags = 0; | |
| zfullyclipped = 0; | |
| } | |
| } | |
| if (zfullyclipped) | |
| { | |
| return 0; | |
| } | |
| numv = 8; | |
| if (zclipped) | |
| { | |
| for (i = 0; i < 12; i++) | |
| { | |
| pv0 = &viewpts[aedges[i].index0]; | |
| pv1 = &viewpts[aedges[i].index1]; | |
| pa0 = &viewaux[aedges[i].index0]; | |
| pa1 = &viewaux[aedges[i].index1]; | |
| if (pv0->flags ^ pv1->flags) | |
| { | |
| frac = (ALIAS_Z_CLIP_PLANE - pa0->fv[2]) / (pa1->fv[2] - pa0->fv[2]); | |
| viewaux[numv].fv[0] = pa0->fv[0] + ((pa1->fv[0] - pa0->fv[0]) * frac); | |
| viewaux[numv].fv[1] = pa0->fv[1] + ((pa1->fv[1] - pa0->fv[1]) * frac); | |
| viewaux[numv].fv[2] = ALIAS_Z_CLIP_PLANE; | |
| viewpts[numv].flags = 0; | |
| numv++; | |
| } | |
| } | |
| } | |
| anyclip = 0; | |
| allclip = ALIAS_XY_CLIP_MASK; | |
| for (i = 0; i < numv; i++) | |
| { | |
| if (viewpts[i].flags & ALIAS_Z_CLIP) | |
| continue; | |
| zi = 1.0 / viewaux[i].fv[2]; | |
| v0 = ((viewaux[i].fv[0] * xscale) * zi) + xcenter; | |
| v1 = ((viewaux[i].fv[1] * yscale) * zi) + ycenter; | |
| flags = 0; | |
| if (v0 < r_refdef.fvrectx) | |
| flags |= ALIAS_LEFT_CLIP; | |
| if (v1 < r_refdef.fvrecty) | |
| flags |= ALIAS_TOP_CLIP; | |
| if (v0 > r_refdef.fvrectright) | |
| flags |= ALIAS_RIGHT_CLIP; | |
| if (v1 > r_refdef.fvrectbottom) | |
| flags |= ALIAS_BOTTOM_CLIP; | |
| anyclip |= flags; | |
| allclip &= flags; | |
| } | |
| if (allclip) | |
| return 0; | |
| currententity->trivial_accept = (!anyclip) & (!zclipped); | |
| if (currententity->trivial_accept) | |
| { | |
| if (minz > (r_aliastransition + (pmdl->size * r_resfudge))) | |
| { | |
| currententity->trivial_accept |= 2; | |
| } | |
| } | |
| return 1; | |
| } | |
| void R_AliasTransformVector(vec3_t in, vec3_t out) | |
| { | |
| out[0] = DotProduct(in, aliastransform[0]) + aliastransform[0][3]; | |
| out[1] = DotProduct(in, aliastransform[1]) + aliastransform[1][3]; | |
| out[2] = DotProduct(in, aliastransform[2]) + aliastransform[2][3]; | |
| } | |
| void R_AliasPreparePoints(void) | |
| { | |
| int32_t i; | |
| stvert_t *pstverts; | |
| finalvert_t *fv; | |
| auxvert_t *av; | |
| mtriangle_t *ptri; | |
| finalvert_t *pfv[3]; | |
| pstverts = (stvert_t *) (((uint8_t *) paliashdr) + paliashdr->stverts); | |
| r_anumverts = pmdl->numverts; | |
| fv = pfinalverts; | |
| av = pauxverts; | |
| for (i = 0; i < r_anumverts; i++, fv++, av++, r_apverts++, pstverts++) | |
| { | |
| R_AliasTransformFinalVert(fv, av, r_apverts, pstverts); | |
| if (av->fv[2] < ALIAS_Z_CLIP_PLANE) | |
| fv->flags |= ALIAS_Z_CLIP; | |
| else | |
| { | |
| R_AliasProjectFinalVert(fv, av); | |
| if (fv->v[0] < r_refdef.aliasvrect.x) | |
| fv->flags |= ALIAS_LEFT_CLIP; | |
| if (fv->v[1] < r_refdef.aliasvrect.y) | |
| fv->flags |= ALIAS_TOP_CLIP; | |
| if (fv->v[0] > r_refdef.aliasvrectright) | |
| fv->flags |= ALIAS_RIGHT_CLIP; | |
| if (fv->v[1] > r_refdef.aliasvrectbottom) | |
| fv->flags |= ALIAS_BOTTOM_CLIP; | |
| } | |
| } | |
| r_affinetridesc.numtriangles = 1; | |
| ptri = (mtriangle_t *) (((uint8_t *) paliashdr) + paliashdr->triangles); | |
| for (i = 0; i < pmdl->numtris; i++, ptri++) | |
| { | |
| pfv[0] = &pfinalverts[ptri->vertindex[0]]; | |
| pfv[1] = &pfinalverts[ptri->vertindex[1]]; | |
| pfv[2] = &pfinalverts[ptri->vertindex[2]]; | |
| if (((pfv[0]->flags & pfv[1]->flags) & pfv[2]->flags) & (ALIAS_XY_CLIP_MASK | ALIAS_Z_CLIP)) | |
| continue; | |
| if (!(((pfv[0]->flags | pfv[1]->flags) | pfv[2]->flags) & (ALIAS_XY_CLIP_MASK | ALIAS_Z_CLIP))) | |
| { | |
| r_affinetridesc.pfinalverts = pfinalverts; | |
| r_affinetridesc.ptriangles = ptri; | |
| D_PolysetDraw(); | |
| } | |
| else | |
| { | |
| R_AliasClipTriangle(ptri); | |
| } | |
| } | |
| } | |
| void R_AliasSetUpTransform(int32_t trivial_accept) | |
| { | |
| int32_t i; | |
| float rotationmatrix[3][4]; | |
| float t2matrix[3][4]; | |
| static float tmatrix[3][4]; | |
| static float viewmatrix[3][4]; | |
| vec3_t angles; | |
| angles[ROLL] = currententity->angles[ROLL]; | |
| angles[PITCH] = -currententity->angles[PITCH]; | |
| angles[YAW] = currententity->angles[YAW]; | |
| AngleVectors(angles, alias_forward, alias_right, alias_up); | |
| tmatrix[0][0] = pmdl->scale[0]; | |
| tmatrix[1][1] = pmdl->scale[1]; | |
| tmatrix[2][2] = pmdl->scale[2]; | |
| tmatrix[0][3] = pmdl->scale_origin[0]; | |
| tmatrix[1][3] = pmdl->scale_origin[1]; | |
| tmatrix[2][3] = pmdl->scale_origin[2]; | |
| for (i = 0; i < 3; i++) | |
| { | |
| t2matrix[i][0] = alias_forward[i]; | |
| t2matrix[i][1] = -alias_right[i]; | |
| t2matrix[i][2] = alias_up[i]; | |
| } | |
| t2matrix[0][3] = -modelorg[0]; | |
| t2matrix[1][3] = -modelorg[1]; | |
| t2matrix[2][3] = -modelorg[2]; | |
| R_ConcatTransforms(t2matrix, tmatrix, rotationmatrix); | |
| VectorCopy(vright, viewmatrix[0]); | |
| VectorCopy(vup, viewmatrix[1]); | |
| VectorInverse(viewmatrix[1]); | |
| VectorCopy(vpn, viewmatrix[2]); | |
| R_ConcatTransforms(viewmatrix, rotationmatrix, aliastransform); | |
| if (trivial_accept) | |
| { | |
| for (i = 0; i < 4; i++) | |
| { | |
| aliastransform[0][i] *= aliasxscale * (1.0 / (((float) 0x8000) * 0x10000)); | |
| aliastransform[1][i] *= aliasyscale * (1.0 / (((float) 0x8000) * 0x10000)); | |
| aliastransform[2][i] *= 1.0 / (((float) 0x8000) * 0x10000); | |
| } | |
| } | |
| } | |
| void R_AliasTransformFinalVert(finalvert_t *fv, auxvert_t *av, trivertx_t *pverts, stvert_t *pstverts) | |
| { | |
| int32_t temp; | |
| float lightcos; | |
| float *plightnormal; | |
| av->fv[0] = DotProduct(pverts->v, aliastransform[0]) + aliastransform[0][3]; | |
| av->fv[1] = DotProduct(pverts->v, aliastransform[1]) + aliastransform[1][3]; | |
| av->fv[2] = DotProduct(pverts->v, aliastransform[2]) + aliastransform[2][3]; | |
| fv->v[2] = pstverts->s; | |
| fv->v[3] = pstverts->t; | |
| fv->flags = pstverts->onseam; | |
| plightnormal = r_avertexnormals[pverts->lightnormalindex]; | |
| lightcos = DotProduct(plightnormal, r_plightvec); | |
| temp = r_ambientlight; | |
| if (lightcos < 0) | |
| { | |
| temp += (int32_t) (r_shadelight * lightcos); | |
| if (temp < 0) | |
| temp = 0; | |
| } | |
| fv->v[4] = temp; | |
| } | |
| void R_AliasTransformAndProjectFinalVerts(finalvert_t *fv, stvert_t *pstverts) | |
| { | |
| int32_t i; | |
| int32_t temp; | |
| float lightcos; | |
| float *plightnormal; | |
| float zi; | |
| trivertx_t *pverts; | |
| pverts = r_apverts; | |
| for (i = 0; i < r_anumverts; i++, fv++, pverts++, pstverts++) | |
| { | |
| zi = 1.0 / (DotProduct(pverts->v, aliastransform[2]) + aliastransform[2][3]); | |
| fv->v[5] = zi; | |
| fv->v[0] = ((DotProduct(pverts->v, aliastransform[0]) + aliastransform[0][3]) * zi) + aliasxcenter; | |
| fv->v[1] = ((DotProduct(pverts->v, aliastransform[1]) + aliastransform[1][3]) * zi) + aliasycenter; | |
| fv->v[2] = pstverts->s; | |
| fv->v[3] = pstverts->t; | |
| fv->flags = pstverts->onseam; | |
| plightnormal = r_avertexnormals[pverts->lightnormalindex]; | |
| lightcos = DotProduct(plightnormal, r_plightvec); | |
| temp = r_ambientlight; | |
| if (lightcos < 0) | |
| { | |
| temp += (int32_t) (r_shadelight * lightcos); | |
| if (temp < 0) | |
| temp = 0; | |
| } | |
| fv->v[4] = temp; | |
| } | |
| } | |
| void R_AliasProjectFinalVert(finalvert_t *fv, auxvert_t *av) | |
| { | |
| float zi; | |
| zi = 1.0 / av->fv[2]; | |
| fv->v[5] = zi * ziscale; | |
| fv->v[0] = ((av->fv[0] * aliasxscale) * zi) + aliasxcenter; | |
| fv->v[1] = ((av->fv[1] * aliasyscale) * zi) + aliasycenter; | |
| } | |
| void R_AliasPrepareUnclippedPoints(void) | |
| { | |
| stvert_t *pstverts; | |
| finalvert_t *fv; | |
| pstverts = (stvert_t *) (((uint8_t *) paliashdr) + paliashdr->stverts); | |
| r_anumverts = pmdl->numverts; | |
| fv = pfinalverts; | |
| R_AliasTransformAndProjectFinalVerts(fv, pstverts); | |
| if (r_affinetridesc.drawtype) | |
| D_PolysetDrawFinalVerts(fv, r_anumverts); | |
| r_affinetridesc.pfinalverts = pfinalverts; | |
| r_affinetridesc.ptriangles = (mtriangle_t *) (((uint8_t *) paliashdr) + paliashdr->triangles); | |
| r_affinetridesc.numtriangles = pmdl->numtris; | |
| D_PolysetDraw(); | |
| } | |
| void R_AliasSetupSkin(void) | |
| { | |
| int32_t skinnum; | |
| int32_t i; | |
| int32_t numskins; | |
| maliasskingroup_t *paliasskingroup; | |
| float *pskinintervals; | |
| float fullskininterval; | |
| float skintargettime; | |
| float skintime; | |
| skinnum = currententity->skinnum; | |
| if ((skinnum >= pmdl->numskins) || (skinnum < 0)) | |
| { | |
| Con_DPrintf("R_AliasSetupSkin: no such skin # %d\n", skinnum); | |
| skinnum = 0; | |
| } | |
| pskindesc = ((maliasskindesc_t *) (((uint8_t *) paliashdr) + paliashdr->skindesc)) + skinnum; | |
| a_skinwidth = pmdl->skinwidth; | |
| if (pskindesc->type == ALIAS_SKIN_GROUP) | |
| { | |
| paliasskingroup = (maliasskingroup_t *) (((uint8_t *) paliashdr) + pskindesc->skin); | |
| pskinintervals = (float *) (((uint8_t *) paliashdr) + paliasskingroup->intervals); | |
| numskins = paliasskingroup->numskins; | |
| fullskininterval = pskinintervals[numskins - 1]; | |
| skintime = cl.time + currententity->syncbase; | |
| skintargettime = skintime - (((int32_t) (skintime / fullskininterval)) * fullskininterval); | |
| for (i = 0; i < (numskins - 1); i++) | |
| { | |
| if (pskinintervals[i] > skintargettime) | |
| break; | |
| } | |
| pskindesc = &paliasskingroup->skindescs[i]; | |
| } | |
| r_affinetridesc.pskindesc = pskindesc; | |
| r_affinetridesc.pskin = (void *) (((uint8_t *) paliashdr) + pskindesc->skin); | |
| r_affinetridesc.skinwidth = a_skinwidth; | |
| r_affinetridesc.seamfixupX16 = (a_skinwidth >> 1) << 16; | |
| r_affinetridesc.skinheight = pmdl->skinheight; | |
| } | |
| void R_AliasSetupLighting(alight_t *plighting) | |
| { | |
| r_ambientlight = plighting->ambientlight; | |
| if (r_ambientlight < LIGHT_MIN) | |
| r_ambientlight = LIGHT_MIN; | |
| r_ambientlight = (255 - r_ambientlight) << VID_CBITS; | |
| if (r_ambientlight < LIGHT_MIN) | |
| r_ambientlight = LIGHT_MIN; | |
| r_shadelight = plighting->shadelight; | |
| if (r_shadelight < 0) | |
| r_shadelight = 0; | |
| r_shadelight *= VID_GRADES; | |
| r_plightvec[0] = DotProduct(plighting->plightvec, alias_forward); | |
| r_plightvec[1] = -DotProduct(plighting->plightvec, alias_right); | |
| r_plightvec[2] = DotProduct(plighting->plightvec, alias_up); | |
| } | |
| void R_AliasSetupFrame(void) | |
| { | |
| int32_t frame; | |
| int32_t i; | |
| int32_t numframes; | |
| maliasgroup_t *paliasgroup; | |
| float *pintervals; | |
| float fullinterval; | |
| float targettime; | |
| float time; | |
| frame = currententity->frame; | |
| if ((frame >= pmdl->numframes) || (frame < 0)) | |
| { | |
| Con_DPrintf("R_AliasSetupFrame: no such frame %d\n", frame); | |
| frame = 0; | |
| } | |
| if (paliashdr->frames[frame].type == ALIAS_SINGLE) | |
| { | |
| r_apverts = (trivertx_t *) (((uint8_t *) paliashdr) + paliashdr->frames[frame].frame); | |
| return; | |
| } | |
| paliasgroup = (maliasgroup_t *) (((uint8_t *) paliashdr) + paliashdr->frames[frame].frame); | |
| pintervals = (float *) (((uint8_t *) paliashdr) + paliasgroup->intervals); | |
| numframes = paliasgroup->numframes; | |
| fullinterval = pintervals[numframes - 1]; | |
| time = cl.time + currententity->syncbase; | |
| targettime = time - (((int32_t) (time / fullinterval)) * fullinterval); | |
| for (i = 0; i < (numframes - 1); i++) | |
| { | |
| if (pintervals[i] > targettime) | |
| break; | |
| } | |
| r_apverts = (trivertx_t *) (((uint8_t *) paliashdr) + paliasgroup->frames[i].frame); | |
| } | |
| void R_AliasDrawModel(alight_t *plighting) | |
| { | |
| finalvert_t finalverts[(MAXALIASVERTS + ((CACHE_SIZE - 1) / (sizeof(finalvert_t)))) + 1]; | |
| auxvert_t auxverts[MAXALIASVERTS]; | |
| r_amodels_drawn++; | |
| pfinalverts = (finalvert_t *) ALIGN_PTR(&finalverts[0], CACHE_SIZE); | |
| pauxverts = &auxverts[0]; | |
| paliashdr = (aliashdr_t *) Mod_Extradata(currententity->model); | |
| pmdl = (mdl_t *) (((uint8_t *) paliashdr) + paliashdr->model); | |
| R_AliasSetupSkin(); | |
| R_AliasSetUpTransform(currententity->trivial_accept); | |
| R_AliasSetupLighting(plighting); | |
| R_AliasSetupFrame(); | |
| if (!currententity->colormap) | |
| Sys_Error("R_AliasDrawModel: !currententity->colormap"); | |
| r_affinetridesc.drawtype = (currententity->trivial_accept == 3) && r_recursiveaffinetriangles; | |
| if (r_affinetridesc.drawtype) | |
| { | |
| D_PolysetUpdateTables(); | |
| } | |
| acolormap = currententity->colormap; | |
| if (currententity != (&cl.viewent)) | |
| ziscale = ((float) 0x8000) * ((float) 0x10000); | |
| else | |
| ziscale = (((float) 0x8000) * ((float) 0x10000)) * 3.0; | |
| if (currententity->trivial_accept) | |
| R_AliasPrepareUnclippedPoints(); | |
| else | |
| R_AliasPreparePoints(); | |
| } | |
| void R_EntityRotate(vec3_t vec) | |
| { | |
| vec3_t tvec; | |
| VectorCopy(vec, tvec); | |
| vec[0] = DotProduct(entity_rotation[0], tvec); | |
| vec[1] = DotProduct(entity_rotation[1], tvec); | |
| vec[2] = DotProduct(entity_rotation[2], tvec); | |
| } | |
| void R_RotateBmodel(void) | |
| { | |
| float angle; | |
| float s; | |
| float c; | |
| float temp1[3][3]; | |
| float temp2[3][3]; | |
| float temp3[3][3]; | |
| angle = currententity->angles[YAW]; | |
| angle = ((angle * M_PI) * 2) / 360; | |
| s = sin(angle); | |
| c = cos(angle); | |
| temp1[0][0] = c; | |
| temp1[0][1] = s; | |
| temp1[0][2] = 0; | |
| temp1[1][0] = -s; | |
| temp1[1][1] = c; | |
| temp1[1][2] = 0; | |
| temp1[2][0] = 0; | |
| temp1[2][1] = 0; | |
| temp1[2][2] = 1; | |
| angle = currententity->angles[PITCH]; | |
| angle = ((angle * M_PI) * 2) / 360; | |
| s = sin(angle); | |
| c = cos(angle); | |
| temp2[0][0] = c; | |
| temp2[0][1] = 0; | |
| temp2[0][2] = -s; | |
| temp2[1][0] = 0; | |
| temp2[1][1] = 1; | |
| temp2[1][2] = 0; | |
| temp2[2][0] = s; | |
| temp2[2][1] = 0; | |
| temp2[2][2] = c; | |
| R_ConcatRotations(temp2, temp1, temp3); | |
| angle = currententity->angles[ROLL]; | |
| angle = ((angle * M_PI) * 2) / 360; | |
| s = sin(angle); | |
| c = cos(angle); | |
| temp1[0][0] = 1; | |
| temp1[0][1] = 0; | |
| temp1[0][2] = 0; | |
| temp1[1][0] = 0; | |
| temp1[1][1] = c; | |
| temp1[1][2] = s; | |
| temp1[2][0] = 0; | |
| temp1[2][1] = -s; | |
| temp1[2][2] = c; | |
| R_ConcatRotations(temp1, temp3, entity_rotation); | |
| R_EntityRotate(modelorg); | |
| R_EntityRotate(vpn); | |
| R_EntityRotate(vright); | |
| R_EntityRotate(vup); | |
| R_TransformFrustum(); | |
| } | |
| void R_RecursiveClipBPoly(bedge_t *pedges, mnode_t *pnode, msurface_t *psurf) | |
| { | |
| bedge_t *psideedges[2]; | |
| bedge_t *pnextedge; | |
| bedge_t *ptedge; | |
| int32_t i; | |
| int32_t side; | |
| int32_t lastside; | |
| float dist; | |
| float frac; | |
| float lastdist; | |
| mplane_t *splitplane; | |
| mplane_t tplane; | |
| mvertex_t *pvert; | |
| mvertex_t *plastvert; | |
| mvertex_t *ptvert; | |
| mnode_t *pn; | |
| psideedges[0] = (psideedges[1] = 0); | |
| makeclippededge = 0; | |
| splitplane = pnode->plane; | |
| tplane.dist = splitplane->dist - DotProduct(r_entorigin, splitplane->normal); | |
| tplane.normal[0] = DotProduct(entity_rotation[0], splitplane->normal); | |
| tplane.normal[1] = DotProduct(entity_rotation[1], splitplane->normal); | |
| tplane.normal[2] = DotProduct(entity_rotation[2], splitplane->normal); | |
| for (; pedges; pedges = pnextedge) | |
| { | |
| pnextedge = pedges->pnext; | |
| plastvert = pedges->v[0]; | |
| lastdist = DotProduct(plastvert->position, tplane.normal) - tplane.dist; | |
| if (lastdist > 0) | |
| lastside = 0; | |
| else | |
| lastside = 1; | |
| pvert = pedges->v[1]; | |
| dist = DotProduct(pvert->position, tplane.normal) - tplane.dist; | |
| if (dist > 0) | |
| side = 0; | |
| else | |
| side = 1; | |
| if (side != lastside) | |
| { | |
| if (numbverts >= MAX_BMODEL_VERTS) | |
| return; | |
| frac = lastdist / (lastdist - dist); | |
| ptvert = &pbverts[numbverts++]; | |
| ptvert->position[0] = plastvert->position[0] + (frac * (pvert->position[0] - plastvert->position[0])); | |
| ptvert->position[1] = plastvert->position[1] + (frac * (pvert->position[1] - plastvert->position[1])); | |
| ptvert->position[2] = plastvert->position[2] + (frac * (pvert->position[2] - plastvert->position[2])); | |
| if (numbedges >= (MAX_BMODEL_EDGES - 1)) | |
| { | |
| Con_Printf("Out of edges for bmodel\n"); | |
| return; | |
| } | |
| ptedge = &pbedges[numbedges]; | |
| ptedge->pnext = psideedges[lastside]; | |
| psideedges[lastside] = ptedge; | |
| ptedge->v[0] = plastvert; | |
| ptedge->v[1] = ptvert; | |
| ptedge = &pbedges[numbedges + 1]; | |
| ptedge->pnext = psideedges[side]; | |
| psideedges[side] = ptedge; | |
| ptedge->v[0] = ptvert; | |
| ptedge->v[1] = pvert; | |
| numbedges += 2; | |
| if (side == 0) | |
| { | |
| pfrontenter = ptvert; | |
| makeclippededge = 1; | |
| } | |
| else | |
| { | |
| pfrontexit = ptvert; | |
| makeclippededge = 1; | |
| } | |
| } | |
| else | |
| { | |
| pedges->pnext = psideedges[side]; | |
| psideedges[side] = pedges; | |
| } | |
| } | |
| if (makeclippededge) | |
| { | |
| if (numbedges >= (MAX_BMODEL_EDGES - 2)) | |
| { | |
| Con_Printf("Out of edges for bmodel\n"); | |
| return; | |
| } | |
| ptedge = &pbedges[numbedges]; | |
| ptedge->pnext = psideedges[0]; | |
| psideedges[0] = ptedge; | |
| ptedge->v[0] = pfrontexit; | |
| ptedge->v[1] = pfrontenter; | |
| ptedge = &pbedges[numbedges + 1]; | |
| ptedge->pnext = psideedges[1]; | |
| psideedges[1] = ptedge; | |
| ptedge->v[0] = pfrontenter; | |
| ptedge->v[1] = pfrontexit; | |
| numbedges += 2; | |
| } | |
| for (i = 0; i < 2; i++) | |
| { | |
| if (psideedges[i]) | |
| { | |
| pn = pnode->children[i]; | |
| if (pn->visframe == r_visframecount) | |
| { | |
| if (pn->contents < 0) | |
| { | |
| if (pn->contents != CONTENTS_SOLID) | |
| { | |
| r_currentbkey = ((mleaf_t *) pn)->key; | |
| R_RenderBmodelFace(psideedges[i], psurf); | |
| } | |
| } | |
| else | |
| { | |
| R_RecursiveClipBPoly(psideedges[i], pnode->children[i], psurf); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| void R_DrawSolidClippedSubmodelPolygons(model_t *pmodel) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| int32_t lindex; | |
| vec_t dot; | |
| msurface_t *psurf; | |
| int32_t numsurfaces; | |
| mplane_t *pplane; | |
| mvertex_t bverts[MAX_BMODEL_VERTS]; | |
| bedge_t bedges[MAX_BMODEL_EDGES]; | |
| bedge_t *pbedge; | |
| medge_t *pedge; | |
| medge_t *pedges; | |
| psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; | |
| numsurfaces = pmodel->nummodelsurfaces; | |
| pedges = pmodel->edges; | |
| for (i = 0; i < numsurfaces; i++, psurf++) | |
| { | |
| pplane = psurf->plane; | |
| dot = DotProduct(modelorg, pplane->normal) - pplane->dist; | |
| if (((psurf->flags & SURF_PLANEBACK) && (dot < (-BACKFACE_EPSILON))) || ((!(psurf->flags & SURF_PLANEBACK)) && (dot > BACKFACE_EPSILON))) | |
| { | |
| pbverts = bverts; | |
| pbedges = bedges; | |
| numbverts = (numbedges = 0); | |
| if (psurf->numedges > 0) | |
| { | |
| pbedge = &bedges[numbedges]; | |
| numbedges += psurf->numedges; | |
| for (j = 0; j < psurf->numedges; j++) | |
| { | |
| lindex = pmodel->surfedges[psurf->firstedge + j]; | |
| if (lindex > 0) | |
| { | |
| pedge = &pedges[lindex]; | |
| pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]]; | |
| pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]]; | |
| } | |
| else | |
| { | |
| lindex = -lindex; | |
| pedge = &pedges[lindex]; | |
| pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]]; | |
| pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]]; | |
| } | |
| pbedge[j].pnext = &pbedge[j + 1]; | |
| } | |
| pbedge[j - 1].pnext = 0; | |
| R_RecursiveClipBPoly(pbedge, currententity->topnode, psurf); | |
| } | |
| else | |
| { | |
| Sys_Error("no edges in bmodel"); | |
| } | |
| } | |
| } | |
| } | |
| void R_DrawSubmodelPolygons(model_t *pmodel, int32_t clipflags) | |
| { | |
| int32_t i; | |
| vec_t dot; | |
| msurface_t *psurf; | |
| int32_t numsurfaces; | |
| mplane_t *pplane; | |
| psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; | |
| numsurfaces = pmodel->nummodelsurfaces; | |
| for (i = 0; i < numsurfaces; i++, psurf++) | |
| { | |
| pplane = psurf->plane; | |
| dot = DotProduct(modelorg, pplane->normal) - pplane->dist; | |
| if (((psurf->flags & SURF_PLANEBACK) && (dot < (-BACKFACE_EPSILON))) || ((!(psurf->flags & SURF_PLANEBACK)) && (dot > BACKFACE_EPSILON))) | |
| { | |
| r_currentkey = ((mleaf_t *) currententity->topnode)->key; | |
| R_RenderFace(psurf, clipflags); | |
| } | |
| } | |
| } | |
| void R_RecursiveWorldNode(mnode_t *node, int32_t clipflags) | |
| { | |
| int32_t i; | |
| int32_t c; | |
| int32_t side; | |
| int32_t *pindex; | |
| vec3_t acceptpt; | |
| vec3_t rejectpt; | |
| mplane_t *plane; | |
| msurface_t *surf; | |
| msurface_t **mark; | |
| mleaf_t *pleaf; | |
| double d; | |
| double dot; | |
| if (node->contents == CONTENTS_SOLID) | |
| return; | |
| if (node->visframe != r_visframecount) | |
| return; | |
| if (clipflags) | |
| { | |
| for (i = 0; i < 4; i++) | |
| { | |
| if (!(clipflags & (1 << i))) | |
| continue; | |
| pindex = pfrustum_indexes[i]; | |
| rejectpt[0] = (float) node->minmaxs[pindex[0]]; | |
| rejectpt[1] = (float) node->minmaxs[pindex[1]]; | |
| rejectpt[2] = (float) node->minmaxs[pindex[2]]; | |
| d = DotProduct(rejectpt, view_clipplanes[i].normal); | |
| d -= view_clipplanes[i].dist; | |
| if (d <= 0) | |
| return; | |
| acceptpt[0] = (float) node->minmaxs[pindex[3 + 0]]; | |
| acceptpt[1] = (float) node->minmaxs[pindex[3 + 1]]; | |
| acceptpt[2] = (float) node->minmaxs[pindex[3 + 2]]; | |
| d = DotProduct(acceptpt, view_clipplanes[i].normal); | |
| d -= view_clipplanes[i].dist; | |
| if (d >= 0) | |
| clipflags &= ~(1 << i); | |
| } | |
| } | |
| if (node->contents < 0) | |
| { | |
| pleaf = (mleaf_t *) node; | |
| mark = pleaf->firstmarksurface; | |
| c = pleaf->nummarksurfaces; | |
| if (c) | |
| { | |
| do | |
| { | |
| (*mark)->visframe = r_framecount; | |
| mark++; | |
| } | |
| while (--c); | |
| } | |
| if (pleaf->efrags) | |
| { | |
| R_StoreEfrags(&pleaf->efrags); | |
| } | |
| pleaf->key = r_currentkey; | |
| r_currentkey++; | |
| } | |
| else | |
| { | |
| plane = node->plane; | |
| switch (plane->type) | |
| { | |
| case PLANE_X: | |
| dot = modelorg[0] - plane->dist; | |
| break; | |
| case PLANE_Y: | |
| dot = modelorg[1] - plane->dist; | |
| break; | |
| case PLANE_Z: | |
| dot = modelorg[2] - plane->dist; | |
| break; | |
| default: | |
| dot = DotProduct(modelorg, plane->normal) - plane->dist; | |
| break; | |
| } | |
| if (dot >= 0) | |
| side = 0; | |
| else | |
| side = 1; | |
| R_RecursiveWorldNode(node->children[side], clipflags); | |
| c = node->numsurfaces; | |
| if (c) | |
| { | |
| surf = cl.worldmodel->surfaces + node->firstsurface; | |
| if (dot < (-BACKFACE_EPSILON)) | |
| { | |
| do | |
| { | |
| if ((surf->flags & SURF_PLANEBACK) && (surf->visframe == r_framecount)) | |
| { | |
| if (r_drawpolys) | |
| { | |
| if (r_worldpolysbacktofront) | |
| { | |
| if (numbtofpolys < MAX_BTOFPOLYS) | |
| { | |
| pbtofpolys[numbtofpolys].clipflags = clipflags; | |
| pbtofpolys[numbtofpolys].psurf = surf; | |
| numbtofpolys++; | |
| } | |
| } | |
| else | |
| { | |
| R_RenderPoly(surf, clipflags); | |
| } | |
| } | |
| else | |
| { | |
| R_RenderFace(surf, clipflags); | |
| } | |
| } | |
| surf++; | |
| } | |
| while (--c); | |
| } | |
| else | |
| if (dot > BACKFACE_EPSILON) | |
| { | |
| do | |
| { | |
| if ((!(surf->flags & SURF_PLANEBACK)) && (surf->visframe == r_framecount)) | |
| { | |
| if (r_drawpolys) | |
| { | |
| if (r_worldpolysbacktofront) | |
| { | |
| if (numbtofpolys < MAX_BTOFPOLYS) | |
| { | |
| pbtofpolys[numbtofpolys].clipflags = clipflags; | |
| pbtofpolys[numbtofpolys].psurf = surf; | |
| numbtofpolys++; | |
| } | |
| } | |
| else | |
| { | |
| R_RenderPoly(surf, clipflags); | |
| } | |
| } | |
| else | |
| { | |
| R_RenderFace(surf, clipflags); | |
| } | |
| } | |
| surf++; | |
| } | |
| while (--c); | |
| } | |
| r_currentkey++; | |
| } | |
| R_RecursiveWorldNode(node->children[!side], clipflags); | |
| } | |
| } | |
| void R_RenderWorld(void) | |
| { | |
| int32_t i; | |
| model_t *clmodel; | |
| btofpoly_t btofpolys[MAX_BTOFPOLYS]; | |
| pbtofpolys = btofpolys; | |
| currententity = &cl_entities[0]; | |
| VectorCopy(r_origin, modelorg); | |
| clmodel = currententity->model; | |
| r_pcurrentvertbase = clmodel->vertexes; | |
| R_RecursiveWorldNode(clmodel->nodes, 15); | |
| if (r_worldpolysbacktofront) | |
| { | |
| for (i = numbtofpolys - 1; i >= 0; i--) | |
| { | |
| R_RenderPoly(btofpolys[i].psurf, btofpolys[i].clipflags); | |
| } | |
| } | |
| } | |
| void R_EmitEdge(mvertex_t *pv0, mvertex_t *pv1) | |
| { | |
| edge_t *edge; | |
| edge_t *pcheck; | |
| int32_t u_check; | |
| float u; | |
| float u_step; | |
| vec3_t local; | |
| vec3_t transformed; | |
| float *world; | |
| int32_t v; | |
| int32_t v2; | |
| int32_t ceilv0; | |
| float scale; | |
| float lzi0; | |
| float u0; | |
| float v0; | |
| int32_t side; | |
| if (r_lastvertvalid) | |
| { | |
| u0 = r_u1; | |
| v0 = r_v1; | |
| lzi0 = r_lzi1; | |
| ceilv0 = r_ceilv1; | |
| } | |
| else | |
| { | |
| world = &pv0->position[0]; | |
| VectorSubtract(world, modelorg, local); | |
| TransformVector(local, transformed); | |
| if (transformed[2] < NEAR_CLIP) | |
| transformed[2] = NEAR_CLIP; | |
| lzi0 = 1.0 / transformed[2]; | |
| scale = xscale * lzi0; | |
| u0 = xcenter + (scale * transformed[0]); | |
| if (u0 < r_refdef.fvrectx_adj) | |
| u0 = r_refdef.fvrectx_adj; | |
| if (u0 > r_refdef.fvrectright_adj) | |
| u0 = r_refdef.fvrectright_adj; | |
| scale = yscale * lzi0; | |
| v0 = ycenter - (scale * transformed[1]); | |
| if (v0 < r_refdef.fvrecty_adj) | |
| v0 = r_refdef.fvrecty_adj; | |
| if (v0 > r_refdef.fvrectbottom_adj) | |
| v0 = r_refdef.fvrectbottom_adj; | |
| ceilv0 = (int32_t) ceil(v0); | |
| } | |
| world = &pv1->position[0]; | |
| VectorSubtract(world, modelorg, local); | |
| TransformVector(local, transformed); | |
| if (transformed[2] < NEAR_CLIP) | |
| transformed[2] = NEAR_CLIP; | |
| r_lzi1 = 1.0 / transformed[2]; | |
| scale = xscale * r_lzi1; | |
| r_u1 = xcenter + (scale * transformed[0]); | |
| if (r_u1 < r_refdef.fvrectx_adj) | |
| r_u1 = r_refdef.fvrectx_adj; | |
| if (r_u1 > r_refdef.fvrectright_adj) | |
| r_u1 = r_refdef.fvrectright_adj; | |
| scale = yscale * r_lzi1; | |
| r_v1 = ycenter - (scale * transformed[1]); | |
| if (r_v1 < r_refdef.fvrecty_adj) | |
| r_v1 = r_refdef.fvrecty_adj; | |
| if (r_v1 > r_refdef.fvrectbottom_adj) | |
| r_v1 = r_refdef.fvrectbottom_adj; | |
| if (r_lzi1 > lzi0) | |
| lzi0 = r_lzi1; | |
| if (lzi0 > r_nearzi) | |
| r_nearzi = lzi0; | |
| if (r_nearzionly) | |
| return; | |
| r_emitted = 1; | |
| r_ceilv1 = (int32_t) ceil(r_v1); | |
| if (ceilv0 == r_ceilv1) | |
| { | |
| if (cacheoffset != 0x7FFFFFFF) | |
| { | |
| cacheoffset = FULLY_CLIPPED_CACHED | (r_framecount & FRAMECOUNT_MASK); | |
| } | |
| return; | |
| } | |
| side = ceilv0 > r_ceilv1; | |
| edge = edge_p++; | |
| edge->owner = r_pedge; | |
| edge->nearzi = lzi0; | |
| if (side == 0) | |
| { | |
| v = ceilv0; | |
| v2 = r_ceilv1 - 1; | |
| edge->surfs[0] = surface_p - surfaces; | |
| edge->surfs[1] = 0; | |
| u_step = (r_u1 - u0) / (r_v1 - v0); | |
| u = u0 + ((((float) v) - v0) * u_step); | |
| } | |
| else | |
| { | |
| v2 = ceilv0 - 1; | |
| v = r_ceilv1; | |
| edge->surfs[0] = 0; | |
| edge->surfs[1] = surface_p - surfaces; | |
| u_step = (u0 - r_u1) / (v0 - r_v1); | |
| u = r_u1 + ((((float) v) - r_v1) * u_step); | |
| } | |
| edge->u_step = u_step * 0x100000; | |
| edge->u = (u * 0x100000) + 0xFFFFF; | |
| if (edge->u < r_refdef.vrect_x_adj_shift20) | |
| edge->u = r_refdef.vrect_x_adj_shift20; | |
| if (edge->u > r_refdef.vrectright_adj_shift20) | |
| edge->u = r_refdef.vrectright_adj_shift20; | |
| u_check = edge->u; | |
| if (edge->surfs[0]) | |
| u_check++; | |
| if ((!newedges[v]) || (newedges[v]->u >= u_check)) | |
| { | |
| edge->next = newedges[v]; | |
| newedges[v] = edge; | |
| } | |
| else | |
| { | |
| pcheck = newedges[v]; | |
| while (pcheck->next && (pcheck->next->u < u_check)) | |
| pcheck = pcheck->next; | |
| edge->next = pcheck->next; | |
| pcheck->next = edge; | |
| } | |
| edge->nextremove = removeedges[v2]; | |
| removeedges[v2] = edge; | |
| } | |
| void R_ClipEdge(mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip) | |
| { | |
| float d0; | |
| float d1; | |
| float f; | |
| mvertex_t clipvert; | |
| if (clip) | |
| { | |
| do | |
| { | |
| d0 = DotProduct(pv0->position, clip->normal) - clip->dist; | |
| d1 = DotProduct(pv1->position, clip->normal) - clip->dist; | |
| if (d0 >= 0) | |
| { | |
| if (d1 >= 0) | |
| { | |
| continue; | |
| } | |
| cacheoffset = 0x7FFFFFFF; | |
| f = d0 / (d0 - d1); | |
| clipvert.position[0] = pv0->position[0] + (f * (pv1->position[0] - pv0->position[0])); | |
| clipvert.position[1] = pv0->position[1] + (f * (pv1->position[1] - pv0->position[1])); | |
| clipvert.position[2] = pv0->position[2] + (f * (pv1->position[2] - pv0->position[2])); | |
| if (clip->leftedge) | |
| { | |
| r_leftclipped = 1; | |
| r_leftexit = clipvert; | |
| } | |
| else | |
| if (clip->rightedge) | |
| { | |
| r_rightclipped = 1; | |
| r_rightexit = clipvert; | |
| } | |
| R_ClipEdge(pv0, &clipvert, clip->next); | |
| return; | |
| } | |
| else | |
| { | |
| if (d1 < 0) | |
| { | |
| if (!r_leftclipped) | |
| cacheoffset = FULLY_CLIPPED_CACHED | (r_framecount & FRAMECOUNT_MASK); | |
| return; | |
| } | |
| r_lastvertvalid = 0; | |
| cacheoffset = 0x7FFFFFFF; | |
| f = d0 / (d0 - d1); | |
| clipvert.position[0] = pv0->position[0] + (f * (pv1->position[0] - pv0->position[0])); | |
| clipvert.position[1] = pv0->position[1] + (f * (pv1->position[1] - pv0->position[1])); | |
| clipvert.position[2] = pv0->position[2] + (f * (pv1->position[2] - pv0->position[2])); | |
| if (clip->leftedge) | |
| { | |
| r_leftclipped = 1; | |
| r_leftenter = clipvert; | |
| } | |
| else | |
| if (clip->rightedge) | |
| { | |
| r_rightclipped = 1; | |
| r_rightenter = clipvert; | |
| } | |
| R_ClipEdge(&clipvert, pv1, clip->next); | |
| return; | |
| } | |
| } | |
| while ((clip = clip->next) != 0); | |
| } | |
| R_EmitEdge(pv0, pv1); | |
| } | |
| void R_EmitCachedEdge(void) | |
| { | |
| edge_t *pedge_t; | |
| pedge_t = (edge_t *) (((uint8_t *) r_edges) + r_pedge->cachededgeoffset); | |
| if (!pedge_t->surfs[0]) | |
| pedge_t->surfs[0] = (int32_t) (surface_p - surfaces); | |
| else | |
| pedge_t->surfs[1] = (int32_t) (surface_p - surfaces); | |
| if (pedge_t->nearzi > r_nearzi) | |
| r_nearzi = pedge_t->nearzi; | |
| r_emitted = 1; | |
| } | |
| void R_RenderFace(msurface_t *fa, int32_t clipflags) | |
| { | |
| int32_t i; | |
| int32_t lindex; | |
| uint32_t mask; | |
| mplane_t *pplane; | |
| float distinv; | |
| vec3_t p_normal; | |
| medge_t *pedges; | |
| medge_t tedge; | |
| clipplane_t *pclip; | |
| if (surface_p >= surf_max) | |
| { | |
| r_outofsurfaces++; | |
| return; | |
| } | |
| if (((edge_p + fa->numedges) + 4) >= edge_max) | |
| { | |
| r_outofedges += fa->numedges; | |
| return; | |
| } | |
| c_faceclip++; | |
| pclip = 0; | |
| for (i = 3, mask = 0x08; i >= 0; i--, mask >>= 1) | |
| { | |
| if (clipflags & mask) | |
| { | |
| view_clipplanes[i].next = pclip; | |
| pclip = &view_clipplanes[i]; | |
| } | |
| } | |
| r_emitted = 0; | |
| r_nearzi = 0; | |
| r_nearzionly = 0; | |
| makeleftedge = (makerightedge = 0); | |
| pedges = currententity->model->edges; | |
| r_lastvertvalid = 0; | |
| for (i = 0; i < fa->numedges; i++) | |
| { | |
| lindex = currententity->model->surfedges[fa->firstedge + i]; | |
| if (lindex > 0) | |
| { | |
| r_pedge = &pedges[lindex]; | |
| if (!insubmodel) | |
| { | |
| if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED) | |
| { | |
| if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) == r_framecount) | |
| { | |
| r_lastvertvalid = 0; | |
| continue; | |
| } | |
| } | |
| else | |
| { | |
| uintptr_t edge_base = (uintptr_t) ((uint8_t *) r_edges); | |
| uintptr_t edge_cur = (uintptr_t) ((uint8_t *) edge_p); | |
| uintptr_t edge_diff = edge_cur - edge_base; | |
| if ((edge_diff > ((uintptr_t) r_pedge->cachededgeoffset)) && (((edge_t *) (((uint8_t *) r_edges) + r_pedge->cachededgeoffset))->owner == r_pedge)) | |
| { | |
| R_EmitCachedEdge(); | |
| r_lastvertvalid = 0; | |
| continue; | |
| } | |
| } | |
| } | |
| cacheoffset = ((uint8_t *) edge_p) - ((uint8_t *) r_edges); | |
| r_leftclipped = (r_rightclipped = 0); | |
| R_ClipEdge(&r_pcurrentvertbase[r_pedge->v[0]], &r_pcurrentvertbase[r_pedge->v[1]], pclip); | |
| r_pedge->cachededgeoffset = cacheoffset; | |
| if (r_leftclipped) | |
| makeleftedge = 1; | |
| if (r_rightclipped) | |
| makerightedge = 1; | |
| r_lastvertvalid = 1; | |
| } | |
| else | |
| { | |
| lindex = -lindex; | |
| r_pedge = &pedges[lindex]; | |
| if (!insubmodel) | |
| { | |
| if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED) | |
| { | |
| if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) == r_framecount) | |
| { | |
| r_lastvertvalid = 0; | |
| continue; | |
| } | |
| } | |
| else | |
| { | |
| uintptr_t edge_base = (uintptr_t) ((uint8_t *) r_edges); | |
| uintptr_t edge_cur = (uintptr_t) ((uint8_t *) edge_p); | |
| uintptr_t edge_diff = edge_cur - edge_base; | |
| if ((edge_diff > ((uintptr_t) r_pedge->cachededgeoffset)) && (((edge_t *) (((uint8_t *) r_edges) + r_pedge->cachededgeoffset))->owner == r_pedge)) | |
| { | |
| R_EmitCachedEdge(); | |
| r_lastvertvalid = 0; | |
| continue; | |
| } | |
| } | |
| } | |
| cacheoffset = ((uint8_t *) edge_p) - ((uint8_t *) r_edges); | |
| r_leftclipped = (r_rightclipped = 0); | |
| R_ClipEdge(&r_pcurrentvertbase[r_pedge->v[1]], &r_pcurrentvertbase[r_pedge->v[0]], pclip); | |
| r_pedge->cachededgeoffset = cacheoffset; | |
| if (r_leftclipped) | |
| makeleftedge = 1; | |
| if (r_rightclipped) | |
| makerightedge = 1; | |
| r_lastvertvalid = 1; | |
| } | |
| } | |
| if (makeleftedge) | |
| { | |
| r_pedge = &tedge; | |
| r_lastvertvalid = 0; | |
| R_ClipEdge(&r_leftexit, &r_leftenter, pclip->next); | |
| } | |
| if (makerightedge) | |
| { | |
| r_pedge = &tedge; | |
| r_lastvertvalid = 0; | |
| r_nearzionly = 1; | |
| R_ClipEdge(&r_rightexit, &r_rightenter, view_clipplanes[1].next); | |
| } | |
| if (!r_emitted) | |
| return; | |
| r_polycount++; | |
| surface_p->data = (void *) fa; | |
| surface_p->nearzi = r_nearzi; | |
| surface_p->flags = fa->flags; | |
| surface_p->insubmodel = insubmodel; | |
| surface_p->spanstate = 0; | |
| surface_p->entity = currententity; | |
| surface_p->key = r_currentkey++; | |
| surface_p->spans = 0; | |
| pplane = fa->plane; | |
| TransformVector(pplane->normal, p_normal); | |
| distinv = 1.0f / (pplane->dist - DotProduct(modelorg, pplane->normal)); | |
| surface_p->d_zistepu = (p_normal[0] * xscaleinv) * distinv; | |
| surface_p->d_zistepv = ((-p_normal[1]) * yscaleinv) * distinv; | |
| surface_p->d_ziorigin = ((p_normal[2] * distinv) - (xcenter * surface_p->d_zistepu)) - (ycenter * surface_p->d_zistepv); | |
| surface_p++; | |
| } | |
| void R_RenderBmodelFace(bedge_t *pedges, msurface_t *psurf) | |
| { | |
| int32_t i; | |
| uint32_t mask; | |
| mplane_t *pplane; | |
| float distinv; | |
| vec3_t p_normal; | |
| medge_t tedge; | |
| clipplane_t *pclip; | |
| if (surface_p >= surf_max) | |
| { | |
| r_outofsurfaces++; | |
| return; | |
| } | |
| if (((edge_p + psurf->numedges) + 4) >= edge_max) | |
| { | |
| r_outofedges += psurf->numedges; | |
| return; | |
| } | |
| c_faceclip++; | |
| r_pedge = &tedge; | |
| pclip = 0; | |
| for (i = 3, mask = 0x08; i >= 0; i--, mask >>= 1) | |
| { | |
| if (r_clipflags & mask) | |
| { | |
| view_clipplanes[i].next = pclip; | |
| pclip = &view_clipplanes[i]; | |
| } | |
| } | |
| r_emitted = 0; | |
| r_nearzi = 0; | |
| r_nearzionly = 0; | |
| makeleftedge = (makerightedge = 0); | |
| r_lastvertvalid = 0; | |
| for (; pedges; pedges = pedges->pnext) | |
| { | |
| r_leftclipped = (r_rightclipped = 0); | |
| R_ClipEdge(pedges->v[0], pedges->v[1], pclip); | |
| if (r_leftclipped) | |
| makeleftedge = 1; | |
| if (r_rightclipped) | |
| makerightedge = 1; | |
| } | |
| if (makeleftedge) | |
| { | |
| r_pedge = &tedge; | |
| R_ClipEdge(&r_leftexit, &r_leftenter, pclip->next); | |
| } | |
| if (makerightedge) | |
| { | |
| r_pedge = &tedge; | |
| r_nearzionly = 1; | |
| R_ClipEdge(&r_rightexit, &r_rightenter, view_clipplanes[1].next); | |
| } | |
| if (!r_emitted) | |
| return; | |
| r_polycount++; | |
| surface_p->data = (void *) psurf; | |
| surface_p->nearzi = r_nearzi; | |
| surface_p->flags = psurf->flags; | |
| surface_p->insubmodel = 1; | |
| surface_p->spanstate = 0; | |
| surface_p->entity = currententity; | |
| surface_p->key = r_currentbkey; | |
| surface_p->spans = 0; | |
| pplane = psurf->plane; | |
| TransformVector(pplane->normal, p_normal); | |
| distinv = 1.0 / (pplane->dist - DotProduct(modelorg, pplane->normal)); | |
| surface_p->d_zistepu = (p_normal[0] * xscaleinv) * distinv; | |
| surface_p->d_zistepv = ((-p_normal[1]) * yscaleinv) * distinv; | |
| surface_p->d_ziorigin = ((p_normal[2] * distinv) - (xcenter * surface_p->d_zistepu)) - (ycenter * surface_p->d_zistepv); | |
| surface_p++; | |
| } | |
| void R_RenderPoly(msurface_t *fa, int32_t clipflags) | |
| { | |
| int32_t i; | |
| int32_t lindex; | |
| int32_t lnumverts; | |
| int32_t s_axis; | |
| int32_t t_axis; | |
| float dist; | |
| float lastdist; | |
| float lzi; | |
| float scale; | |
| float u; | |
| float v; | |
| float frac; | |
| uint32_t mask; | |
| vec3_t local; | |
| vec3_t transformed; | |
| clipplane_t *pclip; | |
| medge_t *pedges; | |
| mplane_t *pplane; | |
| mvertex_t verts[2][100]; | |
| polyvert_t pverts[100]; | |
| int32_t vertpage; | |
| int32_t newverts; | |
| int32_t newpage; | |
| int32_t lastvert; | |
| bool visible; | |
| s_axis = (t_axis = 0); | |
| pclip = 0; | |
| for (i = 3, mask = 0x08; i >= 0; i--, mask >>= 1) | |
| { | |
| if (clipflags & mask) | |
| { | |
| view_clipplanes[i].next = pclip; | |
| pclip = &view_clipplanes[i]; | |
| } | |
| } | |
| pedges = currententity->model->edges; | |
| lnumverts = fa->numedges; | |
| vertpage = 0; | |
| for (i = 0; i < lnumverts; i++) | |
| { | |
| lindex = currententity->model->surfedges[fa->firstedge + i]; | |
| if (lindex > 0) | |
| { | |
| r_pedge = &pedges[lindex]; | |
| verts[0][i] = r_pcurrentvertbase[r_pedge->v[0]]; | |
| } | |
| else | |
| { | |
| r_pedge = &pedges[-lindex]; | |
| verts[0][i] = r_pcurrentvertbase[r_pedge->v[1]]; | |
| } | |
| } | |
| while (pclip) | |
| { | |
| lastvert = lnumverts - 1; | |
| lastdist = DotProduct(verts[vertpage][lastvert].position, pclip->normal) - pclip->dist; | |
| visible = 0; | |
| newverts = 0; | |
| newpage = vertpage ^ 1; | |
| for (i = 0; i < lnumverts; i++) | |
| { | |
| dist = DotProduct(verts[vertpage][i].position, pclip->normal) - pclip->dist; | |
| if ((lastdist > 0) != (dist > 0)) | |
| { | |
| frac = dist / (dist - lastdist); | |
| verts[newpage][newverts].position[0] = verts[vertpage][i].position[0] + ((verts[vertpage][lastvert].position[0] - verts[vertpage][i].position[0]) * frac); | |
| verts[newpage][newverts].position[1] = verts[vertpage][i].position[1] + ((verts[vertpage][lastvert].position[1] - verts[vertpage][i].position[1]) * frac); | |
| verts[newpage][newverts].position[2] = verts[vertpage][i].position[2] + ((verts[vertpage][lastvert].position[2] - verts[vertpage][i].position[2]) * frac); | |
| newverts++; | |
| } | |
| if (dist >= 0) | |
| { | |
| verts[newpage][newverts] = verts[vertpage][i]; | |
| newverts++; | |
| visible = 1; | |
| } | |
| lastvert = i; | |
| lastdist = dist; | |
| } | |
| if ((!visible) || (newverts < 3)) | |
| return; | |
| lnumverts = newverts; | |
| vertpage ^= 1; | |
| pclip = pclip->next; | |
| } | |
| pplane = fa->plane; | |
| switch (pplane->type) | |
| { | |
| case PLANE_X: | |
| case PLANE_ANYX: | |
| s_axis = 1; | |
| t_axis = 2; | |
| break; | |
| case PLANE_Y: | |
| case PLANE_ANYY: | |
| s_axis = 0; | |
| t_axis = 2; | |
| break; | |
| case PLANE_Z: | |
| case PLANE_ANYZ: | |
| s_axis = 0; | |
| t_axis = 1; | |
| break; | |
| } | |
| r_nearzi = 0; | |
| for (i = 0; i < lnumverts; i++) | |
| { | |
| VectorSubtract(verts[vertpage][i].position, modelorg, local); | |
| TransformVector(local, transformed); | |
| if (transformed[2] < NEAR_CLIP) | |
| transformed[2] = NEAR_CLIP; | |
| lzi = 1.0 / transformed[2]; | |
| if (lzi > r_nearzi) | |
| r_nearzi = lzi; | |
| scale = xscale * lzi; | |
| u = xcenter + (scale * transformed[0]); | |
| if (u < r_refdef.fvrectx_adj) | |
| u = r_refdef.fvrectx_adj; | |
| if (u > r_refdef.fvrectright_adj) | |
| u = r_refdef.fvrectright_adj; | |
| scale = yscale * lzi; | |
| v = ycenter - (scale * transformed[1]); | |
| if (v < r_refdef.fvrecty_adj) | |
| v = r_refdef.fvrecty_adj; | |
| if (v > r_refdef.fvrectbottom_adj) | |
| v = r_refdef.fvrectbottom_adj; | |
| pverts[i].u = u; | |
| pverts[i].v = v; | |
| pverts[i].zi = lzi; | |
| pverts[i].s = verts[vertpage][i].position[s_axis]; | |
| pverts[i].t = verts[vertpage][i].position[t_axis]; | |
| } | |
| r_polydesc.numverts = lnumverts; | |
| r_polydesc.nearzi = r_nearzi; | |
| r_polydesc.pcurrentface = fa; | |
| r_polydesc.pverts = pverts; | |
| D_DrawPoly(); | |
| } | |
| void R_ZDrawSubmodelPolys(model_t *pmodel) | |
| { | |
| int32_t i; | |
| int32_t numsurfaces; | |
| msurface_t *psurf; | |
| float dot; | |
| mplane_t *pplane; | |
| psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; | |
| numsurfaces = pmodel->nummodelsurfaces; | |
| for (i = 0; i < numsurfaces; i++, psurf++) | |
| { | |
| pplane = psurf->plane; | |
| dot = DotProduct(modelorg, pplane->normal) - pplane->dist; | |
| if (((psurf->flags & SURF_PLANEBACK) && (dot < (-BACKFACE_EPSILON))) || ((!(psurf->flags & SURF_PLANEBACK)) && (dot > BACKFACE_EPSILON))) | |
| { | |
| R_RenderPoly(psurf, 15); | |
| } | |
| } | |
| } | |
| void R_DrawCulledPolys(void) | |
| { | |
| surf_t *s; | |
| msurface_t *pface; | |
| currententity = &cl_entities[0]; | |
| if (r_worldpolysbacktofront) | |
| { | |
| for (s = surface_p - 1; s > (&surfaces[1]); s--) | |
| { | |
| if (!s->spans) | |
| continue; | |
| if (!(s->flags & SURF_DRAWBACKGROUND)) | |
| { | |
| pface = (msurface_t *) s->data; | |
| R_RenderPoly(pface, 15); | |
| } | |
| } | |
| } | |
| else | |
| { | |
| for (s = &surfaces[1]; s < surface_p; s++) | |
| { | |
| if (!s->spans) | |
| continue; | |
| if (!(s->flags & SURF_DRAWBACKGROUND)) | |
| { | |
| pface = (msurface_t *) s->data; | |
| R_RenderPoly(pface, 15); | |
| } | |
| } | |
| } | |
| } | |
| void R_BeginEdgeFrame(void) | |
| { | |
| int32_t v; | |
| edge_p = r_edges; | |
| edge_max = &r_edges[r_numallocatededges]; | |
| surface_p = &surfaces[2]; | |
| surfaces[1].spans = 0; | |
| surfaces[1].flags = SURF_DRAWBACKGROUND; | |
| if (r_draworder.value) | |
| { | |
| pdrawfunc = R_GenerateSpansBackward; | |
| surfaces[1].key = 0; | |
| r_currentkey = 1; | |
| } | |
| else | |
| { | |
| pdrawfunc = R_GenerateSpans; | |
| surfaces[1].key = 0x7FFFFFFF; | |
| r_currentkey = 0; | |
| } | |
| for (v = r_refdef.vrect.y; v < r_refdef.vrectbottom; v++) | |
| { | |
| newedges[v] = (removeedges[v] = 0); | |
| } | |
| } | |
| void R_InsertNewEdges(edge_t *edgestoadd, edge_t *edgelist) | |
| { | |
| edge_t *next_edge; | |
| do | |
| { | |
| next_edge = edgestoadd->next; | |
| edgesearch: | |
| if (edgelist->u >= edgestoadd->u) | |
| goto addedge; | |
| edgelist = edgelist->next; | |
| if (edgelist->u >= edgestoadd->u) | |
| goto addedge; | |
| edgelist = edgelist->next; | |
| if (edgelist->u >= edgestoadd->u) | |
| goto addedge; | |
| edgelist = edgelist->next; | |
| if (edgelist->u >= edgestoadd->u) | |
| goto addedge; | |
| edgelist = edgelist->next; | |
| goto edgesearch; | |
| addedge: | |
| edgestoadd->next = edgelist; | |
| edgestoadd->prev = edgelist->prev; | |
| edgelist->prev->next = edgestoadd; | |
| edgelist->prev = edgestoadd; | |
| } | |
| while ((edgestoadd = next_edge) != 0); | |
| } | |
| void R_RemoveEdges(edge_t *pedge) | |
| { | |
| do | |
| { | |
| pedge->next->prev = pedge->prev; | |
| pedge->prev->next = pedge->next; | |
| } | |
| while ((pedge = pedge->nextremove) != 0); | |
| } | |
| void R_StepActiveU(edge_t *pedge) | |
| { | |
| edge_t *pnext_edge; | |
| edge_t *pwedge; | |
| while (1) | |
| { | |
| nextedge: | |
| pedge->u += pedge->u_step; | |
| if (pedge->u < pedge->prev->u) | |
| goto pushback; | |
| pedge = pedge->next; | |
| pedge->u += pedge->u_step; | |
| if (pedge->u < pedge->prev->u) | |
| goto pushback; | |
| pedge = pedge->next; | |
| pedge->u += pedge->u_step; | |
| if (pedge->u < pedge->prev->u) | |
| goto pushback; | |
| pedge = pedge->next; | |
| pedge->u += pedge->u_step; | |
| if (pedge->u < pedge->prev->u) | |
| goto pushback; | |
| pedge = pedge->next; | |
| goto nextedge; | |
| pushback: | |
| if (pedge == (&edge_aftertail)) | |
| return; | |
| pnext_edge = pedge->next; | |
| pedge->next->prev = pedge->prev; | |
| pedge->prev->next = pedge->next; | |
| pwedge = pedge->prev->prev; | |
| while (pwedge->u > pedge->u) | |
| { | |
| pwedge = pwedge->prev; | |
| } | |
| pedge->next = pwedge->next; | |
| pedge->prev = pwedge; | |
| pedge->next->prev = pedge; | |
| pwedge->next = pedge; | |
| pedge = pnext_edge; | |
| if (pedge == (&edge_tail)) | |
| return; | |
| } | |
| } | |
| static void R_CleanupSpan() | |
| { | |
| surf_t *surf; | |
| int32_t iu; | |
| espan_t *span; | |
| surf = surfaces[1].next; | |
| iu = edge_tail_u_shift20; | |
| if (iu > surf->last_u) | |
| { | |
| span = span_p++; | |
| span->u = surf->last_u; | |
| span->count = iu - span->u; | |
| span->v = current_iv; | |
| span->pnext = surf->spans; | |
| surf->spans = span; | |
| } | |
| do | |
| { | |
| surf->spanstate = 0; | |
| surf = surf->next; | |
| } | |
| while (surf != (&surfaces[1])); | |
| } | |
| static void R_LeadingEdgeBackwards(edge_t *edge) | |
| { | |
| espan_t *span; | |
| surf_t *surf; | |
| surf_t *surf2; | |
| int32_t iu; | |
| surf = &surfaces[edge->surfs[1]]; | |
| if ((++surf->spanstate) == 1) | |
| { | |
| surf2 = surfaces[1].next; | |
| if (surf->key > surf2->key) | |
| goto newtop; | |
| if (surf->insubmodel && (surf->key == surf2->key)) | |
| { | |
| goto newtop; | |
| } | |
| continue_search: | |
| do | |
| { | |
| surf2 = surf2->next; | |
| } | |
| while (surf->key < surf2->key); | |
| if (surf->key == surf2->key) | |
| { | |
| if (!surf->insubmodel) | |
| goto continue_search; | |
| } | |
| goto gotposition; | |
| newtop: | |
| iu = edge->u >> 20; | |
| if (iu > surf2->last_u) | |
| { | |
| span = span_p++; | |
| span->u = surf2->last_u; | |
| span->count = iu - span->u; | |
| span->v = current_iv; | |
| span->pnext = surf2->spans; | |
| surf2->spans = span; | |
| } | |
| surf->last_u = iu; | |
| gotposition: | |
| surf->next = surf2; | |
| surf->prev = surf2->prev; | |
| surf2->prev->next = surf; | |
| surf2->prev = surf; | |
| } | |
| } | |
| static void R_TrailingEdge(surf_t *surf, edge_t *edge) | |
| { | |
| espan_t *span; | |
| int32_t iu; | |
| if ((--surf->spanstate) == 0) | |
| { | |
| if (surf->insubmodel) | |
| r_bmodelactive--; | |
| if (surf == surfaces[1].next) | |
| { | |
| iu = edge->u >> 20; | |
| if (iu > surf->last_u) | |
| { | |
| span = span_p++; | |
| span->u = surf->last_u; | |
| span->count = iu - span->u; | |
| span->v = current_iv; | |
| span->pnext = surf->spans; | |
| surf->spans = span; | |
| } | |
| surf->next->last_u = iu; | |
| } | |
| surf->prev->next = surf->next; | |
| surf->next->prev = surf->prev; | |
| } | |
| } | |
| static void R_LeadingEdge(edge_t *edge) | |
| { | |
| espan_t *span; | |
| surf_t *surf; | |
| surf_t *surf2; | |
| int32_t iu; | |
| double fu; | |
| double newzi; | |
| double testzi; | |
| double newzitop; | |
| double newzibottom; | |
| if (edge->surfs[1]) | |
| { | |
| surf = &surfaces[edge->surfs[1]]; | |
| if ((++surf->spanstate) == 1) | |
| { | |
| if (surf->insubmodel) | |
| r_bmodelactive++; | |
| surf2 = surfaces[1].next; | |
| if (surf->key < surf2->key) | |
| goto newtop; | |
| if (surf->insubmodel && (surf->key == surf2->key)) | |
| { | |
| fu = ((float) (edge->u - 0xFFFFF)) * (1.0 / 0x100000); | |
| newzi = (surf->d_ziorigin + (fv * surf->d_zistepv)) + (fu * surf->d_zistepu); | |
| newzibottom = newzi * 0.99; | |
| testzi = (surf2->d_ziorigin + (fv * surf2->d_zistepv)) + (fu * surf2->d_zistepu); | |
| if (newzibottom >= testzi) | |
| { | |
| goto newtop; | |
| } | |
| newzitop = newzi * 1.01; | |
| if (newzitop >= testzi) | |
| { | |
| if (surf->d_zistepu >= surf2->d_zistepu) | |
| { | |
| goto newtop; | |
| } | |
| } | |
| } | |
| continue_search: | |
| do | |
| { | |
| surf2 = surf2->next; | |
| } | |
| while (surf->key > surf2->key); | |
| if (surf->key == surf2->key) | |
| { | |
| if (!surf->insubmodel) | |
| goto continue_search; | |
| fu = ((float) (edge->u - 0xFFFFF)) * (1.0 / 0x100000); | |
| newzi = (surf->d_ziorigin + (fv * surf->d_zistepv)) + (fu * surf->d_zistepu); | |
| newzibottom = newzi * 0.99; | |
| testzi = (surf2->d_ziorigin + (fv * surf2->d_zistepv)) + (fu * surf2->d_zistepu); | |
| if (newzibottom >= testzi) | |
| { | |
| goto gotposition; | |
| } | |
| newzitop = newzi * 1.01; | |
| if (newzitop >= testzi) | |
| { | |
| if (surf->d_zistepu >= surf2->d_zistepu) | |
| { | |
| goto gotposition; | |
| } | |
| } | |
| goto continue_search; | |
| } | |
| goto gotposition; | |
| newtop: | |
| iu = edge->u >> 20; | |
| if (iu > surf2->last_u) | |
| { | |
| span = span_p++; | |
| span->u = surf2->last_u; | |
| span->count = iu - span->u; | |
| span->v = current_iv; | |
| span->pnext = surf2->spans; | |
| surf2->spans = span; | |
| } | |
| surf->last_u = iu; | |
| gotposition: | |
| surf->next = surf2; | |
| surf->prev = surf2->prev; | |
| surf2->prev->next = surf; | |
| surf2->prev = surf; | |
| } | |
| } | |
| } | |
| static void R_GenerateSpans(void) | |
| { | |
| edge_t *edge; | |
| surf_t *surf; | |
| r_bmodelactive = 0; | |
| surfaces[1].next = (surfaces[1].prev = &surfaces[1]); | |
| surfaces[1].last_u = edge_head_u_shift20; | |
| for (edge = edge_head.next; edge != (&edge_tail); edge = edge->next) | |
| { | |
| if (edge->surfs[0]) | |
| { | |
| surf = &surfaces[edge->surfs[0]]; | |
| R_TrailingEdge(surf, edge); | |
| if (!edge->surfs[1]) | |
| continue; | |
| } | |
| R_LeadingEdge(edge); | |
| } | |
| R_CleanupSpan(); | |
| } | |
| static void R_GenerateSpansBackward(void) | |
| { | |
| edge_t *edge; | |
| r_bmodelactive = 0; | |
| surfaces[1].next = (surfaces[1].prev = &surfaces[1]); | |
| surfaces[1].last_u = edge_head_u_shift20; | |
| for (edge = edge_head.next; edge != (&edge_tail); edge = edge->next) | |
| { | |
| if (edge->surfs[0]) | |
| R_TrailingEdge(&surfaces[edge->surfs[0]], edge); | |
| if (edge->surfs[1]) | |
| R_LeadingEdgeBackwards(edge); | |
| } | |
| R_CleanupSpan(); | |
| } | |
| void R_ScanEdges(void) | |
| { | |
| int32_t iv; | |
| int32_t bottom; | |
| uint8_t basespans[(MAXSPANS * (sizeof(espan_t))) + CACHE_SIZE]; | |
| espan_t *basespan_p; | |
| surf_t *s; | |
| basespan_p = (espan_t *) (((((uintptr_t) basespans) + ((uintptr_t) CACHE_SIZE)) - 1) & (~(((uintptr_t) CACHE_SIZE) - 1))); | |
| max_span_p = &basespan_p[MAXSPANS - r_refdef.vrect.width]; | |
| span_p = basespan_p; | |
| edge_head.u = r_refdef.vrect.x << 20; | |
| edge_head_u_shift20 = edge_head.u >> 20; | |
| edge_head.u_step = 0; | |
| edge_head.prev = 0; | |
| edge_head.next = &edge_tail; | |
| edge_head.surfs[0] = 0; | |
| edge_head.surfs[1] = 1; | |
| edge_tail.u = (r_refdef.vrectright << 20) + 0xFFFFF; | |
| edge_tail_u_shift20 = edge_tail.u >> 20; | |
| edge_tail.u_step = 0; | |
| edge_tail.prev = &edge_head; | |
| edge_tail.next = &edge_aftertail; | |
| edge_tail.surfs[0] = 1; | |
| edge_tail.surfs[1] = 0; | |
| edge_aftertail.u = -1; | |
| edge_aftertail.u_step = 0; | |
| edge_aftertail.next = &edge_sentinel; | |
| edge_aftertail.prev = &edge_tail; | |
| edge_sentinel.u = 2000 << 24; | |
| edge_sentinel.prev = &edge_aftertail; | |
| bottom = r_refdef.vrectbottom - 1; | |
| for (iv = r_refdef.vrect.y; iv < bottom; iv++) | |
| { | |
| current_iv = iv; | |
| fv = (float) iv; | |
| surfaces[1].spanstate = 1; | |
| if (newedges[iv]) | |
| { | |
| R_InsertNewEdges(newedges[iv], edge_head.next); | |
| } | |
| (*pdrawfunc)(); | |
| if (span_p >= max_span_p) | |
| { | |
| VID_UnlockBuffer(); | |
| S_ExtraUpdate(); | |
| VID_LockBuffer(); | |
| if (r_drawculledpolys) | |
| { | |
| R_DrawCulledPolys(); | |
| } | |
| else | |
| { | |
| D_DrawSurfaces(); | |
| } | |
| for (s = &surfaces[1]; s < surface_p; s++) | |
| s->spans = 0; | |
| span_p = basespan_p; | |
| } | |
| if (removeedges[iv]) | |
| R_RemoveEdges(removeedges[iv]); | |
| if (edge_head.next != (&edge_tail)) | |
| R_StepActiveU(edge_head.next); | |
| } | |
| current_iv = iv; | |
| fv = (float) iv; | |
| surfaces[1].spanstate = 1; | |
| if (newedges[iv]) | |
| R_InsertNewEdges(newedges[iv], edge_head.next); | |
| (*pdrawfunc)(); | |
| if (r_drawculledpolys) | |
| R_DrawCulledPolys(); | |
| else | |
| D_DrawSurfaces(); | |
| } | |
| void R_RemoveEfrags(entity_t *ent) | |
| { | |
| efrag_t *ef; | |
| efrag_t *old; | |
| efrag_t *walk; | |
| efrag_t **prev; | |
| ef = ent->efrag; | |
| while (ef) | |
| { | |
| prev = &ef->leaf->efrags; | |
| while (1) | |
| { | |
| walk = *prev; | |
| if (!walk) | |
| break; | |
| if (walk == ef) | |
| { | |
| *prev = ef->leafnext; | |
| break; | |
| } | |
| else | |
| prev = &walk->leafnext; | |
| } | |
| old = ef; | |
| ef = ef->entnext; | |
| old->entnext = cl.free_efrags; | |
| cl.free_efrags = old; | |
| } | |
| ent->efrag = 0; | |
| } | |
| static void R_SplitEntityOnNode(mnode_t *node) | |
| { | |
| efrag_t *ef; | |
| mplane_t *splitplane; | |
| mleaf_t *leaf; | |
| int32_t sides; | |
| if (node->contents == CONTENTS_SOLID) | |
| { | |
| return; | |
| } | |
| if (node->contents < 0) | |
| { | |
| if (!r_pefragtopnode) | |
| r_pefragtopnode = node; | |
| leaf = (mleaf_t *) node; | |
| ef = cl.free_efrags; | |
| if (!ef) | |
| { | |
| Con_Printf("Too many efrags!\n"); | |
| return; | |
| } | |
| cl.free_efrags = cl.free_efrags->entnext; | |
| ef->entity = r_addent; | |
| *lastlink = ef; | |
| lastlink = &ef->entnext; | |
| ef->entnext = 0; | |
| ef->leaf = leaf; | |
| ef->leafnext = leaf->efrags; | |
| leaf->efrags = ef; | |
| return; | |
| } | |
| splitplane = node->plane; | |
| sides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane); | |
| if (sides == 3) | |
| { | |
| if (!r_pefragtopnode) | |
| r_pefragtopnode = node; | |
| } | |
| if (sides & 1) | |
| R_SplitEntityOnNode(node->children[0]); | |
| if (sides & 2) | |
| R_SplitEntityOnNode(node->children[1]); | |
| } | |
| void R_SplitEntityOnNode2(mnode_t *node) | |
| { | |
| mplane_t *splitplane; | |
| int32_t sides; | |
| if (node->visframe != r_visframecount) | |
| return; | |
| if (node->contents < 0) | |
| { | |
| if (node->contents != CONTENTS_SOLID) | |
| r_pefragtopnode = node; | |
| return; | |
| } | |
| splitplane = node->plane; | |
| sides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane); | |
| if (sides == 3) | |
| { | |
| r_pefragtopnode = node; | |
| return; | |
| } | |
| if (sides & 1) | |
| R_SplitEntityOnNode2(node->children[0]); | |
| else | |
| R_SplitEntityOnNode2(node->children[1]); | |
| } | |
| void R_AddEfrags(entity_t *ent) | |
| { | |
| model_t *entmodel; | |
| int32_t i; | |
| if (!ent->model) | |
| return; | |
| if (ent == cl_entities) | |
| return; | |
| r_addent = ent; | |
| lastlink = &ent->efrag; | |
| r_pefragtopnode = 0; | |
| entmodel = ent->model; | |
| for (i = 0; i < 3; i++) | |
| { | |
| r_emins[i] = ent->origin[i] + entmodel->mins[i]; | |
| r_emaxs[i] = ent->origin[i] + entmodel->maxs[i]; | |
| } | |
| R_SplitEntityOnNode(cl.worldmodel->nodes); | |
| ent->topnode = r_pefragtopnode; | |
| } | |
| void R_StoreEfrags(efrag_t **ppefrag) | |
| { | |
| entity_t *pent; | |
| model_t *clmodel; | |
| efrag_t *pefrag; | |
| while ((pefrag = *ppefrag) != 0) | |
| { | |
| pent = pefrag->entity; | |
| clmodel = pent->model; | |
| switch (clmodel->type) | |
| { | |
| case mod_alias: | |
| case mod_brush: | |
| case mod_sprite: | |
| pent = pefrag->entity; | |
| if ((pent->visframe != r_framecount) && (cl_numvisedicts < MAX_VISEDICTS)) | |
| { | |
| cl_visedicts[cl_numvisedicts++] = pent; | |
| pent->visframe = r_framecount; | |
| } | |
| ppefrag = &pefrag->leafnext; | |
| break; | |
| default: | |
| Sys_Error("R_StoreEfrags: Bad entity type %d\n", clmodel->type); | |
| } | |
| } | |
| } | |
| void R_AnimateLight(void) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| int32_t k; | |
| i = (int32_t) (cl.time * 10); | |
| for (j = 0; j < MAX_LIGHTSTYLES; j++) | |
| { | |
| if (!cl_lightstyle[j].length) | |
| { | |
| d_lightstylevalue[j] = 256; | |
| continue; | |
| } | |
| k = i % cl_lightstyle[j].length; | |
| k = cl_lightstyle[j].map[k] - 'a'; | |
| k = k * 22; | |
| d_lightstylevalue[j] = k; | |
| } | |
| } | |
| void R_MarkLights(dlight_t *light, int32_t bit, mnode_t *node) | |
| { | |
| mplane_t *splitplane; | |
| float dist; | |
| msurface_t *surf; | |
| int32_t i; | |
| if (node->contents < 0) | |
| return; | |
| splitplane = node->plane; | |
| dist = DotProduct(light->origin, splitplane->normal) - splitplane->dist; | |
| if (dist > light->radius) | |
| { | |
| R_MarkLights(light, bit, node->children[0]); | |
| return; | |
| } | |
| if (dist < (-light->radius)) | |
| { | |
| R_MarkLights(light, bit, node->children[1]); | |
| return; | |
| } | |
| surf = cl.worldmodel->surfaces + node->firstsurface; | |
| for (i = 0; i < node->numsurfaces; i++, surf++) | |
| { | |
| if (surf->dlightframe != r_dlightframecount) | |
| { | |
| surf->dlightbits = 0; | |
| surf->dlightframe = r_dlightframecount; | |
| } | |
| surf->dlightbits |= bit; | |
| } | |
| R_MarkLights(light, bit, node->children[0]); | |
| R_MarkLights(light, bit, node->children[1]); | |
| } | |
| void R_PushDlights(void) | |
| { | |
| int32_t i; | |
| dlight_t *l; | |
| r_dlightframecount = r_framecount + 1; | |
| l = cl_dlights; | |
| for (i = 0; i < MAX_DLIGHTS; i++, l++) | |
| { | |
| if ((l->die < cl.time) || (!l->radius)) | |
| continue; | |
| R_MarkLights(l, 1 << i, cl.worldmodel->nodes); | |
| } | |
| } | |
| static int32_t RecursiveLightPoint(mnode_t *node, vec3_t start, vec3_t end) | |
| { | |
| int32_t r; | |
| float front; | |
| float back; | |
| float frac; | |
| int32_t side; | |
| mplane_t *plane; | |
| vec3_t mid; | |
| msurface_t *surf; | |
| int32_t s; | |
| int32_t t; | |
| int32_t ds; | |
| int32_t dt; | |
| int32_t i; | |
| mtexinfo_t *tex; | |
| uint8_t *lightmap; | |
| uint32_t scale; | |
| int32_t maps; | |
| if (node->contents < 0) | |
| return -1; | |
| plane = node->plane; | |
| front = DotProduct(start, plane->normal) - plane->dist; | |
| back = DotProduct(end, plane->normal) - plane->dist; | |
| side = front < 0; | |
| if ((back < 0) == side) | |
| return RecursiveLightPoint(node->children[side], start, end); | |
| frac = front / (front - back); | |
| mid[0] = start[0] + ((end[0] - start[0]) * frac); | |
| mid[1] = start[1] + ((end[1] - start[1]) * frac); | |
| mid[2] = start[2] + ((end[2] - start[2]) * frac); | |
| r = RecursiveLightPoint(node->children[side], start, mid); | |
| if (r >= 0) | |
| return r; | |
| if ((back < 0) == side) | |
| return -1; | |
| surf = cl.worldmodel->surfaces + node->firstsurface; | |
| for (i = 0; i < node->numsurfaces; i++, surf++) | |
| { | |
| if (surf->flags & SURF_DRAWTILED) | |
| continue; | |
| tex = surf->texinfo; | |
| s = DotProduct(mid, tex->vecs[0]) + tex->vecs[0][3]; | |
| t = DotProduct(mid, tex->vecs[1]) + tex->vecs[1][3]; | |
| ; | |
| if ((s < surf->texturemins[0]) || (t < surf->texturemins[1])) | |
| continue; | |
| ds = s - surf->texturemins[0]; | |
| dt = t - surf->texturemins[1]; | |
| if ((ds > surf->extents[0]) || (dt > surf->extents[1])) | |
| continue; | |
| if (!surf->samples) | |
| return 0; | |
| ds >>= 4; | |
| dt >>= 4; | |
| lightmap = surf->samples; | |
| r = 0; | |
| if (lightmap) | |
| { | |
| lightmap += (dt * ((surf->extents[0] >> 4) + 1)) + ds; | |
| for (maps = 0; (maps < MAXLIGHTMAPS) && (surf->styles[maps] != 255); maps++) | |
| { | |
| scale = d_lightstylevalue[surf->styles[maps]]; | |
| r += (*lightmap) * scale; | |
| lightmap += ((surf->extents[0] >> 4) + 1) * ((surf->extents[1] >> 4) + 1); | |
| } | |
| r >>= 8; | |
| } | |
| return r; | |
| } | |
| return RecursiveLightPoint(node->children[!side], mid, end); | |
| } | |
| int32_t R_LightPoint(vec3_t p) | |
| { | |
| vec3_t end; | |
| int32_t r; | |
| if (!cl.worldmodel->lightdata) | |
| return 255; | |
| end[0] = p[0]; | |
| end[1] = p[1]; | |
| end[2] = p[2] - 2048; | |
| r = RecursiveLightPoint(cl.worldmodel->nodes, p, end); | |
| if (r == (-1)) | |
| r = 0; | |
| if (r < r_refdef.ambientlight) | |
| r = r_refdef.ambientlight; | |
| return r; | |
| } | |
| void R_InitTextures(void) | |
| { | |
| int32_t x; | |
| int32_t y; | |
| int32_t m; | |
| uint8_t *dest; | |
| r_notexture_mip = Hunk_AllocName(((((sizeof(texture_t)) + (16 * 16)) + (8 * 8)) + (4 * 4)) + (2 * 2), "notexture"); | |
| r_notexture_mip->width = (r_notexture_mip->height = 16); | |
| r_notexture_mip->offsets[0] = sizeof(texture_t); | |
| r_notexture_mip->offsets[1] = r_notexture_mip->offsets[0] + (16 * 16); | |
| r_notexture_mip->offsets[2] = r_notexture_mip->offsets[1] + (8 * 8); | |
| r_notexture_mip->offsets[3] = r_notexture_mip->offsets[2] + (4 * 4); | |
| for (m = 0; m < 4; m++) | |
| { | |
| dest = ((uint8_t *) r_notexture_mip) + r_notexture_mip->offsets[m]; | |
| for (y = 0; y < (16 >> m); y++) | |
| for (x = 0; x < (16 >> m); x++) | |
| { | |
| if ((y < (8 >> m)) ^ (x < (8 >> m))) | |
| *(dest++) = 0; | |
| else | |
| *(dest++) = 0xff; | |
| } | |
| } | |
| } | |
| void R_Init(void) | |
| { | |
| int32_t dummy; | |
| r_stack_start = (uint8_t *) (&dummy); | |
| R_InitTurb(); | |
| Cmd_AddCommand("timerefresh", R_TimeRefresh_f); | |
| Cmd_AddCommand("pointfile", R_ReadPointFile_f); | |
| Cvar_RegisterVariable(&r_draworder); | |
| Cvar_RegisterVariable(&r_speeds); | |
| Cvar_RegisterVariable(&r_timegraph); | |
| Cvar_RegisterVariable(&r_graphheight); | |
| Cvar_RegisterVariable(&r_drawflat); | |
| Cvar_RegisterVariable(&r_ambient); | |
| Cvar_RegisterVariable(&r_clearcolor); | |
| Cvar_RegisterVariable(&r_waterwarp); | |
| Cvar_RegisterVariable(&r_fullbright); | |
| Cvar_RegisterVariable(&r_drawentities); | |
| Cvar_RegisterVariable(&r_drawviewmodel); | |
| Cvar_RegisterVariable(&r_aliasstats); | |
| Cvar_RegisterVariable(&r_dspeeds); | |
| Cvar_RegisterVariable(&r_reportsurfout); | |
| Cvar_RegisterVariable(&r_maxsurfs); | |
| Cvar_RegisterVariable(&r_numsurfs); | |
| Cvar_RegisterVariable(&r_reportedgeout); | |
| Cvar_RegisterVariable(&r_maxedges); | |
| Cvar_RegisterVariable(&r_numedges); | |
| Cvar_RegisterVariable(&r_aliastransbase); | |
| Cvar_RegisterVariable(&r_aliastransadj); | |
| Cvar_SetValue("r_maxedges", (float) NUMSTACKEDGES); | |
| Cvar_SetValue("r_maxsurfs", (float) NUMSTACKSURFACES); | |
| view_clipplanes[0].leftedge = 1; | |
| view_clipplanes[1].rightedge = 1; | |
| view_clipplanes[1].leftedge = (view_clipplanes[2].leftedge = (view_clipplanes[3].leftedge = 0)); | |
| view_clipplanes[0].rightedge = (view_clipplanes[2].rightedge = (view_clipplanes[3].rightedge = 0)); | |
| r_refdef.xOrigin = XCENTERING; | |
| r_refdef.yOrigin = YCENTERING; | |
| R_InitParticles(); | |
| D_Init(); | |
| } | |
| void R_NewMap(void) | |
| { | |
| int32_t i; | |
| for (i = 0; i < cl.worldmodel->numleafs; i++) | |
| cl.worldmodel->leafs[i].efrags = 0; | |
| r_viewleaf = 0; | |
| R_ClearParticles(); | |
| r_cnumsurfs = r_maxsurfs.value; | |
| if (r_cnumsurfs <= MINSURFACES) | |
| r_cnumsurfs = MINSURFACES; | |
| if (r_cnumsurfs > NUMSTACKSURFACES) | |
| { | |
| surfaces = Hunk_AllocName(r_cnumsurfs * (sizeof(surf_t)), "surfaces"); | |
| surface_p = surfaces; | |
| surf_max = &surfaces[r_cnumsurfs]; | |
| r_surfsonstack = 0; | |
| surfaces--; | |
| R_SurfacePatch(); | |
| } | |
| else | |
| { | |
| r_surfsonstack = 1; | |
| } | |
| r_maxedgesseen = 0; | |
| r_maxsurfsseen = 0; | |
| r_numallocatededges = r_maxedges.value; | |
| if (r_numallocatededges < MINEDGES) | |
| r_numallocatededges = MINEDGES; | |
| if (r_numallocatededges <= NUMSTACKEDGES) | |
| { | |
| auxedges = 0; | |
| } | |
| else | |
| { | |
| auxedges = Hunk_AllocName(r_numallocatededges * (sizeof(edge_t)), "edges"); | |
| } | |
| r_dowarpold = 0; | |
| r_viewchanged = 0; | |
| } | |
| void R_SetVrect(vrect_t *pvrectin, vrect_t *pvrect, int32_t lineadj) | |
| { | |
| int32_t h; | |
| float size; | |
| size = (scr_viewsize.value > 100) ? (100) : (scr_viewsize.value); | |
| if (cl.intermission) | |
| { | |
| size = 100; | |
| lineadj = 0; | |
| } | |
| size /= 100; | |
| h = pvrectin->height - lineadj; | |
| pvrect->width = pvrectin->width * size; | |
| if (pvrect->width < 96) | |
| { | |
| size = 96.0 / pvrectin->width; | |
| pvrect->width = 96; | |
| } | |
| pvrect->width &= ~7; | |
| pvrect->height = pvrectin->height * size; | |
| if (pvrect->height > (pvrectin->height - lineadj)) | |
| pvrect->height = pvrectin->height - lineadj; | |
| pvrect->height &= ~1; | |
| pvrect->x = (pvrectin->width - pvrect->width) / 2; | |
| pvrect->y = (h - pvrect->height) / 2; | |
| { | |
| if (lcd_x.value) | |
| { | |
| pvrect->y >>= 1; | |
| pvrect->height >>= 1; | |
| } | |
| } | |
| } | |
| void R_ViewChanged(vrect_t *pvrect, int32_t lineadj, float aspect) | |
| { | |
| int32_t i; | |
| float res_scale; | |
| r_viewchanged = 1; | |
| R_SetVrect(pvrect, &r_refdef.vrect, lineadj); | |
| r_refdef.horizontalFieldOfView = 2.0 * tan((r_refdef.fov_x / 360) * M_PI); | |
| r_refdef.fvrectx = (float) r_refdef.vrect.x; | |
| r_refdef.fvrectx_adj = ((float) r_refdef.vrect.x) - 0.5; | |
| r_refdef.vrect_x_adj_shift20 = ((r_refdef.vrect.x << 20) + (1 << 19)) - 1; | |
| r_refdef.fvrecty = (float) r_refdef.vrect.y; | |
| r_refdef.fvrecty_adj = ((float) r_refdef.vrect.y) - 0.5; | |
| r_refdef.vrectright = r_refdef.vrect.x + r_refdef.vrect.width; | |
| r_refdef.vrectright_adj_shift20 = ((r_refdef.vrectright << 20) + (1 << 19)) - 1; | |
| r_refdef.fvrectright = (float) r_refdef.vrectright; | |
| r_refdef.fvrectright_adj = ((float) r_refdef.vrectright) - 0.5; | |
| r_refdef.vrectrightedge = ((float) r_refdef.vrectright) - 0.99; | |
| r_refdef.vrectbottom = r_refdef.vrect.y + r_refdef.vrect.height; | |
| r_refdef.fvrectbottom = (float) r_refdef.vrectbottom; | |
| r_refdef.fvrectbottom_adj = ((float) r_refdef.vrectbottom) - 0.5; | |
| r_refdef.aliasvrect.x = (int32_t) (r_refdef.vrect.x * r_aliasuvscale); | |
| r_refdef.aliasvrect.y = (int32_t) (r_refdef.vrect.y * r_aliasuvscale); | |
| r_refdef.aliasvrect.width = (int32_t) (r_refdef.vrect.width * r_aliasuvscale); | |
| r_refdef.aliasvrect.height = (int32_t) (r_refdef.vrect.height * r_aliasuvscale); | |
| r_refdef.aliasvrectright = r_refdef.aliasvrect.x + r_refdef.aliasvrect.width; | |
| r_refdef.aliasvrectbottom = r_refdef.aliasvrect.y + r_refdef.aliasvrect.height; | |
| pixelAspect = aspect; | |
| xOrigin = r_refdef.xOrigin; | |
| yOrigin = r_refdef.yOrigin; | |
| screenAspect = (r_refdef.vrect.width * pixelAspect) / r_refdef.vrect.height; | |
| verticalFieldOfView = r_refdef.horizontalFieldOfView / screenAspect; | |
| xcenter = ((((float) r_refdef.vrect.width) * XCENTERING) + r_refdef.vrect.x) - 0.5; | |
| aliasxcenter = xcenter * r_aliasuvscale; | |
| ycenter = ((((float) r_refdef.vrect.height) * YCENTERING) + r_refdef.vrect.y) - 0.5; | |
| aliasycenter = ycenter * r_aliasuvscale; | |
| xscale = r_refdef.vrect.width / r_refdef.horizontalFieldOfView; | |
| aliasxscale = xscale * r_aliasuvscale; | |
| xscaleinv = 1.0 / xscale; | |
| yscale = xscale * pixelAspect; | |
| aliasyscale = yscale * r_aliasuvscale; | |
| yscaleinv = 1.0 / yscale; | |
| xscaleshrink = (r_refdef.vrect.width - 6) / r_refdef.horizontalFieldOfView; | |
| yscaleshrink = xscaleshrink * pixelAspect; | |
| screenedge[0].normal[0] = (-1.0) / (xOrigin * r_refdef.horizontalFieldOfView); | |
| screenedge[0].normal[1] = 0; | |
| screenedge[0].normal[2] = 1; | |
| screenedge[0].type = PLANE_ANYZ; | |
| screenedge[1].normal[0] = 1.0 / ((1.0 - xOrigin) * r_refdef.horizontalFieldOfView); | |
| screenedge[1].normal[1] = 0; | |
| screenedge[1].normal[2] = 1; | |
| screenedge[1].type = PLANE_ANYZ; | |
| screenedge[2].normal[0] = 0; | |
| screenedge[2].normal[1] = (-1.0) / (yOrigin * verticalFieldOfView); | |
| screenedge[2].normal[2] = 1; | |
| screenedge[2].type = PLANE_ANYZ; | |
| screenedge[3].normal[0] = 0; | |
| screenedge[3].normal[1] = 1.0 / ((1.0 - yOrigin) * verticalFieldOfView); | |
| screenedge[3].normal[2] = 1; | |
| screenedge[3].type = PLANE_ANYZ; | |
| for (i = 0; i < 4; i++) | |
| VectorNormalize(screenedge[i].normal); | |
| res_scale = sqrt(((double) (r_refdef.vrect.width * r_refdef.vrect.height)) / (320.0 * 152.0)) * (2.0 / r_refdef.horizontalFieldOfView); | |
| r_aliastransition = r_aliastransbase.value * res_scale; | |
| r_resfudge = r_aliastransadj.value * res_scale; | |
| if (scr_fov.value <= 90.0) | |
| r_fov_greater_than_90 = 0; | |
| else | |
| r_fov_greater_than_90 = 1; | |
| D_ViewChanged(); | |
| } | |
| void R_MarkLeaves(void) | |
| { | |
| uint8_t *vis; | |
| mnode_t *node; | |
| int32_t i; | |
| if (r_oldviewleaf == r_viewleaf) | |
| return; | |
| r_visframecount++; | |
| r_oldviewleaf = r_viewleaf; | |
| vis = Mod_LeafPVS(r_viewleaf, cl.worldmodel); | |
| for (i = 0; i < cl.worldmodel->numleafs; i++) | |
| { | |
| if (vis[i >> 3] & (1 << (i & 7))) | |
| { | |
| node = (mnode_t *) (&cl.worldmodel->leafs[i + 1]); | |
| do | |
| { | |
| if (node->visframe == r_visframecount) | |
| break; | |
| node->visframe = r_visframecount; | |
| node = node->parent; | |
| } | |
| while (node); | |
| } | |
| } | |
| } | |
| void R_DrawEntitiesOnList(void) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| int32_t lnum; | |
| alight_t lighting; | |
| float lightvec[3] = {-1, 0, 0}; | |
| vec3_t dist; | |
| float add; | |
| if (!r_drawentities.value) | |
| return; | |
| for (i = 0; i < cl_numvisedicts; i++) | |
| { | |
| currententity = cl_visedicts[i]; | |
| if (currententity == (&cl_entities[cl.viewentity])) | |
| continue; | |
| switch (currententity->model->type) | |
| { | |
| case mod_sprite: | |
| VectorCopy(currententity->origin, r_entorigin); | |
| VectorSubtract(r_origin, r_entorigin, modelorg); | |
| R_DrawSprite(); | |
| break; | |
| case mod_alias: | |
| VectorCopy(currententity->origin, r_entorigin); | |
| VectorSubtract(r_origin, r_entorigin, modelorg); | |
| if (R_AliasCheckBBox()) | |
| { | |
| j = R_LightPoint(currententity->origin); | |
| lighting.ambientlight = j; | |
| lighting.shadelight = j; | |
| lighting.plightvec = lightvec; | |
| for (lnum = 0; lnum < MAX_DLIGHTS; lnum++) | |
| { | |
| if (cl_dlights[lnum].die >= cl.time) | |
| { | |
| VectorSubtract(currententity->origin, cl_dlights[lnum].origin, dist); | |
| add = cl_dlights[lnum].radius - Length(dist); | |
| if (add > 0) | |
| lighting.ambientlight += add; | |
| } | |
| } | |
| if (lighting.ambientlight > 128) | |
| lighting.ambientlight = 128; | |
| if ((lighting.ambientlight + lighting.shadelight) > 192) | |
| lighting.shadelight = 192 - lighting.ambientlight; | |
| R_AliasDrawModel(&lighting); | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| } | |
| void R_DrawViewModel(void) | |
| { | |
| float lightvec[3] = {-1, 0, 0}; | |
| int32_t j; | |
| int32_t lnum; | |
| vec3_t dist; | |
| float add; | |
| dlight_t *dl; | |
| if ((!r_drawviewmodel.value) || r_fov_greater_than_90) | |
| return; | |
| if (cl.items & IT_INVISIBILITY) | |
| return; | |
| if (cl.stats[STAT_HEALTH] <= 0) | |
| return; | |
| currententity = &cl.viewent; | |
| if (!currententity->model) | |
| return; | |
| VectorCopy(currententity->origin, r_entorigin); | |
| VectorSubtract(r_origin, r_entorigin, modelorg); | |
| VectorCopy(vup, viewlightvec); | |
| VectorInverse(viewlightvec); | |
| j = R_LightPoint(currententity->origin); | |
| if (j < 24) | |
| j = 24; | |
| r_viewlighting.ambientlight = j; | |
| r_viewlighting.shadelight = j; | |
| for (lnum = 0; lnum < MAX_DLIGHTS; lnum++) | |
| { | |
| dl = &cl_dlights[lnum]; | |
| if (!dl->radius) | |
| continue; | |
| if (!dl->radius) | |
| continue; | |
| if (dl->die < cl.time) | |
| continue; | |
| VectorSubtract(currententity->origin, dl->origin, dist); | |
| add = dl->radius - Length(dist); | |
| if (add > 0) | |
| r_viewlighting.ambientlight += add; | |
| } | |
| if (r_viewlighting.ambientlight > 128) | |
| r_viewlighting.ambientlight = 128; | |
| if ((r_viewlighting.ambientlight + r_viewlighting.shadelight) > 192) | |
| r_viewlighting.shadelight = 192 - r_viewlighting.ambientlight; | |
| r_viewlighting.plightvec = lightvec; | |
| R_AliasDrawModel(&r_viewlighting); | |
| } | |
| int32_t R_BmodelCheckBBox(model_t *clmodel, float *minmaxs) | |
| { | |
| int32_t i; | |
| int32_t *pindex; | |
| int32_t clipflags; | |
| vec3_t acceptpt; | |
| vec3_t rejectpt; | |
| double d; | |
| clipflags = 0; | |
| if ((currententity->angles[0] || currententity->angles[1]) || currententity->angles[2]) | |
| { | |
| for (i = 0; i < 4; i++) | |
| { | |
| d = DotProduct(currententity->origin, view_clipplanes[i].normal); | |
| d -= view_clipplanes[i].dist; | |
| if (d <= (-clmodel->radius)) | |
| return BMODEL_FULLY_CLIPPED; | |
| if (d <= clmodel->radius) | |
| clipflags |= 1 << i; | |
| } | |
| } | |
| else | |
| { | |
| for (i = 0; i < 4; i++) | |
| { | |
| pindex = pfrustum_indexes[i]; | |
| rejectpt[0] = minmaxs[pindex[0]]; | |
| rejectpt[1] = minmaxs[pindex[1]]; | |
| rejectpt[2] = minmaxs[pindex[2]]; | |
| d = DotProduct(rejectpt, view_clipplanes[i].normal); | |
| d -= view_clipplanes[i].dist; | |
| if (d <= 0) | |
| return BMODEL_FULLY_CLIPPED; | |
| acceptpt[0] = minmaxs[pindex[3 + 0]]; | |
| acceptpt[1] = minmaxs[pindex[3 + 1]]; | |
| acceptpt[2] = minmaxs[pindex[3 + 2]]; | |
| d = DotProduct(acceptpt, view_clipplanes[i].normal); | |
| d -= view_clipplanes[i].dist; | |
| if (d <= 0) | |
| clipflags |= 1 << i; | |
| } | |
| } | |
| return clipflags; | |
| } | |
| void R_DrawBEntitiesOnList(void) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| int32_t k; | |
| int32_t clipflags; | |
| vec3_t oldorigin; | |
| model_t *clmodel; | |
| float minmaxs[6]; | |
| if (!r_drawentities.value) | |
| return; | |
| VectorCopy(modelorg, oldorigin); | |
| insubmodel = 1; | |
| r_dlightframecount = r_framecount; | |
| for (i = 0; i < cl_numvisedicts; i++) | |
| { | |
| currententity = cl_visedicts[i]; | |
| switch (currententity->model->type) | |
| { | |
| case mod_brush: | |
| clmodel = currententity->model; | |
| for (j = 0; j < 3; j++) | |
| { | |
| minmaxs[j] = currententity->origin[j] + clmodel->mins[j]; | |
| minmaxs[3 + j] = currententity->origin[j] + clmodel->maxs[j]; | |
| } | |
| clipflags = R_BmodelCheckBBox(clmodel, minmaxs); | |
| if (clipflags != BMODEL_FULLY_CLIPPED) | |
| { | |
| VectorCopy(currententity->origin, r_entorigin); | |
| VectorSubtract(r_origin, r_entorigin, modelorg); | |
| VectorCopy(modelorg, r_worldmodelorg); | |
| r_pcurrentvertbase = clmodel->vertexes; | |
| R_RotateBmodel(); | |
| if (clmodel->firstmodelsurface != 0) | |
| { | |
| for (k = 0; k < MAX_DLIGHTS; k++) | |
| { | |
| if ((cl_dlights[k].die < cl.time) || (!cl_dlights[k].radius)) | |
| { | |
| continue; | |
| } | |
| R_MarkLights(&cl_dlights[k], 1 << k, clmodel->nodes + clmodel->hulls[0].firstclipnode); | |
| } | |
| } | |
| if (r_drawpolys | r_drawculledpolys) | |
| { | |
| R_ZDrawSubmodelPolys(clmodel); | |
| } | |
| else | |
| { | |
| r_pefragtopnode = 0; | |
| for (j = 0; j < 3; j++) | |
| { | |
| r_emins[j] = minmaxs[j]; | |
| r_emaxs[j] = minmaxs[3 + j]; | |
| } | |
| R_SplitEntityOnNode2(cl.worldmodel->nodes); | |
| if (r_pefragtopnode) | |
| { | |
| currententity->topnode = r_pefragtopnode; | |
| if (r_pefragtopnode->contents >= 0) | |
| { | |
| r_clipflags = clipflags; | |
| R_DrawSolidClippedSubmodelPolygons(clmodel); | |
| } | |
| else | |
| { | |
| R_DrawSubmodelPolygons(clmodel, clipflags); | |
| } | |
| currententity->topnode = 0; | |
| } | |
| } | |
| VectorCopy(base_vpn, vpn); | |
| VectorCopy(base_vup, vup); | |
| VectorCopy(base_vright, vright); | |
| VectorCopy(base_modelorg, modelorg); | |
| VectorCopy(oldorigin, modelorg); | |
| R_TransformFrustum(); | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| insubmodel = 0; | |
| } | |
| void R_EdgeDrawing(void) | |
| { | |
| edge_t ledges[(NUMSTACKEDGES + ((CACHE_SIZE - 1) / (sizeof(edge_t)))) + 1]; | |
| surf_t lsurfs[(NUMSTACKSURFACES + ((CACHE_SIZE - 1) / (sizeof(surf_t)))) + 1]; | |
| if (auxedges) | |
| { | |
| r_edges = auxedges; | |
| } | |
| else | |
| { | |
| r_edges = (edge_t *) ALIGN_PTR(&ledges[0], CACHE_SIZE); | |
| } | |
| if (r_surfsonstack) | |
| { | |
| surfaces = (surf_t *) ALIGN_PTR(&lsurfs[0], CACHE_SIZE); | |
| surf_max = &surfaces[r_cnumsurfs]; | |
| surfaces--; | |
| R_SurfacePatch(); | |
| } | |
| R_BeginEdgeFrame(); | |
| if (r_dspeeds.value) | |
| { | |
| rw_time1 = Sys_FloatTime(); | |
| } | |
| R_RenderWorld(); | |
| if (r_drawculledpolys) | |
| R_ScanEdges(); | |
| D_TurnZOn(); | |
| if (r_dspeeds.value) | |
| { | |
| rw_time2 = Sys_FloatTime(); | |
| db_time1 = rw_time2; | |
| } | |
| R_DrawBEntitiesOnList(); | |
| if (r_dspeeds.value) | |
| { | |
| db_time2 = Sys_FloatTime(); | |
| se_time1 = db_time2; | |
| } | |
| if (!r_dspeeds.value) | |
| { | |
| VID_UnlockBuffer(); | |
| S_ExtraUpdate(); | |
| VID_LockBuffer(); | |
| } | |
| if (!(r_drawpolys | r_drawculledpolys)) | |
| R_ScanEdges(); | |
| } | |
| void R_RenderView_(void) | |
| { | |
| uint8_t warpbuffer[WARP_WIDTH * WARP_HEIGHT]; | |
| r_warpbuffer = warpbuffer; | |
| if ((r_timegraph.value || r_speeds.value) || r_dspeeds.value) | |
| r_time1 = Sys_FloatTime(); | |
| R_SetupFrame(); | |
| R_MarkLeaves(); | |
| Sys_LowFPPrecision(); | |
| if ((!cl_entities[0].model) || (!cl.worldmodel)) | |
| Sys_Error("R_RenderView: NULL worldmodel"); | |
| if (!r_dspeeds.value) | |
| { | |
| VID_UnlockBuffer(); | |
| S_ExtraUpdate(); | |
| VID_LockBuffer(); | |
| } | |
| R_EdgeDrawing(); | |
| if (!r_dspeeds.value) | |
| { | |
| VID_UnlockBuffer(); | |
| S_ExtraUpdate(); | |
| VID_LockBuffer(); | |
| } | |
| if (r_dspeeds.value) | |
| { | |
| se_time2 = Sys_FloatTime(); | |
| de_time1 = se_time2; | |
| } | |
| R_DrawEntitiesOnList(); | |
| if (r_dspeeds.value) | |
| { | |
| de_time2 = Sys_FloatTime(); | |
| dv_time1 = de_time2; | |
| } | |
| R_DrawViewModel(); | |
| if (r_dspeeds.value) | |
| { | |
| dv_time2 = Sys_FloatTime(); | |
| dp_time1 = Sys_FloatTime(); | |
| } | |
| R_DrawParticles(); | |
| if (r_dspeeds.value) | |
| dp_time2 = Sys_FloatTime(); | |
| if (r_dowarp) | |
| D_WarpScreen(); | |
| V_SetContentsColor(r_viewleaf->contents); | |
| if (r_timegraph.value) | |
| R_TimeGraph(); | |
| if (r_aliasstats.value) | |
| R_PrintAliasStats(); | |
| if (r_speeds.value) | |
| R_PrintTimes(); | |
| if (r_dspeeds.value) | |
| R_PrintDSpeeds(); | |
| if (r_reportsurfout.value && r_outofsurfaces) | |
| Con_Printf("Short %d surfaces\n", r_outofsurfaces); | |
| if (r_reportedgeout.value && r_outofedges) | |
| Con_Printf("Short roughly %d edges\n", (r_outofedges * 2) / 3); | |
| Sys_HighFPPrecision(); | |
| } | |
| void R_RenderView(void) | |
| { | |
| int32_t dummy; | |
| ptrdiff_t delta = ((uint8_t *) (&dummy)) - r_stack_start; | |
| if ((delta < (-10000)) || (delta > 10000)) | |
| Sys_Error("R_RenderView: called without enough stack"); | |
| if (Hunk_LowMark() & 3) | |
| Sys_Error("Hunk is misaligned"); | |
| if (((uintptr_t) (&dummy)) & 3u) | |
| Sys_Error("Stack is misaligned"); | |
| if (((uintptr_t) (&r_warpbuffer)) & 3u) | |
| Sys_Error("Globals are misaligned"); | |
| R_RenderView_(); | |
| } | |
| void R_InitTurb(void) | |
| { | |
| int32_t i; | |
| for (i = 0; i < SIN_BUFFER_SIZE; i++) | |
| { | |
| sintable[i] = AMP + (sin(((i * 3.14159) * 2) / CYCLE) * AMP); | |
| intsintable[i] = AMP2 + (sin(((i * 3.14159) * 2) / CYCLE) * AMP2); | |
| } | |
| } | |
| void R_CheckVariables(void) | |
| { | |
| static float oldbright; | |
| if (r_fullbright.value != oldbright) | |
| { | |
| oldbright = r_fullbright.value; | |
| D_FlushCaches(); | |
| } | |
| } | |
| void Show(void) | |
| { | |
| vrect_t vr; | |
| vr.x = (vr.y = 0); | |
| vr.width = vid.width; | |
| vr.height = vid.height; | |
| vr.pnext = 0; | |
| VID_Update(&vr); | |
| } | |
| void R_TimeRefresh_f(void) | |
| { | |
| int32_t i; | |
| float start; | |
| float stop; | |
| float time; | |
| int32_t startangle; | |
| vrect_t vr; | |
| startangle = r_refdef.viewangles[1]; | |
| start = Sys_FloatTime(); | |
| for (i = 0; i < 128; i++) | |
| { | |
| r_refdef.viewangles[1] = (i / 128.0) * 360.0; | |
| VID_LockBuffer(); | |
| R_RenderView(); | |
| VID_UnlockBuffer(); | |
| vr.x = r_refdef.vrect.x; | |
| vr.y = r_refdef.vrect.y; | |
| vr.width = r_refdef.vrect.width; | |
| vr.height = r_refdef.vrect.height; | |
| vr.pnext = 0; | |
| VID_Update(&vr); | |
| } | |
| stop = Sys_FloatTime(); | |
| time = stop - start; | |
| Con_Printf("%f seconds (%f fps)\n", time, 128 / time); | |
| r_refdef.viewangles[1] = startangle; | |
| } | |
| void R_LineGraph(int32_t x, int32_t y, int32_t h) | |
| { | |
| int32_t i; | |
| uint8_t *dest; | |
| int32_t s; | |
| x += r_refdef.vrect.x; | |
| y += r_refdef.vrect.y; | |
| dest = (vid.buffer + (vid.rowbytes * y)) + x; | |
| s = r_graphheight.value; | |
| if (h > s) | |
| h = s; | |
| for (i = 0; i < h; i++, dest -= vid.rowbytes * 2) | |
| { | |
| dest[0] = 0xff; | |
| *(dest - vid.rowbytes) = 0x30; | |
| } | |
| for (; i < s; i++, dest -= vid.rowbytes * 2) | |
| { | |
| dest[0] = 0x30; | |
| *(dest - vid.rowbytes) = 0x30; | |
| } | |
| } | |
| void R_TimeGraph(void) | |
| { | |
| static int32_t timex; | |
| int32_t a; | |
| float r_time2; | |
| static uint8_t r_timings[MAX_TIMINGS]; | |
| int32_t x; | |
| r_time2 = Sys_FloatTime(); | |
| a = (r_time2 - r_time1) / 0.01; | |
| r_timings[timex] = a; | |
| a = timex; | |
| if (r_refdef.vrect.width <= MAX_TIMINGS) | |
| x = r_refdef.vrect.width - 1; | |
| else | |
| x = r_refdef.vrect.width - ((r_refdef.vrect.width - MAX_TIMINGS) / 2); | |
| do | |
| { | |
| R_LineGraph(x, r_refdef.vrect.height - 2, r_timings[a]); | |
| if (x == 0) | |
| break; | |
| x--; | |
| a--; | |
| if (a == (-1)) | |
| a = MAX_TIMINGS - 1; | |
| } | |
| while (a != timex); | |
| timex = (timex + 1) % MAX_TIMINGS; | |
| } | |
| void R_PrintTimes(void) | |
| { | |
| float r_time2; | |
| float ms; | |
| r_time2 = Sys_FloatTime(); | |
| ms = 1000 * (r_time2 - r_time1); | |
| Con_Printf("%5.1f ms %3i/%3i/%3i poly %3i surf\n", ms, c_faceclip, r_polycount, r_drawnpolycount, c_surf); | |
| c_surf = 0; | |
| } | |
| void R_PrintDSpeeds(void) | |
| { | |
| float ms; | |
| float dp_time; | |
| float r_time2; | |
| float rw_time; | |
| float db_time; | |
| float se_time; | |
| float de_time; | |
| float dv_time; | |
| r_time2 = Sys_FloatTime(); | |
| dp_time = (dp_time2 - dp_time1) * 1000; | |
| rw_time = (rw_time2 - rw_time1) * 1000; | |
| db_time = (db_time2 - db_time1) * 1000; | |
| se_time = (se_time2 - se_time1) * 1000; | |
| de_time = (de_time2 - de_time1) * 1000; | |
| dv_time = (dv_time2 - dv_time1) * 1000; | |
| ms = (r_time2 - r_time1) * 1000; | |
| Con_Printf("%3i %4.1fp %3iw %4.1fb %3is %4.1fe %4.1fv\n", (int32_t) ms, dp_time, (int32_t) rw_time, db_time, (int32_t) se_time, de_time, dv_time); | |
| } | |
| void R_PrintAliasStats(void) | |
| { | |
| Con_Printf("%3i polygon model drawn\n", r_amodels_drawn); | |
| } | |
| void WarpPalette(void) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| uint8_t newpalette[768]; | |
| int32_t basecolor[3]; | |
| basecolor[0] = 130; | |
| basecolor[1] = 80; | |
| basecolor[2] = 50; | |
| for (i = 0; i < 256; i++) | |
| { | |
| for (j = 0; j < 3; j++) | |
| { | |
| newpalette[(i * 3) + j] = (host_basepal[(i * 3) + j] + basecolor[j]) / 2; | |
| } | |
| } | |
| VID_ShiftPalette(newpalette); | |
| } | |
| void R_TransformFrustum(void) | |
| { | |
| int32_t i; | |
| vec3_t v; | |
| vec3_t v2; | |
| for (i = 0; i < 4; i++) | |
| { | |
| v[0] = screenedge[i].normal[2]; | |
| v[1] = -screenedge[i].normal[0]; | |
| v[2] = screenedge[i].normal[1]; | |
| v2[0] = ((v[1] * vright[0]) + (v[2] * vup[0])) + (v[0] * vpn[0]); | |
| v2[1] = ((v[1] * vright[1]) + (v[2] * vup[1])) + (v[0] * vpn[1]); | |
| v2[2] = ((v[1] * vright[2]) + (v[2] * vup[2])) + (v[0] * vpn[2]); | |
| VectorCopy(v2, view_clipplanes[i].normal); | |
| view_clipplanes[i].dist = DotProduct(modelorg, v2); | |
| } | |
| } | |
| void TransformVector(vec3_t in, vec3_t out) | |
| { | |
| out[0] = DotProduct(in, vright); | |
| out[1] = DotProduct(in, vup); | |
| out[2] = DotProduct(in, vpn); | |
| } | |
| void R_TransformPlane(mplane_t *p, float *normal, float *dist) | |
| { | |
| float d; | |
| d = DotProduct(r_origin, p->normal); | |
| *dist = p->dist - d; | |
| TransformVector(p->normal, normal); | |
| } | |
| void R_SetUpFrustumIndexes(void) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| int32_t *pindex; | |
| pindex = r_frustum_indexes; | |
| for (i = 0; i < 4; i++) | |
| { | |
| for (j = 0; j < 3; j++) | |
| { | |
| if (view_clipplanes[i].normal[j] < 0) | |
| { | |
| pindex[j] = j; | |
| pindex[j + 3] = j + 3; | |
| } | |
| else | |
| { | |
| pindex[j] = j + 3; | |
| pindex[j + 3] = j; | |
| } | |
| } | |
| pfrustum_indexes[i] = pindex; | |
| pindex += 6; | |
| } | |
| } | |
| void R_SetupFrame(void) | |
| { | |
| int32_t edgecount; | |
| vrect_t vrect; | |
| float w; | |
| float h; | |
| if (cl.maxclients > 1) | |
| { | |
| Cvar_Set("r_draworder", "0"); | |
| Cvar_Set("r_fullbright", "0"); | |
| Cvar_Set("r_ambient", "0"); | |
| Cvar_Set("r_drawflat", "0"); | |
| } | |
| if (r_numsurfs.value) | |
| { | |
| if ((surface_p - surfaces) > r_maxsurfsseen) | |
| r_maxsurfsseen = surface_p - surfaces; | |
| Con_Printf("Used %d of %d surfs; %d max\n", surface_p - surfaces, surf_max - surfaces, r_maxsurfsseen); | |
| } | |
| if (r_numedges.value) | |
| { | |
| edgecount = edge_p - r_edges; | |
| if (edgecount > r_maxedgesseen) | |
| r_maxedgesseen = edgecount; | |
| Con_Printf("Used %d of %d edges; %d max\n", edgecount, r_numallocatededges, r_maxedgesseen); | |
| } | |
| r_refdef.ambientlight = r_ambient.value; | |
| if (r_refdef.ambientlight < 0) | |
| r_refdef.ambientlight = 0; | |
| if (!sv.active) | |
| r_draworder.value = 0; | |
| R_CheckVariables(); | |
| R_AnimateLight(); | |
| r_framecount++; | |
| numbtofpolys = 0; | |
| VectorCopy(r_refdef.vieworg, modelorg); | |
| VectorCopy(r_refdef.vieworg, r_origin); | |
| AngleVectors(r_refdef.viewangles, vpn, vright, vup); | |
| r_oldviewleaf = r_viewleaf; | |
| r_viewleaf = Mod_PointInLeaf(r_origin, cl.worldmodel); | |
| r_dowarpold = r_dowarp; | |
| r_dowarp = r_waterwarp.value && (r_viewleaf->contents <= CONTENTS_WATER); | |
| if (((r_dowarp != r_dowarpold) || r_viewchanged) || lcd_x.value) | |
| { | |
| if (r_dowarp) | |
| { | |
| if ((vid.width <= vid.maxwarpwidth) && (vid.height <= vid.maxwarpheight)) | |
| { | |
| vrect.x = 0; | |
| vrect.y = 0; | |
| vrect.width = vid.width; | |
| vrect.height = vid.height; | |
| R_ViewChanged(&vrect, sb_lines, vid.aspect); | |
| } | |
| else | |
| { | |
| w = vid.width; | |
| h = vid.height; | |
| if (w > vid.maxwarpwidth) | |
| { | |
| h *= ((float) vid.maxwarpwidth) / w; | |
| w = vid.maxwarpwidth; | |
| } | |
| if (h > vid.maxwarpheight) | |
| { | |
| h = vid.maxwarpheight; | |
| w *= ((float) vid.maxwarpheight) / h; | |
| } | |
| vrect.x = 0; | |
| vrect.y = 0; | |
| vrect.width = (int32_t) w; | |
| vrect.height = (int32_t) h; | |
| R_ViewChanged(&vrect, (int32_t) (((float) sb_lines) * (h / ((float) vid.height))), (vid.aspect * (h / w)) * (((float) vid.width) / ((float) vid.height))); | |
| } | |
| } | |
| else | |
| { | |
| vrect.x = 0; | |
| vrect.y = 0; | |
| vrect.width = vid.width; | |
| vrect.height = vid.height; | |
| R_ViewChanged(&vrect, sb_lines, vid.aspect); | |
| } | |
| r_viewchanged = 0; | |
| } | |
| R_TransformFrustum(); | |
| VectorCopy(vpn, base_vpn); | |
| VectorCopy(vright, base_vright); | |
| VectorCopy(vup, base_vup); | |
| VectorCopy(modelorg, base_modelorg); | |
| R_SetSkyFrame(); | |
| R_SetUpFrustumIndexes(); | |
| r_cache_thrash = 0; | |
| c_faceclip = 0; | |
| d_spanpixcount = 0; | |
| r_polycount = 0; | |
| r_drawnpolycount = 0; | |
| r_wholepolycount = 0; | |
| r_amodels_drawn = 0; | |
| r_outofsurfaces = 0; | |
| r_outofedges = 0; | |
| D_SetupFrame(); | |
| } | |
| void R_InitParticles(void) | |
| { | |
| int32_t i; | |
| i = COM_CheckParm("-particles"); | |
| if (i) | |
| { | |
| r_numparticles = (int32_t) ((int32_t) strtol(com_argv[i + 1], 0, 0)); | |
| if (r_numparticles < ABSOLUTE_MIN_PARTICLES) | |
| r_numparticles = ABSOLUTE_MIN_PARTICLES; | |
| } | |
| else | |
| { | |
| r_numparticles = MAX_PARTICLES; | |
| } | |
| particles = (particle_t *) Hunk_AllocName(r_numparticles * (sizeof(particle_t)), "particles"); | |
| } | |
| void R_EntityParticles(entity_t *ent) | |
| { | |
| int32_t count; | |
| int32_t i; | |
| particle_t *p; | |
| float angle; | |
| float sr; | |
| float sp; | |
| float sy; | |
| float cr; | |
| float cp; | |
| float cy; | |
| vec3_t forward; | |
| float dist; | |
| dist = 64; | |
| count = 50; | |
| if (!avelocities[0][0]) | |
| { | |
| for (i = 0; i < (NUMVERTEXNORMALS * 3); i++) | |
| avelocities[0][i] = (rand() & 255) * 0.01; | |
| } | |
| for (i = 0; i < NUMVERTEXNORMALS; i++) | |
| { | |
| angle = cl.time * avelocities[i][0]; | |
| sy = sin(angle); | |
| cy = cos(angle); | |
| angle = cl.time * avelocities[i][1]; | |
| sp = sin(angle); | |
| cp = cos(angle); | |
| angle = cl.time * avelocities[i][2]; | |
| sr = sin(angle); | |
| cr = cos(angle); | |
| forward[0] = cp * cy; | |
| forward[1] = cp * sy; | |
| forward[2] = -sp; | |
| if (!free_particles) | |
| return; | |
| p = free_particles; | |
| free_particles = p->next; | |
| p->next = active_particles; | |
| active_particles = p; | |
| p->die = cl.time + 0.01; | |
| p->color = 0x6f; | |
| p->type = pt_explode; | |
| p->org[0] = (ent->origin[0] + (r_avertexnormals[i][0] * dist)) + (forward[0] * beamlength); | |
| p->org[1] = (ent->origin[1] + (r_avertexnormals[i][1] * dist)) + (forward[1] * beamlength); | |
| p->org[2] = (ent->origin[2] + (r_avertexnormals[i][2] * dist)) + (forward[2] * beamlength); | |
| } | |
| } | |
| void R_ClearParticles(void) | |
| { | |
| int32_t i; | |
| free_particles = &particles[0]; | |
| active_particles = 0; | |
| for (i = 0; i < r_numparticles; i++) | |
| particles[i].next = &particles[i + 1]; | |
| particles[r_numparticles - 1].next = 0; | |
| } | |
| void R_ReadPointFile_f(void) | |
| { | |
| FILE *f; | |
| vec3_t org; | |
| int32_t r; | |
| int32_t c; | |
| particle_t *p; | |
| char name[MAX_OSPATH]; | |
| sprintf(name, "maps/%s.pts", sv.name); | |
| COM_FOpenFile(name, &f); | |
| if (!f) | |
| { | |
| Con_Printf("couldn't open %s\n", name); | |
| return; | |
| } | |
| Con_Printf("Reading %s...\n", name); | |
| c = 0; | |
| for (;;) | |
| { | |
| r = fscanf(f, "%f %f %f\n", &org[0], &org[1], &org[2]); | |
| if (r != 3) | |
| break; | |
| c++; | |
| if (!free_particles) | |
| { | |
| Con_Printf("Not enough free particles\n"); | |
| break; | |
| } | |
| p = free_particles; | |
| free_particles = p->next; | |
| p->next = active_particles; | |
| active_particles = p; | |
| p->die = 99999; | |
| p->color = (-c) & 15; | |
| p->type = pt_static; | |
| VectorCopy(vec3_origin, p->vel); | |
| VectorCopy(org, p->org); | |
| } | |
| fclose(f); | |
| Con_Printf("%i points read\n", c); | |
| } | |
| void R_ParseParticleEffect(void) | |
| { | |
| vec3_t org; | |
| vec3_t dir; | |
| int32_t i; | |
| int32_t count; | |
| int32_t msgcount; | |
| int32_t color; | |
| for (i = 0; i < 3; i++) | |
| org[i] = MSG_ReadCoord(); | |
| for (i = 0; i < 3; i++) | |
| dir[i] = MSG_ReadChar() * (1.0 / 16); | |
| msgcount = MSG_ReadByte(); | |
| color = MSG_ReadByte(); | |
| if (msgcount == 255) | |
| count = 1024; | |
| else | |
| count = msgcount; | |
| R_RunParticleEffect(org, dir, color, count); | |
| } | |
| void R_ParticleExplosion(vec3_t org) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| particle_t *p; | |
| for (i = 0; i < 1024; i++) | |
| { | |
| if (!free_particles) | |
| return; | |
| p = free_particles; | |
| free_particles = p->next; | |
| p->next = active_particles; | |
| active_particles = p; | |
| p->die = cl.time + 5; | |
| p->color = ramp1[0]; | |
| p->ramp = rand() & 3; | |
| if (i & 1) | |
| { | |
| p->type = pt_explode; | |
| for (j = 0; j < 3; j++) | |
| { | |
| p->org[j] = org[j] + ((rand() % 32) - 16); | |
| p->vel[j] = (rand() % 512) - 256; | |
| } | |
| } | |
| else | |
| { | |
| p->type = pt_explode2; | |
| for (j = 0; j < 3; j++) | |
| { | |
| p->org[j] = org[j] + ((rand() % 32) - 16); | |
| p->vel[j] = (rand() % 512) - 256; | |
| } | |
| } | |
| } | |
| } | |
| void R_ParticleExplosion2(vec3_t org, int32_t colorStart, int32_t colorLength) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| particle_t *p; | |
| int32_t colorMod = 0; | |
| for (i = 0; i < 512; i++) | |
| { | |
| if (!free_particles) | |
| return; | |
| p = free_particles; | |
| free_particles = p->next; | |
| p->next = active_particles; | |
| active_particles = p; | |
| p->die = cl.time + 0.3; | |
| p->color = colorStart + (colorMod % colorLength); | |
| colorMod++; | |
| p->type = pt_blob; | |
| for (j = 0; j < 3; j++) | |
| { | |
| p->org[j] = org[j] + ((rand() % 32) - 16); | |
| p->vel[j] = (rand() % 512) - 256; | |
| } | |
| } | |
| } | |
| void R_BlobExplosion(vec3_t org) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| particle_t *p; | |
| for (i = 0; i < 1024; i++) | |
| { | |
| if (!free_particles) | |
| return; | |
| p = free_particles; | |
| free_particles = p->next; | |
| p->next = active_particles; | |
| active_particles = p; | |
| p->die = (cl.time + 1) + ((rand() & 8) * 0.05); | |
| if (i & 1) | |
| { | |
| p->type = pt_blob; | |
| p->color = 66 + (rand() % 6); | |
| for (j = 0; j < 3; j++) | |
| { | |
| p->org[j] = org[j] + ((rand() % 32) - 16); | |
| p->vel[j] = (rand() % 512) - 256; | |
| } | |
| } | |
| else | |
| { | |
| p->type = pt_blob2; | |
| p->color = 150 + (rand() % 6); | |
| for (j = 0; j < 3; j++) | |
| { | |
| p->org[j] = org[j] + ((rand() % 32) - 16); | |
| p->vel[j] = (rand() % 512) - 256; | |
| } | |
| } | |
| } | |
| } | |
| void R_RunParticleEffect(vec3_t org, vec3_t dir, int32_t color, int32_t count) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| particle_t *p; | |
| for (i = 0; i < count; i++) | |
| { | |
| if (!free_particles) | |
| return; | |
| p = free_particles; | |
| free_particles = p->next; | |
| p->next = active_particles; | |
| active_particles = p; | |
| if (count == 1024) | |
| { | |
| p->die = cl.time + 5; | |
| p->color = ramp1[0]; | |
| p->ramp = rand() & 3; | |
| if (i & 1) | |
| { | |
| p->type = pt_explode; | |
| for (j = 0; j < 3; j++) | |
| { | |
| p->org[j] = org[j] + ((rand() % 32) - 16); | |
| p->vel[j] = (rand() % 512) - 256; | |
| } | |
| } | |
| else | |
| { | |
| p->type = pt_explode2; | |
| for (j = 0; j < 3; j++) | |
| { | |
| p->org[j] = org[j] + ((rand() % 32) - 16); | |
| p->vel[j] = (rand() % 512) - 256; | |
| } | |
| } | |
| } | |
| else | |
| { | |
| p->die = cl.time + (0.1 * (rand() % 5)); | |
| p->color = (color & (~7)) + (rand() & 7); | |
| p->type = pt_slowgrav; | |
| for (j = 0; j < 3; j++) | |
| { | |
| p->org[j] = org[j] + ((rand() & 15) - 8); | |
| p->vel[j] = dir[j] * 15; | |
| } | |
| } | |
| } | |
| } | |
| void R_LavaSplash(vec3_t org) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| int32_t k; | |
| particle_t *p; | |
| float vel; | |
| vec3_t dir; | |
| for (i = -16; i < 16; i++) | |
| for (j = -16; j < 16; j++) | |
| for (k = 0; k < 1; k++) | |
| { | |
| if (!free_particles) | |
| return; | |
| p = free_particles; | |
| free_particles = p->next; | |
| p->next = active_particles; | |
| active_particles = p; | |
| p->die = (cl.time + 2) + ((rand() & 31) * 0.02); | |
| p->color = 224 + (rand() & 7); | |
| p->type = pt_slowgrav; | |
| dir[0] = (j * 8) + (rand() & 7); | |
| dir[1] = (i * 8) + (rand() & 7); | |
| dir[2] = 256; | |
| p->org[0] = org[0] + dir[0]; | |
| p->org[1] = org[1] + dir[1]; | |
| p->org[2] = org[2] + (rand() & 63); | |
| VectorNormalize(dir); | |
| vel = 50 + (rand() & 63); | |
| VectorScale(dir, vel, p->vel); | |
| } | |
| } | |
| void R_TeleportSplash(vec3_t org) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| int32_t k; | |
| particle_t *p; | |
| float vel; | |
| vec3_t dir; | |
| for (i = -16; i < 16; i += 4) | |
| for (j = -16; j < 16; j += 4) | |
| for (k = -24; k < 32; k += 4) | |
| { | |
| if (!free_particles) | |
| return; | |
| p = free_particles; | |
| free_particles = p->next; | |
| p->next = active_particles; | |
| active_particles = p; | |
| p->die = (cl.time + 0.2) + ((rand() & 7) * 0.02); | |
| p->color = 7 + (rand() & 7); | |
| p->type = pt_slowgrav; | |
| dir[0] = j * 8; | |
| dir[1] = i * 8; | |
| dir[2] = k * 8; | |
| p->org[0] = (org[0] + i) + (rand() & 3); | |
| p->org[1] = (org[1] + j) + (rand() & 3); | |
| p->org[2] = (org[2] + k) + (rand() & 3); | |
| VectorNormalize(dir); | |
| vel = 50 + (rand() & 63); | |
| VectorScale(dir, vel, p->vel); | |
| } | |
| } | |
| void R_RocketTrail(vec3_t start, vec3_t end, int32_t type) | |
| { | |
| vec3_t vec; | |
| float len; | |
| int32_t j; | |
| particle_t *p; | |
| int32_t dec; | |
| static int32_t tracercount; | |
| VectorSubtract(end, start, vec); | |
| len = VectorNormalize(vec); | |
| if (type < 128) | |
| dec = 3; | |
| else | |
| { | |
| dec = 1; | |
| type -= 128; | |
| } | |
| while (len > 0) | |
| { | |
| len -= dec; | |
| if (!free_particles) | |
| return; | |
| p = free_particles; | |
| free_particles = p->next; | |
| p->next = active_particles; | |
| active_particles = p; | |
| VectorCopy(vec3_origin, p->vel); | |
| p->die = cl.time + 2; | |
| switch (type) | |
| { | |
| case 0: | |
| p->ramp = rand() & 3; | |
| p->color = ramp3[(int32_t) p->ramp]; | |
| p->type = pt_fire; | |
| for (j = 0; j < 3; j++) | |
| p->org[j] = start[j] + ((rand() % 6) - 3); | |
| break; | |
| case 1: | |
| p->ramp = (rand() & 3) + 2; | |
| p->color = ramp3[(int32_t) p->ramp]; | |
| p->type = pt_fire; | |
| for (j = 0; j < 3; j++) | |
| p->org[j] = start[j] + ((rand() % 6) - 3); | |
| break; | |
| case 2: | |
| p->type = pt_grav; | |
| p->color = 67 + (rand() & 3); | |
| for (j = 0; j < 3; j++) | |
| p->org[j] = start[j] + ((rand() % 6) - 3); | |
| break; | |
| case 3: | |
| case 5: | |
| p->die = cl.time + 0.5; | |
| p->type = pt_static; | |
| if (type == 3) | |
| p->color = 52 + ((tracercount & 4) << 1); | |
| else | |
| p->color = 230 + ((tracercount & 4) << 1); | |
| tracercount++; | |
| VectorCopy(start, p->org); | |
| if (tracercount & 1) | |
| { | |
| p->vel[0] = 30 * vec[1]; | |
| p->vel[1] = 30 * (-vec[0]); | |
| } | |
| else | |
| { | |
| p->vel[0] = 30 * (-vec[1]); | |
| p->vel[1] = 30 * vec[0]; | |
| } | |
| break; | |
| case 4: | |
| p->type = pt_grav; | |
| p->color = 67 + (rand() & 3); | |
| for (j = 0; j < 3; j++) | |
| p->org[j] = start[j] + ((rand() % 6) - 3); | |
| len -= 3; | |
| break; | |
| case 6: | |
| p->color = ((9 * 16) + 8) + (rand() & 3); | |
| p->type = pt_static; | |
| p->die = cl.time + 0.3; | |
| for (j = 0; j < 3; j++) | |
| p->org[j] = start[j] + ((rand() & 15) - 8); | |
| break; | |
| } | |
| VectorAdd(start, vec, start); | |
| } | |
| } | |
| void R_DrawParticles(void) | |
| { | |
| particle_t *p; | |
| particle_t *kill; | |
| float grav; | |
| int32_t i; | |
| float time2; | |
| float time3; | |
| float time1; | |
| float dvel; | |
| float frametime; | |
| D_StartParticles(); | |
| VectorScale(vright, xscaleshrink, r_pright); | |
| VectorScale(vup, yscaleshrink, r_pup); | |
| VectorCopy(vpn, r_ppn); | |
| frametime = cl.time - cl.oldtime; | |
| time3 = frametime * 15; | |
| time2 = frametime * 10; | |
| time1 = frametime * 5; | |
| grav = (frametime * sv_gravity.value) * 0.05; | |
| dvel = 4 * frametime; | |
| for (;;) | |
| { | |
| kill = active_particles; | |
| if (kill && (kill->die < cl.time)) | |
| { | |
| active_particles = kill->next; | |
| kill->next = free_particles; | |
| free_particles = kill; | |
| continue; | |
| } | |
| break; | |
| } | |
| for (p = active_particles; p; p = p->next) | |
| { | |
| for (;;) | |
| { | |
| kill = p->next; | |
| if (kill && (kill->die < cl.time)) | |
| { | |
| p->next = kill->next; | |
| kill->next = free_particles; | |
| free_particles = kill; | |
| continue; | |
| } | |
| break; | |
| } | |
| D_DrawParticle(p); | |
| p->org[0] += p->vel[0] * frametime; | |
| p->org[1] += p->vel[1] * frametime; | |
| p->org[2] += p->vel[2] * frametime; | |
| switch (p->type) | |
| { | |
| case pt_static: | |
| break; | |
| case pt_fire: | |
| p->ramp += time1; | |
| if (p->ramp >= 6) | |
| p->die = -1; | |
| else | |
| p->color = ramp3[(int32_t) p->ramp]; | |
| p->vel[2] += grav; | |
| break; | |
| case pt_explode: | |
| p->ramp += time2; | |
| if (p->ramp >= 8) | |
| p->die = -1; | |
| else | |
| p->color = ramp1[(int32_t) p->ramp]; | |
| for (i = 0; i < 3; i++) | |
| p->vel[i] += p->vel[i] * dvel; | |
| p->vel[2] -= grav; | |
| break; | |
| case pt_explode2: | |
| p->ramp += time3; | |
| if (p->ramp >= 8) | |
| p->die = -1; | |
| else | |
| p->color = ramp2[(int32_t) p->ramp]; | |
| for (i = 0; i < 3; i++) | |
| p->vel[i] -= p->vel[i] * frametime; | |
| p->vel[2] -= grav; | |
| break; | |
| case pt_blob: | |
| for (i = 0; i < 3; i++) | |
| p->vel[i] += p->vel[i] * dvel; | |
| p->vel[2] -= grav; | |
| break; | |
| case pt_blob2: | |
| for (i = 0; i < 2; i++) | |
| p->vel[i] -= p->vel[i] * dvel; | |
| p->vel[2] -= grav; | |
| break; | |
| case pt_grav: | |
| case pt_slowgrav: | |
| p->vel[2] -= grav; | |
| break; | |
| } | |
| } | |
| D_EndParticles(); | |
| } | |
| void R_InitSky(texture_t *mt) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| uint8_t *src; | |
| src = ((uint8_t *) mt) + mt->offsets[0]; | |
| for (i = 0; i < 128; i++) | |
| { | |
| for (j = 0; j < 128; j++) | |
| { | |
| newsky[((i * 256) + j) + 128] = src[((i * 256) + j) + 128]; | |
| } | |
| } | |
| for (i = 0; i < 128; i++) | |
| { | |
| for (j = 0; j < 131; j++) | |
| { | |
| if (src[(i * 256) + (j & 0x7F)]) | |
| { | |
| bottomsky[(i * 131) + j] = src[(i * 256) + (j & 0x7F)]; | |
| bottommask[(i * 131) + j] = 0; | |
| } | |
| else | |
| { | |
| bottomsky[(i * 131) + j] = 0; | |
| bottommask[(i * 131) + j] = 0xff; | |
| } | |
| } | |
| } | |
| r_skysource = newsky; | |
| } | |
| void R_MakeSky(void) | |
| { | |
| int32_t x; | |
| int32_t y; | |
| int32_t ofs; | |
| int32_t baseofs; | |
| int32_t xshift; | |
| int32_t yshift; | |
| uint32_t *pnewsky; | |
| static int32_t xlast = -1; | |
| static int32_t ylast = -1; | |
| xshift = skytime * skyspeed; | |
| yshift = skytime * skyspeed; | |
| if ((xshift == xlast) && (yshift == ylast)) | |
| return; | |
| xlast = xshift; | |
| ylast = yshift; | |
| pnewsky = (uint32_t *) (&newsky[0]); | |
| for (y = 0; y < SKYSIZE; y++) | |
| { | |
| baseofs = ((y + yshift) & SKYMASK) * 131; | |
| for (x = 0; x < SKYSIZE; x++) | |
| { | |
| ofs = baseofs + ((x + xshift) & SKYMASK); | |
| *((uint8_t *) pnewsky) = ((*(((uint8_t *) pnewsky) + 128)) & (*((uint8_t *) (&bottommask[ofs])))) | (*((uint8_t *) (&bottomsky[ofs]))); | |
| pnewsky = (uint32_t *) (((uint8_t *) pnewsky) + 1); | |
| } | |
| pnewsky += 128 / (sizeof(uint32_t)); | |
| } | |
| r_skymade = 1; | |
| } | |
| void R_GenSkyTile(void *pdest) | |
| { | |
| int32_t x; | |
| int32_t y; | |
| int32_t ofs; | |
| int32_t baseofs; | |
| int32_t xshift; | |
| int32_t yshift; | |
| uint32_t *pnewsky; | |
| uint32_t *pd; | |
| xshift = skytime * skyspeed; | |
| yshift = skytime * skyspeed; | |
| pnewsky = (uint32_t *) (&newsky[0]); | |
| pd = (uint32_t *) pdest; | |
| for (y = 0; y < SKYSIZE; y++) | |
| { | |
| baseofs = ((y + yshift) & SKYMASK) * 131; | |
| for (x = 0; x < SKYSIZE; x++) | |
| { | |
| ofs = baseofs + ((x + xshift) & SKYMASK); | |
| *((uint8_t *) pd) = ((*(((uint8_t *) pnewsky) + 128)) & (*((uint8_t *) (&bottommask[ofs])))) | (*((uint8_t *) (&bottomsky[ofs]))); | |
| pnewsky = (uint32_t *) (((uint8_t *) pnewsky) + 1); | |
| pd = (uint32_t *) (((uint8_t *) pd) + 1); | |
| } | |
| pnewsky += 128 / (sizeof(uint32_t)); | |
| } | |
| } | |
| void R_GenSkyTile16(void *pdest) | |
| { | |
| int32_t x; | |
| int32_t y; | |
| int32_t ofs; | |
| int32_t baseofs; | |
| int32_t xshift; | |
| int32_t yshift; | |
| uint8_t *pnewsky; | |
| uint16_t *pd; | |
| xshift = skytime * skyspeed; | |
| yshift = skytime * skyspeed; | |
| pnewsky = (uint8_t *) (&newsky[0]); | |
| pd = (uint16_t *) pdest; | |
| for (y = 0; y < SKYSIZE; y++) | |
| { | |
| baseofs = ((y + yshift) & SKYMASK) * 131; | |
| for (x = 0; x < SKYSIZE; x++) | |
| { | |
| ofs = baseofs + ((x + xshift) & SKYMASK); | |
| *pd = d_8to16table[((*(pnewsky + 128)) & (*((uint8_t *) (&bottommask[ofs])))) | (*((uint8_t *) (&bottomsky[ofs])))]; | |
| pnewsky++; | |
| pd++; | |
| } | |
| pnewsky += TILE_SIZE; | |
| } | |
| } | |
| void R_SetSkyFrame(void) | |
| { | |
| int32_t g; | |
| int32_t s1; | |
| int32_t s2; | |
| float temp; | |
| skyspeed = iskyspeed; | |
| skyspeed2 = iskyspeed2; | |
| g = GreatestCommonDivisor(iskyspeed, iskyspeed2); | |
| s1 = iskyspeed / g; | |
| s2 = iskyspeed2 / g; | |
| temp = (SKYSIZE * s1) * s2; | |
| skytime = cl.time - (((int32_t) (cl.time / temp)) * temp); | |
| r_skymade = 0; | |
| } | |
| void R_RotateSprite(float beamlength) | |
| { | |
| vec3_t vec; | |
| if (beamlength == 0.0) | |
| return; | |
| VectorScale(r_spritedesc.vpn, -beamlength, vec); | |
| VectorAdd(r_entorigin, vec, r_entorigin); | |
| VectorSubtract(modelorg, vec, modelorg); | |
| } | |
| int32_t R_ClipSpriteFace(int32_t nump, clipplane_t *pclipplane) | |
| { | |
| int32_t i; | |
| int32_t outcount; | |
| float dists[MAXWORKINGVERTS + 1]; | |
| float frac; | |
| float clipdist; | |
| float *pclipnormal; | |
| float *in; | |
| float *instep; | |
| float *outstep; | |
| float *vert2; | |
| clipdist = pclipplane->dist; | |
| pclipnormal = pclipplane->normal; | |
| if (clip_current) | |
| { | |
| in = clip_verts[1][0]; | |
| outstep = clip_verts[0][0]; | |
| clip_current = 0; | |
| } | |
| else | |
| { | |
| in = clip_verts[0][0]; | |
| outstep = clip_verts[1][0]; | |
| clip_current = 1; | |
| } | |
| instep = in; | |
| for (i = 0; i < nump; i++, instep += (sizeof(vec5_t)) / (sizeof(float))) | |
| { | |
| dists[i] = DotProduct(instep, pclipnormal) - clipdist; | |
| } | |
| dists[nump] = dists[0]; | |
| memcpy(instep, in, sizeof(vec5_t)); | |
| instep = in; | |
| outcount = 0; | |
| for (i = 0; i < nump; i++, instep += (sizeof(vec5_t)) / (sizeof(float))) | |
| { | |
| if (dists[i] >= 0) | |
| { | |
| memcpy(outstep, instep, sizeof(vec5_t)); | |
| outstep += (sizeof(vec5_t)) / (sizeof(float)); | |
| outcount++; | |
| } | |
| if ((dists[i] == 0) || (dists[i + 1] == 0)) | |
| continue; | |
| if ((dists[i] > 0) == (dists[i + 1] > 0)) | |
| continue; | |
| frac = dists[i] / (dists[i] - dists[i + 1]); | |
| vert2 = instep + ((sizeof(vec5_t)) / (sizeof(float))); | |
| outstep[0] = instep[0] + (frac * (vert2[0] - instep[0])); | |
| outstep[1] = instep[1] + (frac * (vert2[1] - instep[1])); | |
| outstep[2] = instep[2] + (frac * (vert2[2] - instep[2])); | |
| outstep[3] = instep[3] + (frac * (vert2[3] - instep[3])); | |
| outstep[4] = instep[4] + (frac * (vert2[4] - instep[4])); | |
| outstep += (sizeof(vec5_t)) / (sizeof(float)); | |
| outcount++; | |
| } | |
| return outcount; | |
| } | |
| void R_SetupAndDrawSprite() | |
| { | |
| int32_t i; | |
| int32_t nump; | |
| float dot; | |
| float scale; | |
| float *pv; | |
| vec5_t *pverts; | |
| vec3_t left; | |
| vec3_t up; | |
| vec3_t right; | |
| vec3_t down; | |
| vec3_t transformed; | |
| vec3_t local; | |
| emitpoint_t outverts[MAXWORKINGVERTS + 1]; | |
| emitpoint_t *pout; | |
| dot = DotProduct(r_spritedesc.vpn, modelorg); | |
| if (dot >= 0) | |
| return; | |
| VectorScale(r_spritedesc.vright, r_spritedesc.pspriteframe->right, right); | |
| VectorScale(r_spritedesc.vup, r_spritedesc.pspriteframe->up, up); | |
| VectorScale(r_spritedesc.vright, r_spritedesc.pspriteframe->left, left); | |
| VectorScale(r_spritedesc.vup, r_spritedesc.pspriteframe->down, down); | |
| pverts = clip_verts[0]; | |
| pverts[0][0] = (r_entorigin[0] + up[0]) + left[0]; | |
| pverts[0][1] = (r_entorigin[1] + up[1]) + left[1]; | |
| pverts[0][2] = (r_entorigin[2] + up[2]) + left[2]; | |
| pverts[0][3] = 0; | |
| pverts[0][4] = 0; | |
| pverts[1][0] = (r_entorigin[0] + up[0]) + right[0]; | |
| pverts[1][1] = (r_entorigin[1] + up[1]) + right[1]; | |
| pverts[1][2] = (r_entorigin[2] + up[2]) + right[2]; | |
| pverts[1][3] = sprite_width; | |
| pverts[1][4] = 0; | |
| pverts[2][0] = (r_entorigin[0] + down[0]) + right[0]; | |
| pverts[2][1] = (r_entorigin[1] + down[1]) + right[1]; | |
| pverts[2][2] = (r_entorigin[2] + down[2]) + right[2]; | |
| pverts[2][3] = sprite_width; | |
| pverts[2][4] = sprite_height; | |
| pverts[3][0] = (r_entorigin[0] + down[0]) + left[0]; | |
| pverts[3][1] = (r_entorigin[1] + down[1]) + left[1]; | |
| pverts[3][2] = (r_entorigin[2] + down[2]) + left[2]; | |
| pverts[3][3] = 0; | |
| pverts[3][4] = sprite_height; | |
| nump = 4; | |
| clip_current = 0; | |
| for (i = 0; i < 4; i++) | |
| { | |
| nump = R_ClipSpriteFace(nump, &view_clipplanes[i]); | |
| if (nump < 3) | |
| return; | |
| if (nump >= MAXWORKINGVERTS) | |
| Sys_Error("R_SetupAndDrawSprite: too many points"); | |
| } | |
| pv = &clip_verts[clip_current][0][0]; | |
| r_spritedesc.nearzi = -999999; | |
| for (i = 0; i < nump; i++) | |
| { | |
| VectorSubtract(pv, r_origin, local); | |
| TransformVector(local, transformed); | |
| if (transformed[2] < NEAR_CLIP) | |
| transformed[2] = NEAR_CLIP; | |
| pout = &outverts[i]; | |
| pout->zi = 1.0 / transformed[2]; | |
| if (pout->zi > r_spritedesc.nearzi) | |
| r_spritedesc.nearzi = pout->zi; | |
| pout->s = pv[3]; | |
| pout->t = pv[4]; | |
| scale = xscale * pout->zi; | |
| pout->u = xcenter + (scale * transformed[0]); | |
| scale = yscale * pout->zi; | |
| pout->v = ycenter - (scale * transformed[1]); | |
| pv += (sizeof(vec5_t)) / (sizeof(*pv)); | |
| } | |
| r_spritedesc.nump = nump; | |
| r_spritedesc.pverts = outverts; | |
| D_DrawSprite(); | |
| } | |
| mspriteframe_t *R_GetSpriteframe(msprite_t *psprite) | |
| { | |
| mspritegroup_t *pspritegroup; | |
| mspriteframe_t *pspriteframe; | |
| int32_t i; | |
| int32_t numframes; | |
| int32_t frame; | |
| float *pintervals; | |
| float fullinterval; | |
| float targettime; | |
| float time; | |
| frame = currententity->frame; | |
| if ((frame >= psprite->numframes) || (frame < 0)) | |
| { | |
| Con_Printf("R_DrawSprite: no such frame %d\n", frame); | |
| frame = 0; | |
| } | |
| if (psprite->frames[frame].type == SPR_SINGLE) | |
| { | |
| pspriteframe = psprite->frames[frame].frameptr; | |
| } | |
| else | |
| { | |
| pspritegroup = (mspritegroup_t *) psprite->frames[frame].frameptr; | |
| pintervals = pspritegroup->intervals; | |
| numframes = pspritegroup->numframes; | |
| fullinterval = pintervals[numframes - 1]; | |
| time = cl.time + currententity->syncbase; | |
| targettime = time - (((int32_t) (time / fullinterval)) * fullinterval); | |
| for (i = 0; i < (numframes - 1); i++) | |
| { | |
| if (pintervals[i] > targettime) | |
| break; | |
| } | |
| pspriteframe = pspritegroup->frames[i]; | |
| } | |
| return pspriteframe; | |
| } | |
| void R_DrawSprite(void) | |
| { | |
| int32_t i; | |
| msprite_t *psprite; | |
| vec3_t tvec; | |
| float dot; | |
| float angle; | |
| float sr; | |
| float cr; | |
| psprite = currententity->model->cache.data; | |
| r_spritedesc.pspriteframe = R_GetSpriteframe(psprite); | |
| sprite_width = r_spritedesc.pspriteframe->width; | |
| sprite_height = r_spritedesc.pspriteframe->height; | |
| if (psprite->type == SPR_FACING_UPRIGHT) | |
| { | |
| tvec[0] = -modelorg[0]; | |
| tvec[1] = -modelorg[1]; | |
| tvec[2] = -modelorg[2]; | |
| VectorNormalize(tvec); | |
| dot = tvec[2]; | |
| if ((dot > 0.999848) || (dot < (-0.999848))) | |
| return; | |
| r_spritedesc.vup[0] = 0; | |
| r_spritedesc.vup[1] = 0; | |
| r_spritedesc.vup[2] = 1; | |
| r_spritedesc.vright[0] = tvec[1]; | |
| r_spritedesc.vright[1] = -tvec[0]; | |
| r_spritedesc.vright[2] = 0; | |
| VectorNormalize(r_spritedesc.vright); | |
| r_spritedesc.vpn[0] = -r_spritedesc.vright[1]; | |
| r_spritedesc.vpn[1] = r_spritedesc.vright[0]; | |
| r_spritedesc.vpn[2] = 0; | |
| } | |
| else | |
| if (psprite->type == SPR_VP_PARALLEL) | |
| { | |
| for (i = 0; i < 3; i++) | |
| { | |
| r_spritedesc.vup[i] = vup[i]; | |
| r_spritedesc.vright[i] = vright[i]; | |
| r_spritedesc.vpn[i] = vpn[i]; | |
| } | |
| } | |
| else | |
| if (psprite->type == SPR_VP_PARALLEL_UPRIGHT) | |
| { | |
| dot = vpn[2]; | |
| if ((dot > 0.999848) || (dot < (-0.999848))) | |
| return; | |
| r_spritedesc.vup[0] = 0; | |
| r_spritedesc.vup[1] = 0; | |
| r_spritedesc.vup[2] = 1; | |
| r_spritedesc.vright[0] = vpn[1]; | |
| r_spritedesc.vright[1] = -vpn[0]; | |
| r_spritedesc.vright[2] = 0; | |
| VectorNormalize(r_spritedesc.vright); | |
| r_spritedesc.vpn[0] = -r_spritedesc.vright[1]; | |
| r_spritedesc.vpn[1] = r_spritedesc.vright[0]; | |
| r_spritedesc.vpn[2] = 0; | |
| } | |
| else | |
| if (psprite->type == SPR_ORIENTED) | |
| { | |
| AngleVectors(currententity->angles, r_spritedesc.vpn, r_spritedesc.vright, r_spritedesc.vup); | |
| } | |
| else | |
| if (psprite->type == SPR_VP_PARALLEL_ORIENTED) | |
| { | |
| angle = currententity->angles[ROLL] * ((M_PI * 2) / 360); | |
| sr = sin(angle); | |
| cr = cos(angle); | |
| for (i = 0; i < 3; i++) | |
| { | |
| r_spritedesc.vpn[i] = vpn[i]; | |
| r_spritedesc.vright[i] = (vright[i] * cr) + (vup[i] * sr); | |
| r_spritedesc.vup[i] = (vright[i] * (-sr)) + (vup[i] * cr); | |
| } | |
| } | |
| else | |
| { | |
| Sys_Error("R_DrawSprite: Bad sprite type %d", psprite->type); | |
| } | |
| R_RotateSprite(psprite->beamlength); | |
| R_SetupAndDrawSprite(); | |
| } | |
| void R_AddDynamicLights(void) | |
| { | |
| msurface_t *surf; | |
| int32_t lnum; | |
| int32_t sd; | |
| int32_t td; | |
| float dist; | |
| float rad; | |
| float minlight; | |
| vec3_t impact; | |
| vec3_t local; | |
| int32_t s; | |
| int32_t t; | |
| int32_t i; | |
| int32_t smax; | |
| int32_t tmax; | |
| mtexinfo_t *tex; | |
| surf = r_drawsurf.surf; | |
| smax = (surf->extents[0] >> 4) + 1; | |
| tmax = (surf->extents[1] >> 4) + 1; | |
| tex = surf->texinfo; | |
| for (lnum = 0; lnum < MAX_DLIGHTS; lnum++) | |
| { | |
| if (!(surf->dlightbits & (1 << lnum))) | |
| continue; | |
| rad = cl_dlights[lnum].radius; | |
| dist = DotProduct(cl_dlights[lnum].origin, surf->plane->normal) - surf->plane->dist; | |
| rad -= fabs(dist); | |
| minlight = cl_dlights[lnum].minlight; | |
| if (rad < minlight) | |
| continue; | |
| minlight = rad - minlight; | |
| for (i = 0; i < 3; i++) | |
| { | |
| impact[i] = cl_dlights[lnum].origin[i] - (surf->plane->normal[i] * dist); | |
| } | |
| local[0] = DotProduct(impact, tex->vecs[0]) + tex->vecs[0][3]; | |
| local[1] = DotProduct(impact, tex->vecs[1]) + tex->vecs[1][3]; | |
| local[0] -= surf->texturemins[0]; | |
| local[1] -= surf->texturemins[1]; | |
| for (t = 0; t < tmax; t++) | |
| { | |
| td = local[1] - (t * 16); | |
| if (td < 0) | |
| td = -td; | |
| for (s = 0; s < smax; s++) | |
| { | |
| sd = local[0] - (s * 16); | |
| if (sd < 0) | |
| sd = -sd; | |
| if (sd > td) | |
| dist = sd + (td >> 1); | |
| else | |
| dist = td + (sd >> 1); | |
| if (dist < minlight) | |
| blocklights[(t * smax) + s] += (rad - dist) * 256; | |
| } | |
| } | |
| } | |
| } | |
| void R_BuildLightMap(void) | |
| { | |
| int32_t smax; | |
| int32_t tmax; | |
| int32_t t; | |
| int32_t i; | |
| int32_t size; | |
| uint8_t *lightmap; | |
| uint32_t scale; | |
| int32_t maps; | |
| msurface_t *surf; | |
| surf = r_drawsurf.surf; | |
| smax = (surf->extents[0] >> 4) + 1; | |
| tmax = (surf->extents[1] >> 4) + 1; | |
| size = smax * tmax; | |
| lightmap = surf->samples; | |
| if (r_fullbright.value || (!cl.worldmodel->lightdata)) | |
| { | |
| for (i = 0; i < size; i++) | |
| blocklights[i] = 0; | |
| return; | |
| } | |
| for (i = 0; i < size; i++) | |
| blocklights[i] = r_refdef.ambientlight << 8; | |
| if (lightmap) | |
| for (maps = 0; (maps < MAXLIGHTMAPS) && (surf->styles[maps] != 255); maps++) | |
| { | |
| scale = r_drawsurf.lightadj[maps]; | |
| for (i = 0; i < size; i++) | |
| blocklights[i] += lightmap[i] * scale; | |
| lightmap += size; | |
| } | |
| if (surf->dlightframe == r_framecount) | |
| R_AddDynamicLights(); | |
| for (i = 0; i < size; i++) | |
| { | |
| t = ((255 * 256) - ((int32_t) blocklights[i])) >> (8 - VID_CBITS); | |
| if (t < (1 << 6)) | |
| t = 1 << 6; | |
| blocklights[i] = t; | |
| } | |
| } | |
| texture_t *R_TextureAnimation(texture_t *base) | |
| { | |
| int32_t reletive; | |
| int32_t count; | |
| if (currententity->frame) | |
| { | |
| if (base->alternate_anims) | |
| base = base->alternate_anims; | |
| } | |
| if (!base->anim_total) | |
| return base; | |
| reletive = ((int32_t) (cl.time * 10)) % base->anim_total; | |
| count = 0; | |
| while ((base->anim_min > reletive) || (base->anim_max <= reletive)) | |
| { | |
| base = base->anim_next; | |
| if (!base) | |
| Sys_Error("R_TextureAnimation: broken cycle"); | |
| if ((++count) > 100) | |
| Sys_Error("R_TextureAnimation: infinite cycle"); | |
| } | |
| return base; | |
| } | |
| void R_DrawSurface(void) | |
| { | |
| unsigned char *basetptr; | |
| int32_t smax; | |
| int32_t tmax; | |
| int32_t twidth; | |
| int32_t u; | |
| int32_t soffset; | |
| int32_t basetoffset; | |
| int32_t texwidth; | |
| int32_t horzblockstep; | |
| unsigned char *pcolumndest; | |
| void (*pblockdrawer)(void); | |
| texture_t *mt; | |
| R_BuildLightMap(); | |
| surfrowbytes = r_drawsurf.rowbytes; | |
| mt = r_drawsurf.texture; | |
| r_source = ((uint8_t *) mt) + mt->offsets[r_drawsurf.surfmip]; | |
| texwidth = mt->width >> r_drawsurf.surfmip; | |
| blocksize = 16 >> r_drawsurf.surfmip; | |
| blockdivshift = 4 - r_drawsurf.surfmip; | |
| blockdivmask = (1 << blockdivshift) - 1; | |
| r_lightwidth = (r_drawsurf.surf->extents[0] >> 4) + 1; | |
| r_numhblocks = r_drawsurf.surfwidth >> blockdivshift; | |
| r_numvblocks = r_drawsurf.surfheight >> blockdivshift; | |
| if (r_pixbytes == 1) | |
| { | |
| pblockdrawer = surfmiptable[r_drawsurf.surfmip]; | |
| horzblockstep = blocksize; | |
| } | |
| else | |
| { | |
| pblockdrawer = R_DrawSurfaceBlock16; | |
| horzblockstep = blocksize << 1; | |
| } | |
| smax = mt->width >> r_drawsurf.surfmip; | |
| twidth = texwidth; | |
| tmax = mt->height >> r_drawsurf.surfmip; | |
| sourcetstep = texwidth; | |
| r_stepback = tmax * twidth; | |
| r_sourcemax = r_source + (tmax * smax); | |
| soffset = r_drawsurf.surf->texturemins[0]; | |
| basetoffset = r_drawsurf.surf->texturemins[1]; | |
| soffset = ((soffset >> r_drawsurf.surfmip) + (smax << 16)) % smax; | |
| basetptr = &r_source[(((basetoffset >> r_drawsurf.surfmip) + (tmax << 16)) % tmax) * twidth]; | |
| pcolumndest = r_drawsurf.surfdat; | |
| for (u = 0; u < r_numhblocks; u++) | |
| { | |
| r_lightptr = blocklights + u; | |
| prowdestbase = pcolumndest; | |
| pbasesource = basetptr + soffset; | |
| (*pblockdrawer)(); | |
| soffset = soffset + blocksize; | |
| if (soffset >= smax) | |
| soffset = 0; | |
| pcolumndest += horzblockstep; | |
| } | |
| } | |
| void R_DrawSurfaceBlock8_mip0(void) | |
| { | |
| int32_t v; | |
| int32_t i; | |
| int32_t b; | |
| int32_t lightstep; | |
| int32_t lighttemp; | |
| int32_t light; | |
| unsigned char pix; | |
| unsigned char *psource; | |
| unsigned char *prowdest; | |
| psource = pbasesource; | |
| prowdest = prowdestbase; | |
| for (v = 0; v < r_numvblocks; v++) | |
| { | |
| lightleft = r_lightptr[0]; | |
| lightright = r_lightptr[1]; | |
| r_lightptr += r_lightwidth; | |
| lightleftstep = (r_lightptr[0] - lightleft) >> 4; | |
| lightrightstep = (r_lightptr[1] - lightright) >> 4; | |
| for (i = 0; i < 16; i++) | |
| { | |
| lighttemp = lightleft - lightright; | |
| lightstep = lighttemp >> 4; | |
| light = lightright; | |
| for (b = 15; b >= 0; b--) | |
| { | |
| pix = psource[b]; | |
| prowdest[b] = ((unsigned char *) vid.colormap)[(light & 0xFF00) + pix]; | |
| light += lightstep; | |
| } | |
| psource += sourcetstep; | |
| lightright += lightrightstep; | |
| lightleft += lightleftstep; | |
| prowdest += surfrowbytes; | |
| } | |
| if (psource >= r_sourcemax) | |
| psource -= r_stepback; | |
| } | |
| } | |
| void R_DrawSurfaceBlock8_mip1(void) | |
| { | |
| int32_t v; | |
| int32_t i; | |
| int32_t b; | |
| int32_t lightstep; | |
| int32_t lighttemp; | |
| int32_t light; | |
| unsigned char pix; | |
| unsigned char *psource; | |
| unsigned char *prowdest; | |
| psource = pbasesource; | |
| prowdest = prowdestbase; | |
| for (v = 0; v < r_numvblocks; v++) | |
| { | |
| lightleft = r_lightptr[0]; | |
| lightright = r_lightptr[1]; | |
| r_lightptr += r_lightwidth; | |
| lightleftstep = (r_lightptr[0] - lightleft) >> 3; | |
| lightrightstep = (r_lightptr[1] - lightright) >> 3; | |
| for (i = 0; i < 8; i++) | |
| { | |
| lighttemp = lightleft - lightright; | |
| lightstep = lighttemp >> 3; | |
| light = lightright; | |
| for (b = 7; b >= 0; b--) | |
| { | |
| pix = psource[b]; | |
| prowdest[b] = ((unsigned char *) vid.colormap)[(light & 0xFF00) + pix]; | |
| light += lightstep; | |
| } | |
| psource += sourcetstep; | |
| lightright += lightrightstep; | |
| lightleft += lightleftstep; | |
| prowdest += surfrowbytes; | |
| } | |
| if (psource >= r_sourcemax) | |
| psource -= r_stepback; | |
| } | |
| } | |
| void R_DrawSurfaceBlock8_mip2(void) | |
| { | |
| int32_t v; | |
| int32_t i; | |
| int32_t b; | |
| int32_t lightstep; | |
| int32_t lighttemp; | |
| int32_t light; | |
| unsigned char pix; | |
| unsigned char *psource; | |
| unsigned char *prowdest; | |
| psource = pbasesource; | |
| prowdest = prowdestbase; | |
| for (v = 0; v < r_numvblocks; v++) | |
| { | |
| lightleft = r_lightptr[0]; | |
| lightright = r_lightptr[1]; | |
| r_lightptr += r_lightwidth; | |
| lightleftstep = (r_lightptr[0] - lightleft) >> 2; | |
| lightrightstep = (r_lightptr[1] - lightright) >> 2; | |
| for (i = 0; i < 4; i++) | |
| { | |
| lighttemp = lightleft - lightright; | |
| lightstep = lighttemp >> 2; | |
| light = lightright; | |
| for (b = 3; b >= 0; b--) | |
| { | |
| pix = psource[b]; | |
| prowdest[b] = ((unsigned char *) vid.colormap)[(light & 0xFF00) + pix]; | |
| light += lightstep; | |
| } | |
| psource += sourcetstep; | |
| lightright += lightrightstep; | |
| lightleft += lightleftstep; | |
| prowdest += surfrowbytes; | |
| } | |
| if (psource >= r_sourcemax) | |
| psource -= r_stepback; | |
| } | |
| } | |
| void R_DrawSurfaceBlock8_mip3(void) | |
| { | |
| int32_t v; | |
| int32_t i; | |
| int32_t b; | |
| int32_t lightstep; | |
| int32_t lighttemp; | |
| int32_t light; | |
| unsigned char pix; | |
| unsigned char *psource; | |
| unsigned char *prowdest; | |
| psource = pbasesource; | |
| prowdest = prowdestbase; | |
| for (v = 0; v < r_numvblocks; v++) | |
| { | |
| lightleft = r_lightptr[0]; | |
| lightright = r_lightptr[1]; | |
| r_lightptr += r_lightwidth; | |
| lightleftstep = (r_lightptr[0] - lightleft) >> 1; | |
| lightrightstep = (r_lightptr[1] - lightright) >> 1; | |
| for (i = 0; i < 2; i++) | |
| { | |
| lighttemp = lightleft - lightright; | |
| lightstep = lighttemp >> 1; | |
| light = lightright; | |
| for (b = 1; b >= 0; b--) | |
| { | |
| pix = psource[b]; | |
| prowdest[b] = ((unsigned char *) vid.colormap)[(light & 0xFF00) + pix]; | |
| light += lightstep; | |
| } | |
| psource += sourcetstep; | |
| lightright += lightrightstep; | |
| lightleft += lightleftstep; | |
| prowdest += surfrowbytes; | |
| } | |
| if (psource >= r_sourcemax) | |
| psource -= r_stepback; | |
| } | |
| } | |
| void R_DrawSurfaceBlock16(void) | |
| { | |
| int32_t k; | |
| unsigned char *psource; | |
| int32_t lighttemp; | |
| int32_t lightstep; | |
| int32_t light; | |
| uint16_t *prowdest; | |
| prowdest = (uint16_t *) prowdestbase; | |
| for (k = 0; k < blocksize; k++) | |
| { | |
| uint16_t *pdest; | |
| unsigned char pix; | |
| int32_t b; | |
| psource = pbasesource; | |
| lighttemp = lightright - lightleft; | |
| lightstep = lighttemp >> blockdivshift; | |
| light = lightleft; | |
| pdest = prowdest; | |
| for (b = 0; b < blocksize; b++) | |
| { | |
| pix = *psource; | |
| *pdest = vid.colormap16[(light & 0xFF00) + pix]; | |
| psource += sourcesstep; | |
| pdest++; | |
| light += lightstep; | |
| } | |
| pbasesource += sourcetstep; | |
| lightright += lightrightstep; | |
| lightleft += lightleftstep; | |
| prowdest = (uint16_t *) (((int32_t) prowdest) + surfrowbytes); | |
| } | |
| prowdestbase = prowdest; | |
| } | |
| void R_GenTurbTile(pixel_t *pbasetex, void *pdest) | |
| { | |
| int32_t *turb; | |
| int32_t i; | |
| int32_t j; | |
| int32_t s; | |
| int32_t t; | |
| uint8_t *pd; | |
| turb = sintable + (((int32_t) (cl.time * SPEED)) & (CYCLE - 1)); | |
| pd = (uint8_t *) pdest; | |
| for (i = 0; i < TILE_SIZE; i++) | |
| { | |
| for (j = 0; j < TILE_SIZE; j++) | |
| { | |
| s = (((j << 16) + turb[i & (CYCLE - 1)]) >> 16) & 63; | |
| t = (((i << 16) + turb[j & (CYCLE - 1)]) >> 16) & 63; | |
| *(pd++) = *((pbasetex + (t << 6)) + s); | |
| } | |
| } | |
| } | |
| void R_GenTurbTile16(pixel_t *pbasetex, void *pdest) | |
| { | |
| int32_t *turb; | |
| int32_t i; | |
| int32_t j; | |
| int32_t s; | |
| int32_t t; | |
| uint16_t *pd; | |
| turb = sintable + (((int32_t) (cl.time * SPEED)) & (CYCLE - 1)); | |
| pd = (uint16_t *) pdest; | |
| for (i = 0; i < TILE_SIZE; i++) | |
| { | |
| for (j = 0; j < TILE_SIZE; j++) | |
| { | |
| s = (((j << 16) + turb[i & (CYCLE - 1)]) >> 16) & 63; | |
| t = (((i << 16) + turb[j & (CYCLE - 1)]) >> 16) & 63; | |
| *(pd++) = d_8to16table[*((pbasetex + (t << 6)) + s)]; | |
| } | |
| } | |
| } | |
| void R_GenTile(msurface_t *psurf, void *pdest) | |
| { | |
| if (psurf->flags & SURF_DRAWTURB) | |
| { | |
| if (r_pixbytes == 1) | |
| { | |
| R_GenTurbTile((pixel_t *) (((uint8_t *) psurf->texinfo->texture) + psurf->texinfo->texture->offsets[0]), pdest); | |
| } | |
| else | |
| { | |
| R_GenTurbTile16((pixel_t *) (((uint8_t *) psurf->texinfo->texture) + psurf->texinfo->texture->offsets[0]), pdest); | |
| } | |
| } | |
| else | |
| if (psurf->flags & SURF_DRAWSKY) | |
| { | |
| if (r_pixbytes == 1) | |
| { | |
| R_GenSkyTile(pdest); | |
| } | |
| else | |
| { | |
| R_GenSkyTile16(pdest); | |
| } | |
| } | |
| else | |
| { | |
| Sys_Error("Unknown tile type"); | |
| } | |
| } | |
| void Sbar_ShowScores(void) | |
| { | |
| if (sb_showscores) | |
| return; | |
| sb_showscores = 1; | |
| sb_updates = 0; | |
| } | |
| void Sbar_DontShowScores(void) | |
| { | |
| sb_showscores = 0; | |
| sb_updates = 0; | |
| } | |
| void Sbar_Changed(void) | |
| { | |
| sb_updates = 0; | |
| } | |
| void Sbar_Init(void) | |
| { | |
| int32_t i; | |
| for (i = 0; i < 10; i++) | |
| { | |
| sb_nums[0][i] = Draw_PicFromWad(va("num_%i", i)); | |
| sb_nums[1][i] = Draw_PicFromWad(va("anum_%i", i)); | |
| } | |
| sb_nums[0][10] = Draw_PicFromWad("num_minus"); | |
| sb_nums[1][10] = Draw_PicFromWad("anum_minus"); | |
| sb_colon = Draw_PicFromWad("num_colon"); | |
| sb_slash = Draw_PicFromWad("num_slash"); | |
| sb_weapons[0][0] = Draw_PicFromWad("inv_shotgun"); | |
| sb_weapons[0][1] = Draw_PicFromWad("inv_sshotgun"); | |
| sb_weapons[0][2] = Draw_PicFromWad("inv_nailgun"); | |
| sb_weapons[0][3] = Draw_PicFromWad("inv_snailgun"); | |
| sb_weapons[0][4] = Draw_PicFromWad("inv_rlaunch"); | |
| sb_weapons[0][5] = Draw_PicFromWad("inv_srlaunch"); | |
| sb_weapons[0][6] = Draw_PicFromWad("inv_lightng"); | |
| sb_weapons[1][0] = Draw_PicFromWad("inv2_shotgun"); | |
| sb_weapons[1][1] = Draw_PicFromWad("inv2_sshotgun"); | |
| sb_weapons[1][2] = Draw_PicFromWad("inv2_nailgun"); | |
| sb_weapons[1][3] = Draw_PicFromWad("inv2_snailgun"); | |
| sb_weapons[1][4] = Draw_PicFromWad("inv2_rlaunch"); | |
| sb_weapons[1][5] = Draw_PicFromWad("inv2_srlaunch"); | |
| sb_weapons[1][6] = Draw_PicFromWad("inv2_lightng"); | |
| for (i = 0; i < 5; i++) | |
| { | |
| sb_weapons[2 + i][0] = Draw_PicFromWad(va("inva%i_shotgun", i + 1)); | |
| sb_weapons[2 + i][1] = Draw_PicFromWad(va("inva%i_sshotgun", i + 1)); | |
| sb_weapons[2 + i][2] = Draw_PicFromWad(va("inva%i_nailgun", i + 1)); | |
| sb_weapons[2 + i][3] = Draw_PicFromWad(va("inva%i_snailgun", i + 1)); | |
| sb_weapons[2 + i][4] = Draw_PicFromWad(va("inva%i_rlaunch", i + 1)); | |
| sb_weapons[2 + i][5] = Draw_PicFromWad(va("inva%i_srlaunch", i + 1)); | |
| sb_weapons[2 + i][6] = Draw_PicFromWad(va("inva%i_lightng", i + 1)); | |
| } | |
| sb_ammo[0] = Draw_PicFromWad("sb_shells"); | |
| sb_ammo[1] = Draw_PicFromWad("sb_nails"); | |
| sb_ammo[2] = Draw_PicFromWad("sb_rocket"); | |
| sb_ammo[3] = Draw_PicFromWad("sb_cells"); | |
| sb_armor[0] = Draw_PicFromWad("sb_armor1"); | |
| sb_armor[1] = Draw_PicFromWad("sb_armor2"); | |
| sb_armor[2] = Draw_PicFromWad("sb_armor3"); | |
| sb_items[0] = Draw_PicFromWad("sb_key1"); | |
| sb_items[1] = Draw_PicFromWad("sb_key2"); | |
| sb_items[2] = Draw_PicFromWad("sb_invis"); | |
| sb_items[3] = Draw_PicFromWad("sb_invuln"); | |
| sb_items[4] = Draw_PicFromWad("sb_suit"); | |
| sb_items[5] = Draw_PicFromWad("sb_quad"); | |
| sb_sigil[0] = Draw_PicFromWad("sb_sigil1"); | |
| sb_sigil[1] = Draw_PicFromWad("sb_sigil2"); | |
| sb_sigil[2] = Draw_PicFromWad("sb_sigil3"); | |
| sb_sigil[3] = Draw_PicFromWad("sb_sigil4"); | |
| sb_faces[4][0] = Draw_PicFromWad("face1"); | |
| sb_faces[4][1] = Draw_PicFromWad("face_p1"); | |
| sb_faces[3][0] = Draw_PicFromWad("face2"); | |
| sb_faces[3][1] = Draw_PicFromWad("face_p2"); | |
| sb_faces[2][0] = Draw_PicFromWad("face3"); | |
| sb_faces[2][1] = Draw_PicFromWad("face_p3"); | |
| sb_faces[1][0] = Draw_PicFromWad("face4"); | |
| sb_faces[1][1] = Draw_PicFromWad("face_p4"); | |
| sb_faces[0][0] = Draw_PicFromWad("face5"); | |
| sb_faces[0][1] = Draw_PicFromWad("face_p5"); | |
| sb_face_invis = Draw_PicFromWad("face_invis"); | |
| sb_face_invuln = Draw_PicFromWad("face_invul2"); | |
| sb_face_invis_invuln = Draw_PicFromWad("face_inv2"); | |
| sb_face_quad = Draw_PicFromWad("face_quad"); | |
| Cmd_AddCommand("+showscores", Sbar_ShowScores); | |
| Cmd_AddCommand("-showscores", Sbar_DontShowScores); | |
| sb_sbar = Draw_PicFromWad("sbar"); | |
| sb_ibar = Draw_PicFromWad("ibar"); | |
| sb_scorebar = Draw_PicFromWad("scorebar"); | |
| if (hipnotic) | |
| { | |
| hsb_weapons[0][0] = Draw_PicFromWad("inv_laser"); | |
| hsb_weapons[0][1] = Draw_PicFromWad("inv_mjolnir"); | |
| hsb_weapons[0][2] = Draw_PicFromWad("inv_gren_prox"); | |
| hsb_weapons[0][3] = Draw_PicFromWad("inv_prox_gren"); | |
| hsb_weapons[0][4] = Draw_PicFromWad("inv_prox"); | |
| hsb_weapons[1][0] = Draw_PicFromWad("inv2_laser"); | |
| hsb_weapons[1][1] = Draw_PicFromWad("inv2_mjolnir"); | |
| hsb_weapons[1][2] = Draw_PicFromWad("inv2_gren_prox"); | |
| hsb_weapons[1][3] = Draw_PicFromWad("inv2_prox_gren"); | |
| hsb_weapons[1][4] = Draw_PicFromWad("inv2_prox"); | |
| for (i = 0; i < 5; i++) | |
| { | |
| hsb_weapons[2 + i][0] = Draw_PicFromWad(va("inva%i_laser", i + 1)); | |
| hsb_weapons[2 + i][1] = Draw_PicFromWad(va("inva%i_mjolnir", i + 1)); | |
| hsb_weapons[2 + i][2] = Draw_PicFromWad(va("inva%i_gren_prox", i + 1)); | |
| hsb_weapons[2 + i][3] = Draw_PicFromWad(va("inva%i_prox_gren", i + 1)); | |
| hsb_weapons[2 + i][4] = Draw_PicFromWad(va("inva%i_prox", i + 1)); | |
| } | |
| hsb_items[0] = Draw_PicFromWad("sb_wsuit"); | |
| hsb_items[1] = Draw_PicFromWad("sb_eshld"); | |
| } | |
| if (rogue) | |
| { | |
| rsb_invbar[0] = Draw_PicFromWad("r_invbar1"); | |
| rsb_invbar[1] = Draw_PicFromWad("r_invbar2"); | |
| rsb_weapons[0] = Draw_PicFromWad("r_lava"); | |
| rsb_weapons[1] = Draw_PicFromWad("r_superlava"); | |
| rsb_weapons[2] = Draw_PicFromWad("r_gren"); | |
| rsb_weapons[3] = Draw_PicFromWad("r_multirock"); | |
| rsb_weapons[4] = Draw_PicFromWad("r_plasma"); | |
| rsb_items[0] = Draw_PicFromWad("r_shield1"); | |
| rsb_items[1] = Draw_PicFromWad("r_agrav1"); | |
| rsb_teambord = Draw_PicFromWad("r_teambord"); | |
| rsb_ammo[0] = Draw_PicFromWad("r_ammolava"); | |
| rsb_ammo[1] = Draw_PicFromWad("r_ammomulti"); | |
| rsb_ammo[2] = Draw_PicFromWad("r_ammoplasma"); | |
| } | |
| } | |
| void Sbar_DrawPic(int32_t x, int32_t y, qpic_t *pic) | |
| { | |
| if (cl.gametype == GAME_DEATHMATCH) | |
| Draw_Pic(x, y + (vid.height - SBAR_HEIGHT), pic); | |
| else | |
| Draw_Pic(x + ((vid.width - 320) >> 1), y + (vid.height - SBAR_HEIGHT), pic); | |
| } | |
| void Sbar_DrawTransPic(int32_t x, int32_t y, qpic_t *pic) | |
| { | |
| if (cl.gametype == GAME_DEATHMATCH) | |
| Draw_TransPic(x, y + (vid.height - SBAR_HEIGHT), pic); | |
| else | |
| Draw_TransPic(x + ((vid.width - 320) >> 1), y + (vid.height - SBAR_HEIGHT), pic); | |
| } | |
| void Sbar_DrawCharacter(int32_t x, int32_t y, int32_t num) | |
| { | |
| if (cl.gametype == GAME_DEATHMATCH) | |
| Draw_Character(x + 4, (y + vid.height) - SBAR_HEIGHT, num); | |
| else | |
| Draw_Character((x + ((vid.width - 320) >> 1)) + 4, (y + vid.height) - SBAR_HEIGHT, num); | |
| } | |
| void Sbar_DrawString(int32_t x, int32_t y, char *str) | |
| { | |
| if (cl.gametype == GAME_DEATHMATCH) | |
| Draw_String(x, (y + vid.height) - SBAR_HEIGHT, str); | |
| else | |
| Draw_String(x + ((vid.width - 320) >> 1), (y + vid.height) - SBAR_HEIGHT, str); | |
| } | |
| int32_t Sbar_itoa(int32_t num, char *buf) | |
| { | |
| char *str; | |
| int32_t pow10; | |
| int32_t dig; | |
| str = buf; | |
| if (num < 0) | |
| { | |
| *(str++) = '-'; | |
| num = -num; | |
| } | |
| for (pow10 = 10; num >= pow10; pow10 *= 10) | |
| ; | |
| do | |
| { | |
| pow10 /= 10; | |
| dig = num / pow10; | |
| *(str++) = '0' + dig; | |
| num -= dig * pow10; | |
| } | |
| while (pow10 != 1); | |
| *str = 0; | |
| return str - buf; | |
| } | |
| void Sbar_DrawNum(int32_t x, int32_t y, int32_t num, int32_t digits, int32_t color) | |
| { | |
| char str[12]; | |
| char *ptr; | |
| int32_t l; | |
| int32_t frame; | |
| l = Sbar_itoa(num, str); | |
| ptr = str; | |
| if (l > digits) | |
| ptr += l - digits; | |
| if (l < digits) | |
| x += (digits - l) * 24; | |
| while (*ptr) | |
| { | |
| if ((*ptr) == '-') | |
| frame = STAT_MINUS; | |
| else | |
| frame = (*ptr) - '0'; | |
| Sbar_DrawTransPic(x, y, sb_nums[color][frame]); | |
| x += 24; | |
| ptr++; | |
| } | |
| } | |
| void Sbar_SortFrags(void) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| int32_t k; | |
| scoreboardlines = 0; | |
| for (i = 0; i < cl.maxclients; i++) | |
| { | |
| if (cl.scores[i].name[0]) | |
| { | |
| fragsort[scoreboardlines] = i; | |
| scoreboardlines++; | |
| } | |
| } | |
| for (i = 0; i < scoreboardlines; i++) | |
| for (j = 0; j < ((scoreboardlines - 1) - i); j++) | |
| if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j + 1]].frags) | |
| { | |
| k = fragsort[j]; | |
| fragsort[j] = fragsort[j + 1]; | |
| fragsort[j + 1] = k; | |
| } | |
| } | |
| int32_t Sbar_ColorForMap(int32_t m) | |
| { | |
| return (m < 128) ? (m + 8) : (m + 8); | |
| } | |
| void Sbar_UpdateScoreboard(void) | |
| { | |
| int32_t i; | |
| int32_t k; | |
| int32_t top; | |
| int32_t bottom; | |
| scoreboard_t *s; | |
| Sbar_SortFrags(); | |
| memset(scoreboardtext, 0, sizeof(scoreboardtext)); | |
| for (i = 0; i < scoreboardlines; i++) | |
| { | |
| k = fragsort[i]; | |
| s = &cl.scores[k]; | |
| sprintf(&scoreboardtext[i][1], "%3i %s", s->frags, s->name); | |
| top = s->colors & 0xf0; | |
| bottom = (s->colors & 15) << 4; | |
| scoreboardtop[i] = Sbar_ColorForMap(top); | |
| scoreboardbottom[i] = Sbar_ColorForMap(bottom); | |
| } | |
| } | |
| void Sbar_SoloScoreboard(void) | |
| { | |
| char str[80]; | |
| int32_t minutes; | |
| int32_t seconds; | |
| int32_t tens; | |
| int32_t units; | |
| int32_t l; | |
| sprintf(str, "Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]); | |
| Sbar_DrawString(8, 4, str); | |
| sprintf(str, "Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]); | |
| Sbar_DrawString(8, 12, str); | |
| minutes = cl.time / 60; | |
| seconds = cl.time - (60 * minutes); | |
| tens = seconds / 10; | |
| units = seconds - (10 * tens); | |
| sprintf(str, "Time :%3i:%i%i", minutes, tens, units); | |
| Sbar_DrawString(184, 4, str); | |
| l = strlen(cl.levelname); | |
| Sbar_DrawString(232 - (l * 4), 12, cl.levelname); | |
| } | |
| void Sbar_DrawScoreboard(void) | |
| { | |
| Sbar_SoloScoreboard(); | |
| if (cl.gametype == GAME_DEATHMATCH) | |
| Sbar_DeathmatchOverlay(); | |
| } | |
| void Sbar_DrawInventory(void) | |
| { | |
| int32_t i; | |
| char num[6]; | |
| float time; | |
| int32_t flashon; | |
| if (rogue) | |
| { | |
| if (cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN) | |
| Sbar_DrawPic(0, -24, rsb_invbar[0]); | |
| else | |
| Sbar_DrawPic(0, -24, rsb_invbar[1]); | |
| } | |
| else | |
| { | |
| Sbar_DrawPic(0, -24, sb_ibar); | |
| } | |
| for (i = 0; i < 7; i++) | |
| { | |
| if (cl.items & (IT_SHOTGUN << i)) | |
| { | |
| time = cl.item_gettime[i]; | |
| flashon = (int32_t) ((cl.time - time) * 10); | |
| if (flashon >= 10) | |
| { | |
| if (cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN << i)) | |
| flashon = 1; | |
| else | |
| flashon = 0; | |
| } | |
| else | |
| flashon = (flashon % 5) + 2; | |
| Sbar_DrawPic(i * 24, -16, sb_weapons[flashon][i]); | |
| if (flashon > 1) | |
| sb_updates = 0; | |
| } | |
| } | |
| if (hipnotic) | |
| { | |
| int32_t grenadeflashing = 0; | |
| for (i = 0; i < 4; i++) | |
| { | |
| if (cl.items & (1 << hipweapons[i])) | |
| { | |
| time = cl.item_gettime[hipweapons[i]]; | |
| flashon = (int32_t) ((cl.time - time) * 10); | |
| if (flashon >= 10) | |
| { | |
| if (cl.stats[STAT_ACTIVEWEAPON] == (1 << hipweapons[i])) | |
| flashon = 1; | |
| else | |
| flashon = 0; | |
| } | |
| else | |
| flashon = (flashon % 5) + 2; | |
| if (i == 2) | |
| { | |
| if (cl.items & HIT_PROXIMITY_GUN) | |
| { | |
| if (flashon) | |
| { | |
| grenadeflashing = 1; | |
| Sbar_DrawPic(96, -16, hsb_weapons[flashon][2]); | |
| } | |
| } | |
| } | |
| else | |
| if (i == 3) | |
| { | |
| if (cl.items & (IT_SHOTGUN << 4)) | |
| { | |
| if (flashon && (!grenadeflashing)) | |
| { | |
| Sbar_DrawPic(96, -16, hsb_weapons[flashon][3]); | |
| } | |
| else | |
| if (!grenadeflashing) | |
| { | |
| Sbar_DrawPic(96, -16, hsb_weapons[0][3]); | |
| } | |
| } | |
| else | |
| Sbar_DrawPic(96, -16, hsb_weapons[flashon][4]); | |
| } | |
| else | |
| Sbar_DrawPic(176 + (i * 24), -16, hsb_weapons[flashon][i]); | |
| if (flashon > 1) | |
| sb_updates = 0; | |
| } | |
| } | |
| } | |
| if (rogue) | |
| { | |
| if (cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN) | |
| { | |
| for (i = 0; i < 5; i++) | |
| { | |
| if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i)) | |
| { | |
| Sbar_DrawPic((i + 2) * 24, -16, rsb_weapons[i]); | |
| } | |
| } | |
| } | |
| } | |
| for (i = 0; i < 4; i++) | |
| { | |
| sprintf(num, "%3i", cl.stats[STAT_SHELLS + i]); | |
| if (num[0] != ' ') | |
| Sbar_DrawCharacter((((6 * i) + 1) * 8) - 2, -24, (18 + num[0]) - '0'); | |
| if (num[1] != ' ') | |
| Sbar_DrawCharacter((((6 * i) + 2) * 8) - 2, -24, (18 + num[1]) - '0'); | |
| if (num[2] != ' ') | |
| Sbar_DrawCharacter((((6 * i) + 3) * 8) - 2, -24, (18 + num[2]) - '0'); | |
| } | |
| flashon = 0; | |
| for (i = 0; i < 6; i++) | |
| if (cl.items & (1 << (17 + i))) | |
| { | |
| time = cl.item_gettime[17 + i]; | |
| if ((time && (time > (cl.time - 2))) && flashon) | |
| { | |
| sb_updates = 0; | |
| } | |
| else | |
| { | |
| if ((!hipnotic) || (i > 1)) | |
| { | |
| Sbar_DrawPic(192 + (i * 16), -16, sb_items[i]); | |
| } | |
| } | |
| if (time && (time > (cl.time - 2))) | |
| sb_updates = 0; | |
| } | |
| if (hipnotic) | |
| { | |
| for (i = 0; i < 2; i++) | |
| if (cl.items & (1 << (24 + i))) | |
| { | |
| time = cl.item_gettime[24 + i]; | |
| if ((time && (time > (cl.time - 2))) && flashon) | |
| { | |
| sb_updates = 0; | |
| } | |
| else | |
| { | |
| Sbar_DrawPic(288 + (i * 16), -16, hsb_items[i]); | |
| } | |
| if (time && (time > (cl.time - 2))) | |
| sb_updates = 0; | |
| } | |
| } | |
| if (rogue) | |
| { | |
| for (i = 0; i < 2; i++) | |
| { | |
| if (cl.items & (1 << (29 + i))) | |
| { | |
| time = cl.item_gettime[29 + i]; | |
| if ((time && (time > (cl.time - 2))) && flashon) | |
| { | |
| sb_updates = 0; | |
| } | |
| else | |
| { | |
| Sbar_DrawPic(288 + (i * 16), -16, rsb_items[i]); | |
| } | |
| if (time && (time > (cl.time - 2))) | |
| sb_updates = 0; | |
| } | |
| } | |
| } | |
| else | |
| { | |
| for (i = 0; i < 4; i++) | |
| { | |
| if (cl.items & (1 << (28 + i))) | |
| { | |
| time = cl.item_gettime[28 + i]; | |
| if ((time && (time > (cl.time - 2))) && flashon) | |
| { | |
| sb_updates = 0; | |
| } | |
| else | |
| Sbar_DrawPic((320 - 32) + (i * 8), -16, sb_sigil[i]); | |
| if (time && (time > (cl.time - 2))) | |
| sb_updates = 0; | |
| } | |
| } | |
| } | |
| } | |
| void Sbar_DrawFrags(void) | |
| { | |
| int32_t i; | |
| int32_t k; | |
| int32_t l; | |
| int32_t top; | |
| int32_t bottom; | |
| int32_t x; | |
| int32_t y; | |
| int32_t f; | |
| int32_t xofs; | |
| char num[12]; | |
| scoreboard_t *s; | |
| Sbar_SortFrags(); | |
| l = (scoreboardlines <= 4) ? (scoreboardlines) : (4); | |
| x = 23; | |
| if (cl.gametype == GAME_DEATHMATCH) | |
| xofs = 0; | |
| else | |
| xofs = (vid.width - 320) >> 1; | |
| y = (vid.height - SBAR_HEIGHT) - 23; | |
| for (i = 0; i < l; i++) | |
| { | |
| k = fragsort[i]; | |
| s = &cl.scores[k]; | |
| if (!s->name[0]) | |
| continue; | |
| top = s->colors & 0xf0; | |
| bottom = (s->colors & 15) << 4; | |
| top = Sbar_ColorForMap(top); | |
| bottom = Sbar_ColorForMap(bottom); | |
| Draw_Fill((xofs + (x * 8)) + 10, y, 28, 4, top); | |
| Draw_Fill((xofs + (x * 8)) + 10, y + 4, 28, 3, bottom); | |
| f = s->frags; | |
| sprintf(num, "%3i", f); | |
| Sbar_DrawCharacter((x + 1) * 8, -24, num[0]); | |
| Sbar_DrawCharacter((x + 2) * 8, -24, num[1]); | |
| Sbar_DrawCharacter((x + 3) * 8, -24, num[2]); | |
| if (k == (cl.viewentity - 1)) | |
| { | |
| Sbar_DrawCharacter((x * 8) + 2, -24, 16); | |
| Sbar_DrawCharacter(((x + 4) * 8) - 4, -24, 17); | |
| } | |
| x += 4; | |
| } | |
| } | |
| void Sbar_DrawFace(void) | |
| { | |
| int32_t f; | |
| int32_t anim; | |
| if (((rogue && (cl.maxclients != 1)) && (teamplay.value > 3)) && (teamplay.value < 7)) | |
| { | |
| int32_t top; | |
| int32_t bottom; | |
| int32_t xofs; | |
| char num[12]; | |
| scoreboard_t *s; | |
| s = &cl.scores[cl.viewentity - 1]; | |
| top = s->colors & 0xf0; | |
| bottom = (s->colors & 15) << 4; | |
| top = Sbar_ColorForMap(top); | |
| bottom = Sbar_ColorForMap(bottom); | |
| if (cl.gametype == GAME_DEATHMATCH) | |
| xofs = 113; | |
| else | |
| xofs = ((vid.width - 320) >> 1) + 113; | |
| Sbar_DrawPic(112, 0, rsb_teambord); | |
| Draw_Fill(xofs, (vid.height - SBAR_HEIGHT) + 3, 22, 9, top); | |
| Draw_Fill(xofs, (vid.height - SBAR_HEIGHT) + 12, 22, 9, bottom); | |
| f = s->frags; | |
| sprintf(num, "%3i", f); | |
| if (top == 8) | |
| { | |
| if (num[0] != ' ') | |
| Sbar_DrawCharacter(109, 3, (18 + num[0]) - '0'); | |
| if (num[1] != ' ') | |
| Sbar_DrawCharacter(116, 3, (18 + num[1]) - '0'); | |
| if (num[2] != ' ') | |
| Sbar_DrawCharacter(123, 3, (18 + num[2]) - '0'); | |
| } | |
| else | |
| { | |
| Sbar_DrawCharacter(109, 3, num[0]); | |
| Sbar_DrawCharacter(116, 3, num[1]); | |
| Sbar_DrawCharacter(123, 3, num[2]); | |
| } | |
| return; | |
| } | |
| if ((cl.items & (IT_INVISIBILITY | IT_INVULNERABILITY)) == (IT_INVISIBILITY | IT_INVULNERABILITY)) | |
| { | |
| Sbar_DrawPic(112, 0, sb_face_invis_invuln); | |
| return; | |
| } | |
| if (cl.items & IT_QUAD) | |
| { | |
| Sbar_DrawPic(112, 0, sb_face_quad); | |
| return; | |
| } | |
| if (cl.items & IT_INVISIBILITY) | |
| { | |
| Sbar_DrawPic(112, 0, sb_face_invis); | |
| return; | |
| } | |
| if (cl.items & IT_INVULNERABILITY) | |
| { | |
| Sbar_DrawPic(112, 0, sb_face_invuln); | |
| return; | |
| } | |
| if (cl.stats[STAT_HEALTH] >= 100) | |
| f = 4; | |
| else | |
| f = cl.stats[STAT_HEALTH] / 20; | |
| if (cl.time <= cl.faceanimtime) | |
| { | |
| anim = 1; | |
| sb_updates = 0; | |
| } | |
| else | |
| anim = 0; | |
| Sbar_DrawPic(112, 0, sb_faces[f][anim]); | |
| } | |
| void Sbar_Draw(void) | |
| { | |
| if (scr_con_current == vid.height) | |
| return; | |
| if (sb_updates >= vid.numpages) | |
| return; | |
| scr_copyeverything = 1; | |
| sb_updates++; | |
| if (sb_lines && (vid.width > 320)) | |
| Draw_TileClear(0, vid.height - sb_lines, vid.width, sb_lines); | |
| if (sb_lines > 24) | |
| { | |
| Sbar_DrawInventory(); | |
| if (cl.maxclients != 1) | |
| Sbar_DrawFrags(); | |
| } | |
| if (sb_showscores || (cl.stats[STAT_HEALTH] <= 0)) | |
| { | |
| Sbar_DrawPic(0, 0, sb_scorebar); | |
| Sbar_DrawScoreboard(); | |
| sb_updates = 0; | |
| } | |
| else | |
| if (sb_lines) | |
| { | |
| Sbar_DrawPic(0, 0, sb_sbar); | |
| if (hipnotic) | |
| { | |
| if (cl.items & IT_KEY1) | |
| Sbar_DrawPic(209, 3, sb_items[0]); | |
| if (cl.items & IT_KEY2) | |
| Sbar_DrawPic(209, 12, sb_items[1]); | |
| } | |
| if (cl.items & IT_INVULNERABILITY) | |
| { | |
| Sbar_DrawNum(24, 0, 666, 3, 1); | |
| Sbar_DrawPic(0, 0, draw_disc); | |
| } | |
| else | |
| { | |
| if (rogue) | |
| { | |
| Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25); | |
| if (cl.items & RIT_ARMOR3) | |
| Sbar_DrawPic(0, 0, sb_armor[2]); | |
| else | |
| if (cl.items & RIT_ARMOR2) | |
| Sbar_DrawPic(0, 0, sb_armor[1]); | |
| else | |
| if (cl.items & RIT_ARMOR1) | |
| Sbar_DrawPic(0, 0, sb_armor[0]); | |
| } | |
| else | |
| { | |
| Sbar_DrawNum(24, 0, cl.stats[STAT_ARMOR], 3, cl.stats[STAT_ARMOR] <= 25); | |
| if (cl.items & IT_ARMOR3) | |
| Sbar_DrawPic(0, 0, sb_armor[2]); | |
| else | |
| if (cl.items & IT_ARMOR2) | |
| Sbar_DrawPic(0, 0, sb_armor[1]); | |
| else | |
| if (cl.items & IT_ARMOR1) | |
| Sbar_DrawPic(0, 0, sb_armor[0]); | |
| } | |
| } | |
| Sbar_DrawFace(); | |
| Sbar_DrawNum(136, 0, cl.stats[STAT_HEALTH], 3, cl.stats[STAT_HEALTH] <= 25); | |
| if (rogue) | |
| { | |
| if (cl.items & RIT_SHELLS) | |
| Sbar_DrawPic(224, 0, sb_ammo[0]); | |
| else | |
| if (cl.items & RIT_NAILS) | |
| Sbar_DrawPic(224, 0, sb_ammo[1]); | |
| else | |
| if (cl.items & RIT_ROCKETS) | |
| Sbar_DrawPic(224, 0, sb_ammo[2]); | |
| else | |
| if (cl.items & RIT_CELLS) | |
| Sbar_DrawPic(224, 0, sb_ammo[3]); | |
| else | |
| if (cl.items & RIT_LAVA_NAILS) | |
| Sbar_DrawPic(224, 0, rsb_ammo[0]); | |
| else | |
| if (cl.items & RIT_PLASMA_AMMO) | |
| Sbar_DrawPic(224, 0, rsb_ammo[1]); | |
| else | |
| if (cl.items & RIT_MULTI_ROCKETS) | |
| Sbar_DrawPic(224, 0, rsb_ammo[2]); | |
| } | |
| else | |
| { | |
| if (cl.items & IT_SHELLS) | |
| Sbar_DrawPic(224, 0, sb_ammo[0]); | |
| else | |
| if (cl.items & IT_NAILS) | |
| Sbar_DrawPic(224, 0, sb_ammo[1]); | |
| else | |
| if (cl.items & IT_ROCKETS) | |
| Sbar_DrawPic(224, 0, sb_ammo[2]); | |
| else | |
| if (cl.items & IT_CELLS) | |
| Sbar_DrawPic(224, 0, sb_ammo[3]); | |
| } | |
| Sbar_DrawNum(248, 0, cl.stats[STAT_AMMO], 3, cl.stats[STAT_AMMO] <= 10); | |
| } | |
| if (vid.width > 320) | |
| { | |
| if (cl.gametype == GAME_DEATHMATCH) | |
| Sbar_MiniDeathmatchOverlay(); | |
| } | |
| } | |
| void Sbar_IntermissionNumber(int32_t x, int32_t y, int32_t num, int32_t digits, int32_t color) | |
| { | |
| char str[12]; | |
| char *ptr; | |
| int32_t l; | |
| int32_t frame; | |
| l = Sbar_itoa(num, str); | |
| ptr = str; | |
| if (l > digits) | |
| ptr += l - digits; | |
| if (l < digits) | |
| x += (digits - l) * 24; | |
| while (*ptr) | |
| { | |
| if ((*ptr) == '-') | |
| frame = STAT_MINUS; | |
| else | |
| frame = (*ptr) - '0'; | |
| Draw_TransPic(x, y, sb_nums[color][frame]); | |
| x += 24; | |
| ptr++; | |
| } | |
| } | |
| void Sbar_DeathmatchOverlay(void) | |
| { | |
| qpic_t *pic; | |
| int32_t i; | |
| int32_t k; | |
| int32_t l; | |
| int32_t top; | |
| int32_t bottom; | |
| int32_t x; | |
| int32_t y; | |
| int32_t f; | |
| char num[12]; | |
| scoreboard_t *s; | |
| scr_copyeverything = 1; | |
| scr_fullupdate = 0; | |
| pic = Draw_CachePic("gfx/ranking.lmp"); | |
| M_DrawPic((320 - pic->width) / 2, 8, pic); | |
| Sbar_SortFrags(); | |
| l = scoreboardlines; | |
| x = 80 + ((vid.width - 320) >> 1); | |
| y = 40; | |
| for (i = 0; i < l; i++) | |
| { | |
| k = fragsort[i]; | |
| s = &cl.scores[k]; | |
| if (!s->name[0]) | |
| continue; | |
| top = s->colors & 0xf0; | |
| bottom = (s->colors & 15) << 4; | |
| top = Sbar_ColorForMap(top); | |
| bottom = Sbar_ColorForMap(bottom); | |
| Draw_Fill(x, y, 40, 4, top); | |
| Draw_Fill(x, y + 4, 40, 4, bottom); | |
| f = s->frags; | |
| sprintf(num, "%3i", f); | |
| Draw_Character(x + 8, y, num[0]); | |
| Draw_Character(x + 16, y, num[1]); | |
| Draw_Character(x + 24, y, num[2]); | |
| if (k == (cl.viewentity - 1)) | |
| Draw_Character(x - 8, y, 12); | |
| Draw_String(x + 64, y, s->name); | |
| y += 10; | |
| } | |
| } | |
| void Sbar_MiniDeathmatchOverlay(void) | |
| { | |
| qpic_t *pic; | |
| int32_t i; | |
| int32_t k; | |
| int32_t l; | |
| int32_t top; | |
| int32_t bottom; | |
| int32_t x; | |
| int32_t y; | |
| int32_t f; | |
| char num[12]; | |
| scoreboard_t *s; | |
| int32_t numlines; | |
| if ((vid.width < 512) || (!sb_lines)) | |
| return; | |
| scr_copyeverything = 1; | |
| scr_fullupdate = 0; | |
| Sbar_SortFrags(); | |
| l = scoreboardlines; | |
| y = vid.height - sb_lines; | |
| numlines = sb_lines / 8; | |
| if (numlines < 3) | |
| return; | |
| for (i = 0; i < scoreboardlines; i++) | |
| if (fragsort[i] == (cl.viewentity - 1)) | |
| break; | |
| if (i == scoreboardlines) | |
| i = 0; | |
| else | |
| i = i - (numlines / 2); | |
| if (i > (scoreboardlines - numlines)) | |
| i = scoreboardlines - numlines; | |
| if (i < 0) | |
| i = 0; | |
| x = 324; | |
| for (; (i < scoreboardlines) && (y < (vid.height - 8)); i++) | |
| { | |
| k = fragsort[i]; | |
| s = &cl.scores[k]; | |
| if (!s->name[0]) | |
| continue; | |
| top = s->colors & 0xf0; | |
| bottom = (s->colors & 15) << 4; | |
| top = Sbar_ColorForMap(top); | |
| bottom = Sbar_ColorForMap(bottom); | |
| Draw_Fill(x, y + 1, 40, 3, top); | |
| Draw_Fill(x, y + 4, 40, 4, bottom); | |
| f = s->frags; | |
| sprintf(num, "%3i", f); | |
| Draw_Character(x + 8, y, num[0]); | |
| Draw_Character(x + 16, y, num[1]); | |
| Draw_Character(x + 24, y, num[2]); | |
| if (k == (cl.viewentity - 1)) | |
| { | |
| Draw_Character(x, y, 16); | |
| Draw_Character(x + 32, y, 17); | |
| } | |
| Draw_String(x + 48, y, s->name); | |
| y += 8; | |
| } | |
| } | |
| void Sbar_IntermissionOverlay(void) | |
| { | |
| qpic_t *pic; | |
| int32_t dig; | |
| int32_t num; | |
| scr_copyeverything = 1; | |
| scr_fullupdate = 0; | |
| if (cl.gametype == GAME_DEATHMATCH) | |
| { | |
| Sbar_DeathmatchOverlay(); | |
| return; | |
| } | |
| pic = Draw_CachePic("gfx/complete.lmp"); | |
| Draw_Pic(64, 24, pic); | |
| pic = Draw_CachePic("gfx/inter.lmp"); | |
| Draw_TransPic(0, 56, pic); | |
| dig = cl.completed_time / 60; | |
| Sbar_IntermissionNumber(160, 64, dig, 3, 0); | |
| num = cl.completed_time - (dig * 60); | |
| Draw_TransPic(234, 64, sb_colon); | |
| Draw_TransPic(246, 64, sb_nums[0][num / 10]); | |
| Draw_TransPic(266, 64, sb_nums[0][num % 10]); | |
| Sbar_IntermissionNumber(160, 104, cl.stats[STAT_SECRETS], 3, 0); | |
| Draw_TransPic(232, 104, sb_slash); | |
| Sbar_IntermissionNumber(240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0); | |
| Sbar_IntermissionNumber(160, 144, cl.stats[STAT_MONSTERS], 3, 0); | |
| Draw_TransPic(232, 144, sb_slash); | |
| Sbar_IntermissionNumber(240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0); | |
| } | |
| void Sbar_FinaleOverlay(void) | |
| { | |
| qpic_t *pic; | |
| scr_copyeverything = 1; | |
| pic = Draw_CachePic("gfx/finale.lmp"); | |
| Draw_TransPic((vid.width - pic->width) / 2, 16, pic); | |
| } | |
| void SCR_CenterPrint(char *str) | |
| { | |
| strncpy(scr_centerstring, str, (sizeof(scr_centerstring)) - 1); | |
| scr_centertime_off = scr_centertime.value; | |
| scr_centertime_start = cl.time; | |
| scr_center_lines = 1; | |
| while (*str) | |
| { | |
| if ((*str) == '\n') | |
| scr_center_lines++; | |
| str++; | |
| } | |
| } | |
| void SCR_EraseCenterString(void) | |
| { | |
| int32_t y; | |
| if ((scr_erase_center++) > vid.numpages) | |
| { | |
| scr_erase_lines = 0; | |
| return; | |
| } | |
| if (scr_center_lines <= 4) | |
| y = vid.height * 0.35; | |
| else | |
| y = 48; | |
| scr_copytop = 1; | |
| Draw_TileClear(0, y, vid.width, 8 * scr_erase_lines); | |
| } | |
| void SCR_DrawCenterString(void) | |
| { | |
| char *start; | |
| int32_t l; | |
| int32_t j; | |
| int32_t x; | |
| int32_t y; | |
| int32_t remaining; | |
| if (cl.intermission) | |
| remaining = scr_printspeed.value * (cl.time - scr_centertime_start); | |
| else | |
| remaining = 9999; | |
| scr_erase_center = 0; | |
| start = scr_centerstring; | |
| if (scr_center_lines <= 4) | |
| y = vid.height * 0.35; | |
| else | |
| y = 48; | |
| do | |
| { | |
| for (l = 0; l < 40; l++) | |
| if ((start[l] == '\n') || (!start[l])) | |
| break; | |
| x = (vid.width - (l * 8)) / 2; | |
| for (j = 0; j < l; j++, x += 8) | |
| { | |
| Draw_Character(x, y, start[j]); | |
| if (!(remaining--)) | |
| return; | |
| } | |
| y += 8; | |
| while ((*start) && ((*start) != '\n')) | |
| start++; | |
| if (!(*start)) | |
| break; | |
| start++; | |
| } | |
| while (1); | |
| } | |
| void SCR_CheckDrawCenterString(void) | |
| { | |
| scr_copytop = 1; | |
| if (scr_center_lines > scr_erase_lines) | |
| scr_erase_lines = scr_center_lines; | |
| scr_centertime_off -= host_frametime; | |
| if ((scr_centertime_off <= 0) && (!cl.intermission)) | |
| return; | |
| if (key_dest != key_game) | |
| return; | |
| SCR_DrawCenterString(); | |
| } | |
| float CalcFov(float fov_x, float width, float height) | |
| { | |
| float a; | |
| float x; | |
| if ((fov_x < 1) || (fov_x > 179)) | |
| Sys_Error("Bad fov: %f", fov_x); | |
| x = width / tan((fov_x / 360) * M_PI); | |
| a = atan(height / x); | |
| a = (a * 360) / M_PI; | |
| return a; | |
| } | |
| static void SCR_CalcRefdef(void) | |
| { | |
| vrect_t vrect; | |
| float size; | |
| scr_fullupdate = 0; | |
| vid.recalc_refdef = 0; | |
| Sbar_Changed(); | |
| if (scr_viewsize.value < 30) | |
| Cvar_Set("viewsize", "30"); | |
| if (scr_viewsize.value > 120) | |
| Cvar_Set("viewsize", "120"); | |
| if (scr_fov.value < 10) | |
| Cvar_Set("fov", "10"); | |
| if (scr_fov.value > 170) | |
| Cvar_Set("fov", "170"); | |
| r_refdef.fov_x = scr_fov.value; | |
| r_refdef.fov_y = CalcFov(r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height); | |
| if (cl.intermission) | |
| size = 120; | |
| else | |
| size = scr_viewsize.value; | |
| if (size >= 120) | |
| sb_lines = 0; | |
| else | |
| if (size >= 110) | |
| sb_lines = 24; | |
| else | |
| sb_lines = (24 + 16) + 8; | |
| vrect.x = 0; | |
| vrect.y = 0; | |
| vrect.width = vid.width; | |
| vrect.height = vid.height; | |
| R_SetVrect(&vrect, &scr_vrect, sb_lines); | |
| if (scr_con_current > vid.height) | |
| scr_con_current = vid.height; | |
| R_ViewChanged(&vrect, sb_lines, vid.aspect); | |
| } | |
| void SCR_SizeUp_f(void) | |
| { | |
| Cvar_SetValue("viewsize", scr_viewsize.value + 10); | |
| vid.recalc_refdef = 1; | |
| } | |
| void SCR_SizeDown_f(void) | |
| { | |
| Cvar_SetValue("viewsize", scr_viewsize.value - 10); | |
| vid.recalc_refdef = 1; | |
| } | |
| void SCR_Init(void) | |
| { | |
| Cvar_RegisterVariable(&scr_fov); | |
| Cvar_RegisterVariable(&scr_viewsize); | |
| Cvar_RegisterVariable(&scr_conspeed); | |
| Cvar_RegisterVariable(&scr_showram); | |
| Cvar_RegisterVariable(&scr_showturtle); | |
| Cvar_RegisterVariable(&scr_showpause); | |
| Cvar_RegisterVariable(&scr_centertime); | |
| Cvar_RegisterVariable(&scr_printspeed); | |
| Cmd_AddCommand("screenshot", SCR_ScreenShot_f); | |
| Cmd_AddCommand("sizeup", SCR_SizeUp_f); | |
| Cmd_AddCommand("sizedown", SCR_SizeDown_f); | |
| scr_ram = Draw_PicFromWad("ram"); | |
| scr_net = Draw_PicFromWad("net"); | |
| scr_turtle = Draw_PicFromWad("turtle"); | |
| scr_initialized = 1; | |
| } | |
| void SCR_DrawRam(void) | |
| { | |
| if (!scr_showram.value) | |
| return; | |
| if (!r_cache_thrash) | |
| return; | |
| Draw_Pic(scr_vrect.x + 32, scr_vrect.y, scr_ram); | |
| } | |
| void SCR_DrawTurtle(void) | |
| { | |
| static int32_t count; | |
| if (!scr_showturtle.value) | |
| return; | |
| if (host_frametime < 0.1) | |
| { | |
| count = 0; | |
| return; | |
| } | |
| count++; | |
| if (count < 3) | |
| return; | |
| Draw_Pic(scr_vrect.x, scr_vrect.y, scr_turtle); | |
| } | |
| void SCR_DrawNet(void) | |
| { | |
| if ((realtime - cl.last_received_message) < 0.3) | |
| return; | |
| if (cls.demoplayback) | |
| return; | |
| Draw_Pic(scr_vrect.x + 64, scr_vrect.y, scr_net); | |
| } | |
| void SCR_DrawPause(void) | |
| { | |
| qpic_t *pic; | |
| if (!scr_showpause.value) | |
| return; | |
| if (!cl.paused) | |
| return; | |
| pic = Draw_CachePic("gfx/pause.lmp"); | |
| Draw_Pic((vid.width - pic->width) / 2, ((vid.height - 48) - pic->height) / 2, pic); | |
| } | |
| void SCR_DrawLoading(void) | |
| { | |
| qpic_t *pic; | |
| if (!scr_drawloading) | |
| return; | |
| pic = Draw_CachePic("gfx/loading.lmp"); | |
| Draw_Pic((vid.width - pic->width) / 2, ((vid.height - 48) - pic->height) / 2, pic); | |
| } | |
| void SCR_SetUpToDrawConsole(void) | |
| { | |
| Con_CheckResize(); | |
| if (scr_drawloading) | |
| return; | |
| con_forcedup = (!cl.worldmodel) || (cls.signon != SIGNONS); | |
| if (con_forcedup) | |
| { | |
| scr_conlines = vid.height; | |
| scr_con_current = scr_conlines; | |
| } | |
| else | |
| if (key_dest == key_console) | |
| scr_conlines = vid.height / 2; | |
| else | |
| scr_conlines = 0; | |
| if (scr_conlines < scr_con_current) | |
| { | |
| scr_con_current -= scr_conspeed.value * host_frametime; | |
| if (scr_conlines > scr_con_current) | |
| scr_con_current = scr_conlines; | |
| } | |
| else | |
| if (scr_conlines > scr_con_current) | |
| { | |
| scr_con_current += scr_conspeed.value * host_frametime; | |
| if (scr_conlines < scr_con_current) | |
| scr_con_current = scr_conlines; | |
| } | |
| if ((clearconsole++) < vid.numpages) | |
| { | |
| scr_copytop = 1; | |
| Draw_TileClear(0, (int32_t) scr_con_current, vid.width, vid.height - ((int32_t) scr_con_current)); | |
| Sbar_Changed(); | |
| } | |
| else | |
| if ((clearnotify++) < vid.numpages) | |
| { | |
| scr_copytop = 1; | |
| Draw_TileClear(0, 0, vid.width, con_notifylines); | |
| } | |
| else | |
| con_notifylines = 0; | |
| } | |
| void SCR_DrawConsole(void) | |
| { | |
| if (scr_con_current) | |
| { | |
| scr_copyeverything = 1; | |
| Con_DrawConsole(scr_con_current, 1); | |
| clearconsole = 0; | |
| } | |
| else | |
| { | |
| if ((key_dest == key_game) || (key_dest == key_message)) | |
| Con_DrawNotify(); | |
| } | |
| } | |
| void WritePCXfile(char *filename, uint8_t *data, int32_t width, int32_t height, int32_t rowbytes, uint8_t *palette) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| int32_t length; | |
| pcx_t *pcx; | |
| uint8_t *pack; | |
| pcx = Hunk_TempAlloc(((width * height) * 2) + 1000); | |
| if (pcx == 0) | |
| { | |
| Con_Printf("SCR_ScreenShot_f: not enough memory\n"); | |
| return; | |
| } | |
| pcx->manufacturer = 0x0a; | |
| pcx->version = 5; | |
| pcx->encoding = 1; | |
| pcx->bits_per_pixel = 8; | |
| pcx->xmin = 0; | |
| pcx->ymin = 0; | |
| pcx->xmax = (int16_t) (width - 1); | |
| pcx->ymax = (int16_t) (height - 1); | |
| pcx->hres = (int16_t) width; | |
| pcx->vres = (int16_t) height; | |
| memset(pcx->palette, 0, sizeof(pcx->palette)); | |
| pcx->color_planes = 1; | |
| pcx->bytes_per_line = (int16_t) width; | |
| pcx->palette_type = 2; | |
| memset(pcx->filler, 0, sizeof(pcx->filler)); | |
| pack = &pcx->data; | |
| for (i = 0; i < height; i++) | |
| { | |
| for (j = 0; j < width; j++) | |
| { | |
| if (((*data) & 0xc0) != 0xc0) | |
| *(pack++) = *(data++); | |
| else | |
| { | |
| *(pack++) = 0xc1; | |
| *(pack++) = *(data++); | |
| } | |
| } | |
| data += rowbytes - width; | |
| } | |
| *(pack++) = 0x0c; | |
| for (i = 0; i < 768; i++) | |
| *(pack++) = *(palette++); | |
| length = pack - ((uint8_t *) pcx); | |
| COM_WriteFile(filename, pcx, length); | |
| } | |
| void SCR_ScreenShot_f(void) | |
| { | |
| int32_t i; | |
| char pcxname[80]; | |
| char checkname[MAX_OSPATH]; | |
| strcpy(pcxname, "quake00.pcx"); | |
| for (i = 0; i <= 99; i++) | |
| { | |
| pcxname[5] = (i / 10) + '0'; | |
| pcxname[6] = (i % 10) + '0'; | |
| sprintf(checkname, "%s/%s", com_gamedir, pcxname); | |
| if (Sys_FileTime(checkname) == (-1)) | |
| break; | |
| } | |
| if (i == 100) | |
| { | |
| Con_Printf("SCR_ScreenShot_f: Couldn't create a PCX file\n"); | |
| return; | |
| } | |
| D_EnableBackBufferAccess(); | |
| WritePCXfile(pcxname, vid.buffer, vid.width, vid.height, vid.rowbytes, host_basepal); | |
| D_DisableBackBufferAccess(); | |
| Con_Printf("Wrote %s\n", pcxname); | |
| } | |
| void SCR_BeginLoadingPlaque(void) | |
| { | |
| S_StopAllSounds(1); | |
| if (cls.state != ca_connected) | |
| return; | |
| if (cls.signon != SIGNONS) | |
| return; | |
| Con_ClearNotify(); | |
| scr_centertime_off = 0; | |
| scr_con_current = 0; | |
| scr_drawloading = 1; | |
| scr_fullupdate = 0; | |
| Sbar_Changed(); | |
| SCR_UpdateScreen(); | |
| scr_drawloading = 0; | |
| scr_disabled_for_loading = 1; | |
| scr_disabled_time = realtime; | |
| scr_fullupdate = 0; | |
| } | |
| void SCR_EndLoadingPlaque(void) | |
| { | |
| scr_disabled_for_loading = 0; | |
| scr_fullupdate = 0; | |
| Con_ClearNotify(); | |
| } | |
| void SCR_DrawNotifyString(void) | |
| { | |
| char *start; | |
| int32_t l; | |
| int32_t j; | |
| int32_t x; | |
| int32_t y; | |
| start = scr_notifystring; | |
| y = vid.height * 0.35; | |
| do | |
| { | |
| for (l = 0; l < 40; l++) | |
| if ((start[l] == '\n') || (!start[l])) | |
| break; | |
| x = (vid.width - (l * 8)) / 2; | |
| for (j = 0; j < l; j++, x += 8) | |
| Draw_Character(x, y, start[j]); | |
| y += 8; | |
| while ((*start) && ((*start) != '\n')) | |
| start++; | |
| if (!(*start)) | |
| break; | |
| start++; | |
| } | |
| while (1); | |
| } | |
| int32_t SCR_ModalMessage(char *text) | |
| { | |
| if (cls.state == ca_dedicated) | |
| return 1; | |
| scr_notifystring = text; | |
| scr_fullupdate = 0; | |
| scr_drawdialog = 1; | |
| SCR_UpdateScreen(); | |
| scr_drawdialog = 0; | |
| S_ClearBuffer(); | |
| do | |
| { | |
| key_count = -1; | |
| Sys_SendKeyEvents(); | |
| } | |
| while (((key_lastpress != 'y') && (key_lastpress != 'n')) && (key_lastpress != K_ESCAPE)); | |
| scr_fullupdate = 0; | |
| SCR_UpdateScreen(); | |
| return key_lastpress == 'y'; | |
| } | |
| void SCR_BringDownConsole(void) | |
| { | |
| int32_t i; | |
| scr_centertime_off = 0; | |
| for (i = 0; (i < 20) && (scr_conlines != scr_con_current); i++) | |
| SCR_UpdateScreen(); | |
| cl.cshifts[0].percent = 0; | |
| VID_SetPalette(host_basepal); | |
| } | |
| void SCR_UpdateScreen(void) | |
| { | |
| static float oldscr_viewsize; | |
| static float oldlcd_x; | |
| vrect_t vrect; | |
| if (scr_skipupdate || block_drawing) | |
| return; | |
| scr_copytop = 0; | |
| scr_copyeverything = 0; | |
| if (scr_disabled_for_loading) | |
| { | |
| if ((realtime - scr_disabled_time) > 60) | |
| { | |
| scr_disabled_for_loading = 0; | |
| Con_Printf("load failed.\n"); | |
| } | |
| else | |
| return; | |
| } | |
| if (cls.state == ca_dedicated) | |
| return; | |
| if ((!scr_initialized) || (!con_initialized)) | |
| return; | |
| if (scr_viewsize.value != oldscr_viewsize) | |
| { | |
| oldscr_viewsize = scr_viewsize.value; | |
| vid.recalc_refdef = 1; | |
| } | |
| if (oldfov != scr_fov.value) | |
| { | |
| oldfov = scr_fov.value; | |
| vid.recalc_refdef = 1; | |
| } | |
| if (oldlcd_x != lcd_x.value) | |
| { | |
| oldlcd_x = lcd_x.value; | |
| vid.recalc_refdef = 1; | |
| } | |
| if (oldscreensize != scr_viewsize.value) | |
| { | |
| oldscreensize = scr_viewsize.value; | |
| vid.recalc_refdef = 1; | |
| } | |
| if (vid.recalc_refdef) | |
| { | |
| SCR_CalcRefdef(); | |
| } | |
| D_EnableBackBufferAccess(); | |
| if ((scr_fullupdate++) < vid.numpages) | |
| { | |
| scr_copyeverything = 1; | |
| Draw_TileClear(0, 0, vid.width, vid.height); | |
| Sbar_Changed(); | |
| } | |
| pconupdate = 0; | |
| SCR_SetUpToDrawConsole(); | |
| SCR_EraseCenterString(); | |
| D_DisableBackBufferAccess(); | |
| VID_LockBuffer(); | |
| V_RenderView(); | |
| VID_UnlockBuffer(); | |
| D_EnableBackBufferAccess(); | |
| if (scr_drawdialog) | |
| { | |
| Sbar_Draw(); | |
| Draw_FadeScreen(); | |
| SCR_DrawNotifyString(); | |
| scr_copyeverything = 1; | |
| } | |
| else | |
| if (scr_drawloading) | |
| { | |
| SCR_DrawLoading(); | |
| Sbar_Draw(); | |
| } | |
| else | |
| if ((cl.intermission == 1) && (key_dest == key_game)) | |
| { | |
| Sbar_IntermissionOverlay(); | |
| } | |
| else | |
| if ((cl.intermission == 2) && (key_dest == key_game)) | |
| { | |
| Sbar_FinaleOverlay(); | |
| SCR_CheckDrawCenterString(); | |
| } | |
| else | |
| if ((cl.intermission == 3) && (key_dest == key_game)) | |
| { | |
| SCR_CheckDrawCenterString(); | |
| } | |
| else | |
| { | |
| SCR_DrawRam(); | |
| SCR_DrawNet(); | |
| SCR_DrawTurtle(); | |
| SCR_DrawPause(); | |
| SCR_CheckDrawCenterString(); | |
| Sbar_Draw(); | |
| SCR_DrawConsole(); | |
| M_Draw(); | |
| } | |
| D_DisableBackBufferAccess(); | |
| if (pconupdate) | |
| { | |
| D_UpdateRects(pconupdate); | |
| } | |
| V_UpdatePalette(); | |
| if (scr_copyeverything) | |
| { | |
| vrect.x = 0; | |
| vrect.y = 0; | |
| vrect.width = vid.width; | |
| vrect.height = vid.height; | |
| vrect.pnext = 0; | |
| VID_Update(&vrect); | |
| } | |
| else | |
| if (scr_copytop) | |
| { | |
| vrect.x = 0; | |
| vrect.y = 0; | |
| vrect.width = vid.width; | |
| vrect.height = vid.height - sb_lines; | |
| vrect.pnext = 0; | |
| VID_Update(&vrect); | |
| } | |
| else | |
| { | |
| vrect.x = scr_vrect.x; | |
| vrect.y = scr_vrect.y; | |
| vrect.width = scr_vrect.width; | |
| vrect.height = scr_vrect.height; | |
| vrect.pnext = 0; | |
| VID_Update(&vrect); | |
| } | |
| } | |
| void SCR_UpdateWholeScreen(void) | |
| { | |
| scr_fullupdate = 0; | |
| SCR_UpdateScreen(); | |
| } | |
| void S_AmbientOff(void) | |
| { | |
| snd_ambient = 0; | |
| } | |
| void S_AmbientOn(void) | |
| { | |
| snd_ambient = 1; | |
| } | |
| void S_SoundInfo_f(void) | |
| { | |
| if ((!sound_started) || (!shm)) | |
| { | |
| Con_Printf("sound system not started\n"); | |
| return; | |
| } | |
| Con_Printf("%5d stereo\n", shm->channels - 1); | |
| Con_Printf("%5d samples\n", shm->samples); | |
| Con_Printf("%5d samplepos\n", shm->samplepos); | |
| Con_Printf("%5d samplebits\n", shm->samplebits); | |
| Con_Printf("%5d submission_chunk\n", shm->submission_chunk); | |
| Con_Printf("%5d speed\n", shm->speed); | |
| Con_Printf("0x%x dma buffer\n", shm->buffer); | |
| Con_Printf("%5d total_channels\n", total_channels); | |
| } | |
| void S_Startup(void) | |
| { | |
| int32_t rc; | |
| if (!snd_initialized) | |
| return; | |
| if (!fakedma) | |
| { | |
| rc = SNDDMA_Init(); | |
| if (!rc) | |
| { | |
| Con_Printf("S_Startup: SNDDMA_Init failed.\n"); | |
| sound_started = 0; | |
| return; | |
| } | |
| } | |
| sound_started = 1; | |
| } | |
| void S_Init(void) | |
| { | |
| Con_Printf("\nSound Initialization\n"); | |
| if (COM_CheckParm("-nosound")) | |
| return; | |
| if (COM_CheckParm("-simsound")) | |
| fakedma = 1; | |
| Cmd_AddCommand("play", S_Play); | |
| Cmd_AddCommand("playvol", S_PlayVol); | |
| Cmd_AddCommand("stopsound", S_StopAllSoundsC); | |
| Cmd_AddCommand("soundlist", S_SoundList); | |
| Cmd_AddCommand("soundinfo", S_SoundInfo_f); | |
| Cvar_RegisterVariable(&nosound); | |
| Cvar_RegisterVariable(&volume); | |
| Cvar_RegisterVariable(&precache); | |
| Cvar_RegisterVariable(&loadas8bit); | |
| Cvar_RegisterVariable(&bgmvolume); | |
| Cvar_RegisterVariable(&bgmbuffer); | |
| Cvar_RegisterVariable(&ambient_level); | |
| Cvar_RegisterVariable(&ambient_fade); | |
| Cvar_RegisterVariable(&snd_noextraupdate); | |
| Cvar_RegisterVariable(&snd_show); | |
| Cvar_RegisterVariable(&_snd_mixahead); | |
| if (host_parms.memsize < 0x800000) | |
| { | |
| Cvar_Set("loadas8bit", "1"); | |
| Con_Printf("loading all sounds as 8bit\n"); | |
| } | |
| snd_initialized = 1; | |
| S_Startup(); | |
| SND_InitScaletable(); | |
| known_sfx = Hunk_AllocName(MAX_SFX * (sizeof(sfx_t)), "sfx_t"); | |
| num_sfx = 0; | |
| if (fakedma) | |
| { | |
| shm = (void *) Hunk_AllocName(sizeof(*shm), "shm"); | |
| shm->splitbuffer = 0; | |
| shm->samplebits = 16; | |
| shm->speed = 22050; | |
| shm->channels = 2; | |
| shm->samples = 32768; | |
| shm->samplepos = 0; | |
| shm->soundalive = 1; | |
| shm->gamealive = 1; | |
| shm->submission_chunk = 1; | |
| shm->buffer = Hunk_AllocName(1 << 16, "shmbuf"); | |
| } | |
| Con_Printf("Sound sampling rate: %i\n", shm->speed); | |
| ambient_sfx[AMBIENT_WATER] = S_PrecacheSound("ambience/water1.wav"); | |
| ambient_sfx[AMBIENT_SKY] = S_PrecacheSound("ambience/wind2.wav"); | |
| S_StopAllSounds(1); | |
| } | |
| void S_Shutdown(void) | |
| { | |
| if (!sound_started) | |
| return; | |
| if (shm) | |
| shm->gamealive = 0; | |
| shm = 0; | |
| sound_started = 0; | |
| if (!fakedma) | |
| { | |
| SNDDMA_Shutdown(); | |
| } | |
| } | |
| sfx_t *S_FindName(char *name) | |
| { | |
| int32_t i; | |
| sfx_t *sfx; | |
| if (!name) | |
| Sys_Error("S_FindName: NULL\n"); | |
| if (strlen(name) >= MAX_QPATH) | |
| Sys_Error("Sound name too int32_t: %s", name); | |
| for (i = 0; i < num_sfx; i++) | |
| if (!strcmp(known_sfx[i].name, name)) | |
| { | |
| return &known_sfx[i]; | |
| } | |
| if (num_sfx == MAX_SFX) | |
| Sys_Error("S_FindName: out of sfx_t"); | |
| sfx = &known_sfx[i]; | |
| strcpy(sfx->name, name); | |
| num_sfx++; | |
| return sfx; | |
| } | |
| void S_TouchSound(char *name) | |
| { | |
| sfx_t *sfx; | |
| if (!sound_started) | |
| return; | |
| sfx = S_FindName(name); | |
| Cache_Check(&sfx->cache); | |
| } | |
| sfx_t *S_PrecacheSound(char *name) | |
| { | |
| sfx_t *sfx; | |
| if ((!sound_started) || nosound.value) | |
| return 0; | |
| sfx = S_FindName(name); | |
| if (precache.value) | |
| S_LoadSound(sfx); | |
| return sfx; | |
| } | |
| channel_t *SND_PickChannel(int32_t entnum, int32_t entchannel) | |
| { | |
| int32_t ch_idx; | |
| int32_t first_to_die; | |
| int32_t life_left; | |
| first_to_die = -1; | |
| life_left = 0x7fffffff; | |
| for (ch_idx = NUM_AMBIENTS; ch_idx < (NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS); ch_idx++) | |
| { | |
| if (((entchannel != 0) && (channels[ch_idx].entnum == entnum)) && ((channels[ch_idx].entchannel == entchannel) || (entchannel == (-1)))) | |
| { | |
| first_to_die = ch_idx; | |
| break; | |
| } | |
| if (((channels[ch_idx].entnum == cl.viewentity) && (entnum != cl.viewentity)) && channels[ch_idx].sfx) | |
| continue; | |
| if ((channels[ch_idx].end - paintedtime) < life_left) | |
| { | |
| life_left = channels[ch_idx].end - paintedtime; | |
| first_to_die = ch_idx; | |
| } | |
| } | |
| if (first_to_die == (-1)) | |
| return 0; | |
| if (channels[first_to_die].sfx) | |
| channels[first_to_die].sfx = 0; | |
| return &channels[first_to_die]; | |
| } | |
| void SND_Spatialize(channel_t *ch) | |
| { | |
| vec_t dot; | |
| vec_t ldist; | |
| vec_t rdist; | |
| vec_t dist; | |
| vec_t lscale; | |
| vec_t rscale; | |
| vec_t scale; | |
| vec3_t source_vec; | |
| sfx_t *snd; | |
| if (ch->entnum == cl.viewentity) | |
| { | |
| ch->leftvol = ch->master_vol; | |
| ch->rightvol = ch->master_vol; | |
| return; | |
| } | |
| snd = ch->sfx; | |
| VectorSubtract(ch->origin, listener_origin, source_vec); | |
| dist = VectorNormalize(source_vec) * ch->dist_mult; | |
| dot = DotProduct(listener_right, source_vec); | |
| if (shm->channels == 1) | |
| { | |
| rscale = 1.0; | |
| lscale = 1.0; | |
| } | |
| else | |
| { | |
| rscale = 1.0 + dot; | |
| lscale = 1.0 - dot; | |
| } | |
| scale = (1.0 - dist) * rscale; | |
| ch->rightvol = (int32_t) (ch->master_vol * scale); | |
| if (ch->rightvol < 0) | |
| ch->rightvol = 0; | |
| scale = (1.0 - dist) * lscale; | |
| ch->leftvol = (int32_t) (ch->master_vol * scale); | |
| if (ch->leftvol < 0) | |
| ch->leftvol = 0; | |
| } | |
| void S_StartSound(int32_t entnum, int32_t entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation) | |
| { | |
| channel_t *target_chan; | |
| channel_t *check; | |
| sfxcache_t *sc; | |
| int32_t vol; | |
| int32_t ch_idx; | |
| int32_t skip; | |
| if (!sound_started) | |
| return; | |
| if (!sfx) | |
| return; | |
| if (nosound.value) | |
| return; | |
| vol = fvol * 255; | |
| target_chan = SND_PickChannel(entnum, entchannel); | |
| if (!target_chan) | |
| return; | |
| memset(target_chan, 0, sizeof(*target_chan)); | |
| VectorCopy(origin, target_chan->origin); | |
| target_chan->dist_mult = attenuation / sound_nominal_clip_dist; | |
| target_chan->master_vol = vol; | |
| target_chan->entnum = entnum; | |
| target_chan->entchannel = entchannel; | |
| SND_Spatialize(target_chan); | |
| if ((!target_chan->leftvol) && (!target_chan->rightvol)) | |
| return; | |
| sc = S_LoadSound(sfx); | |
| if (!sc) | |
| { | |
| target_chan->sfx = 0; | |
| return; | |
| } | |
| target_chan->sfx = sfx; | |
| target_chan->pos = 0.0; | |
| target_chan->end = paintedtime + sc->length; | |
| check = &channels[NUM_AMBIENTS]; | |
| for (ch_idx = NUM_AMBIENTS; ch_idx < (NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS); ch_idx++, check++) | |
| { | |
| if (check == target_chan) | |
| continue; | |
| if ((check->sfx == sfx) && (!check->pos)) | |
| { | |
| skip = rand() % ((int32_t) (0.1 * shm->speed)); | |
| if (skip >= target_chan->end) | |
| skip = target_chan->end - 1; | |
| target_chan->pos += skip; | |
| target_chan->end -= skip; | |
| break; | |
| } | |
| } | |
| } | |
| void S_StopSound(int32_t entnum, int32_t entchannel) | |
| { | |
| int32_t i; | |
| for (i = 0; i < MAX_DYNAMIC_CHANNELS; i++) | |
| { | |
| if ((channels[i].entnum == entnum) && (channels[i].entchannel == entchannel)) | |
| { | |
| channels[i].end = 0; | |
| channels[i].sfx = 0; | |
| return; | |
| } | |
| } | |
| } | |
| void S_StopAllSounds(bool clear) | |
| { | |
| int32_t i; | |
| if (!sound_started) | |
| return; | |
| total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; | |
| for (i = 0; i < MAX_CHANNELS; i++) | |
| if (channels[i].sfx) | |
| channels[i].sfx = 0; | |
| memset(channels, 0, MAX_CHANNELS * (sizeof(channel_t))); | |
| if (clear) | |
| S_ClearBuffer(); | |
| } | |
| void S_StopAllSoundsC(void) | |
| { | |
| S_StopAllSounds(1); | |
| } | |
| void S_ClearBuffer(void) | |
| { | |
| int32_t clear; | |
| if (((!sound_started) || (!shm)) || (!shm->buffer)) | |
| return; | |
| if (shm->samplebits == 8) | |
| clear = 0x80; | |
| else | |
| clear = 0; | |
| memset(shm->buffer, clear, (shm->samples * shm->samplebits) / 8); | |
| } | |
| void S_StaticSound(sfx_t *sfx, vec3_t origin, float vol, float attenuation) | |
| { | |
| channel_t *ss; | |
| sfxcache_t *sc; | |
| if (!sfx) | |
| return; | |
| if (total_channels == MAX_CHANNELS) | |
| { | |
| Con_Printf("total_channels == MAX_CHANNELS\n"); | |
| return; | |
| } | |
| ss = &channels[total_channels]; | |
| total_channels++; | |
| sc = S_LoadSound(sfx); | |
| if (!sc) | |
| return; | |
| if (sc->loopstart == (-1)) | |
| { | |
| Con_Printf("Sound %s not looped\n", sfx->name); | |
| return; | |
| } | |
| ss->sfx = sfx; | |
| VectorCopy(origin, ss->origin); | |
| ss->master_vol = vol; | |
| ss->dist_mult = (attenuation / 64) / sound_nominal_clip_dist; | |
| ss->end = paintedtime + sc->length; | |
| SND_Spatialize(ss); | |
| } | |
| void S_UpdateAmbientSounds(void) | |
| { | |
| mleaf_t *l; | |
| float vol; | |
| int32_t ambient_channel; | |
| channel_t *chan; | |
| if (!snd_ambient) | |
| return; | |
| if (!cl.worldmodel) | |
| return; | |
| l = Mod_PointInLeaf(listener_origin, cl.worldmodel); | |
| if ((!l) || (!ambient_level.value)) | |
| { | |
| for (ambient_channel = 0; ambient_channel < NUM_AMBIENTS; ambient_channel++) | |
| channels[ambient_channel].sfx = 0; | |
| return; | |
| } | |
| for (ambient_channel = 0; ambient_channel < NUM_AMBIENTS; ambient_channel++) | |
| { | |
| chan = &channels[ambient_channel]; | |
| chan->sfx = ambient_sfx[ambient_channel]; | |
| vol = ambient_level.value * l->ambient_sound_level[ambient_channel]; | |
| if (vol < 8) | |
| vol = 0; | |
| if (chan->master_vol < vol) | |
| { | |
| chan->master_vol += host_frametime * ambient_fade.value; | |
| if (chan->master_vol > vol) | |
| chan->master_vol = vol; | |
| } | |
| else | |
| if (chan->master_vol > vol) | |
| { | |
| chan->master_vol -= host_frametime * ambient_fade.value; | |
| if (chan->master_vol < vol) | |
| chan->master_vol = vol; | |
| } | |
| chan->leftvol = (chan->rightvol = chan->master_vol); | |
| } | |
| } | |
| void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| int32_t total; | |
| channel_t *ch; | |
| channel_t *combine; | |
| if ((!sound_started) || (snd_blocked > 0)) | |
| return; | |
| VectorCopy(origin, listener_origin); | |
| VectorCopy(forward, listener_forward); | |
| VectorCopy(right, listener_right); | |
| VectorCopy(up, listener_up); | |
| S_UpdateAmbientSounds(); | |
| combine = 0; | |
| ch = channels + NUM_AMBIENTS; | |
| for (i = NUM_AMBIENTS; i < total_channels; i++, ch++) | |
| { | |
| if (!ch->sfx) | |
| continue; | |
| SND_Spatialize(ch); | |
| if ((!ch->leftvol) && (!ch->rightvol)) | |
| continue; | |
| if (i >= (MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS)) | |
| { | |
| if (combine && (combine->sfx == ch->sfx)) | |
| { | |
| combine->leftvol += ch->leftvol; | |
| combine->rightvol += ch->rightvol; | |
| ch->leftvol = (ch->rightvol = 0); | |
| continue; | |
| } | |
| combine = (channels + MAX_DYNAMIC_CHANNELS) + NUM_AMBIENTS; | |
| for (j = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; j < i; j++, combine++) | |
| if (combine->sfx == ch->sfx) | |
| break; | |
| if (j == total_channels) | |
| { | |
| combine = 0; | |
| } | |
| else | |
| { | |
| if (combine != ch) | |
| { | |
| combine->leftvol += ch->leftvol; | |
| combine->rightvol += ch->rightvol; | |
| ch->leftvol = (ch->rightvol = 0); | |
| } | |
| continue; | |
| } | |
| } | |
| } | |
| if (snd_show.value) | |
| { | |
| total = 0; | |
| ch = channels; | |
| for (i = 0; i < total_channels; i++, ch++) | |
| if (ch->sfx && (ch->leftvol || ch->rightvol)) | |
| { | |
| total++; | |
| } | |
| Con_Printf("----(%i)----\n", total); | |
| } | |
| S_Update_(); | |
| } | |
| void GetSoundtime(void) | |
| { | |
| int32_t samplepos; | |
| static int32_t buffers; | |
| static int32_t oldsamplepos; | |
| int32_t fullsamples; | |
| fullsamples = shm->samples / shm->channels; | |
| samplepos = SNDDMA_GetDMAPos(); | |
| if (samplepos < oldsamplepos) | |
| { | |
| buffers++; | |
| if (paintedtime > 0x40000000) | |
| { | |
| buffers = 0; | |
| paintedtime = fullsamples; | |
| S_StopAllSounds(1); | |
| } | |
| } | |
| oldsamplepos = samplepos; | |
| soundtime = (buffers * fullsamples) + (samplepos / shm->channels); | |
| } | |
| void S_ExtraUpdate(void) | |
| { | |
| if (snd_noextraupdate.value) | |
| return; | |
| S_Update_(); | |
| } | |
| void S_Update_(void) | |
| { | |
| unsigned endtime; | |
| int32_t samps; | |
| if ((!sound_started) || (snd_blocked > 0)) | |
| return; | |
| GetSoundtime(); | |
| if (paintedtime < soundtime) | |
| { | |
| paintedtime = soundtime; | |
| } | |
| endtime = soundtime + (_snd_mixahead.value * shm->speed); | |
| samps = shm->samples >> (shm->channels - 1); | |
| if ((endtime - soundtime) > samps) | |
| endtime = soundtime + samps; | |
| S_PaintChannels(endtime); | |
| SNDDMA_Submit(); | |
| } | |
| void S_Play(void) | |
| { | |
| static int32_t hash = 345; | |
| int32_t i; | |
| char name[256]; | |
| sfx_t *sfx; | |
| i = 1; | |
| while (i < Cmd_Argc()) | |
| { | |
| if (!strrchr(Cmd_Argv(i), '.')) | |
| { | |
| strcpy(name, Cmd_Argv(i)); | |
| strcat(name, ".wav"); | |
| } | |
| else | |
| strcpy(name, Cmd_Argv(i)); | |
| sfx = S_PrecacheSound(name); | |
| S_StartSound(hash++, 0, sfx, listener_origin, 1.0, 1.0); | |
| i++; | |
| } | |
| } | |
| void S_PlayVol(void) | |
| { | |
| static int32_t hash = 543; | |
| int32_t i; | |
| float vol; | |
| char name[256]; | |
| sfx_t *sfx; | |
| i = 1; | |
| while (i < Cmd_Argc()) | |
| { | |
| if (!strrchr(Cmd_Argv(i), '.')) | |
| { | |
| strcpy(name, Cmd_Argv(i)); | |
| strcat(name, ".wav"); | |
| } | |
| else | |
| strcpy(name, Cmd_Argv(i)); | |
| sfx = S_PrecacheSound(name); | |
| vol = (float) strtod(Cmd_Argv(i + 1), 0); | |
| S_StartSound(hash++, 0, sfx, listener_origin, vol, 1.0); | |
| i += 2; | |
| } | |
| } | |
| void S_SoundList(void) | |
| { | |
| int32_t i; | |
| sfx_t *sfx; | |
| sfxcache_t *sc; | |
| int32_t size; | |
| int32_t total; | |
| total = 0; | |
| for (sfx = known_sfx, i = 0; i < num_sfx; i++, sfx++) | |
| { | |
| sc = Cache_Check(&sfx->cache); | |
| if (!sc) | |
| continue; | |
| size = (sc->length * sc->width) * (sc->stereo + 1); | |
| total += size; | |
| if (sc->loopstart >= 0) | |
| Con_Printf("L"); | |
| else | |
| Con_Printf(" "); | |
| Con_Printf("(%2db) %6i : %s\n", sc->width * 8, size, sfx->name); | |
| } | |
| Con_Printf("Total resident: %i\n", total); | |
| } | |
| void S_LocalSound(char *sound) | |
| { | |
| sfx_t *sfx; | |
| if (nosound.value) | |
| return; | |
| if (!sound_started) | |
| return; | |
| sfx = S_PrecacheSound(sound); | |
| if (!sfx) | |
| { | |
| Con_Printf("S_LocalSound: can't cache %s\n", sound); | |
| return; | |
| } | |
| S_StartSound(cl.viewentity, -1, sfx, vec3_origin, 1, 1); | |
| } | |
| void S_ClearPrecache(void) | |
| { | |
| } | |
| void S_BeginPrecaching(void) | |
| { | |
| } | |
| void S_EndPrecaching(void) | |
| { | |
| } | |
| void ResampleSfx(sfx_t *sfx, int32_t inrate, int32_t inwidth, uint8_t *data) | |
| { | |
| int32_t outcount; | |
| int32_t srcsample; | |
| float stepscale; | |
| int32_t i; | |
| int32_t sample; | |
| int32_t samplefrac; | |
| int32_t fracstep; | |
| sfxcache_t *sc; | |
| sc = Cache_Check(&sfx->cache); | |
| if (!sc) | |
| return; | |
| stepscale = ((float) inrate) / shm->speed; | |
| outcount = sc->length / stepscale; | |
| sc->length = outcount; | |
| if (sc->loopstart != (-1)) | |
| sc->loopstart = sc->loopstart / stepscale; | |
| sc->speed = shm->speed; | |
| if (loadas8bit.value) | |
| sc->width = 1; | |
| else | |
| sc->width = inwidth; | |
| sc->stereo = 0; | |
| if (((stepscale == 1) && (inwidth == 1)) && (sc->width == 1)) | |
| { | |
| for (i = 0; i < outcount; i++) | |
| ((signed char *) sc->data)[i] = (int32_t) (((unsigned char) data[i]) - 128); | |
| } | |
| else | |
| { | |
| samplefrac = 0; | |
| fracstep = stepscale * 256; | |
| for (i = 0; i < outcount; i++) | |
| { | |
| srcsample = samplefrac >> 8; | |
| samplefrac += fracstep; | |
| if (inwidth == 2) | |
| sample = ((int16_t *) data)[srcsample]; | |
| else | |
| sample = ((int32_t) (((unsigned char) data[srcsample]) - 128)) << 8; | |
| if (sc->width == 2) | |
| ((int16_t *) sc->data)[i] = sample; | |
| else | |
| ((signed char *) sc->data)[i] = sample >> 8; | |
| } | |
| } | |
| } | |
| sfxcache_t *S_LoadSound(sfx_t *s) | |
| { | |
| char namebuffer[256]; | |
| uint8_t *data; | |
| wavinfo_t info; | |
| int32_t len; | |
| float stepscale; | |
| sfxcache_t *sc; | |
| uint8_t stackbuf[1 * 1024]; | |
| sc = Cache_Check(&s->cache); | |
| if (sc) | |
| return sc; | |
| strcpy(namebuffer, "sound/"); | |
| strcat(namebuffer, s->name); | |
| data = COM_LoadStackFile(namebuffer, stackbuf, sizeof(stackbuf)); | |
| if (!data) | |
| { | |
| Con_Printf("Couldn't load %s\n", namebuffer); | |
| return 0; | |
| } | |
| info = GetWavinfo(s->name, data, com_filesize); | |
| if (info.channels != 1) | |
| { | |
| Con_Printf("%s is a stereo sample\n", s->name); | |
| return 0; | |
| } | |
| stepscale = ((float) info.rate) / shm->speed; | |
| len = info.samples / stepscale; | |
| len = (len * info.width) * info.channels; | |
| sc = Cache_Alloc(&s->cache, len + (sizeof(sfxcache_t)), s->name); | |
| if (!sc) | |
| return 0; | |
| sc->length = info.samples; | |
| sc->loopstart = info.loopstart; | |
| sc->speed = info.rate; | |
| sc->width = info.width; | |
| sc->stereo = info.channels; | |
| ResampleSfx(s, sc->speed, sc->width, data + info.dataofs); | |
| return sc; | |
| } | |
| int16_t GetLittleShort(void) | |
| { | |
| int16_t val = 0; | |
| val = *data_p; | |
| val = val + ((*(data_p + 1)) << 8); | |
| data_p += 2; | |
| return val; | |
| } | |
| int32_t GetLittleLong(void) | |
| { | |
| int32_t val = 0; | |
| val = *data_p; | |
| val = val + ((*(data_p + 1)) << 8); | |
| val = val + ((*(data_p + 2)) << 16); | |
| val = val + ((*(data_p + 3)) << 24); | |
| data_p += 4; | |
| return val; | |
| } | |
| void FindNextChunk(char *name) | |
| { | |
| while (1) | |
| { | |
| data_p = last_chunk; | |
| if (data_p >= iff_end) | |
| { | |
| data_p = 0; | |
| return; | |
| } | |
| data_p += 4; | |
| iff_chunk_len = GetLittleLong(); | |
| if (iff_chunk_len < 0) | |
| { | |
| data_p = 0; | |
| return; | |
| } | |
| data_p -= 8; | |
| last_chunk = (data_p + 8) + ((iff_chunk_len + 1) & (~1)); | |
| if (!strncmp(data_p, name, 4)) | |
| return; | |
| } | |
| } | |
| void FindChunk(char *name) | |
| { | |
| last_chunk = iff_data; | |
| FindNextChunk(name); | |
| } | |
| void DumpChunks(void) | |
| { | |
| char str[5]; | |
| str[4] = 0; | |
| data_p = iff_data; | |
| do | |
| { | |
| memcpy(str, data_p, 4); | |
| data_p += 4; | |
| iff_chunk_len = GetLittleLong(); | |
| Con_Printf("0x%x : %s (%d)\n", (int32_t) (data_p - 4), str, iff_chunk_len); | |
| data_p += (iff_chunk_len + 1) & (~1); | |
| } | |
| while (data_p < iff_end); | |
| } | |
| wavinfo_t GetWavinfo(char *name, uint8_t *wav, int32_t wavlength) | |
| { | |
| wavinfo_t info; | |
| int32_t i; | |
| int32_t format; | |
| int32_t samples; | |
| memset(&info, 0, sizeof(info)); | |
| if (!wav) | |
| return info; | |
| iff_data = wav; | |
| iff_end = wav + wavlength; | |
| FindChunk("RIFF"); | |
| if (!(data_p && (!strncmp(data_p + 8, "WAVE", 4)))) | |
| { | |
| Con_Printf("Missing RIFF/WAVE chunks\n"); | |
| return info; | |
| } | |
| iff_data = data_p + 12; | |
| FindChunk("fmt "); | |
| if (!data_p) | |
| { | |
| Con_Printf("Missing fmt chunk\n"); | |
| return info; | |
| } | |
| data_p += 8; | |
| format = GetLittleShort(); | |
| if (format != 1) | |
| { | |
| Con_Printf("Microsoft PCM format only\n"); | |
| return info; | |
| } | |
| info.channels = GetLittleShort(); | |
| info.rate = GetLittleLong(); | |
| data_p += 4 + 2; | |
| info.width = GetLittleShort() / 8; | |
| FindChunk("cue "); | |
| if (data_p) | |
| { | |
| data_p += 32; | |
| info.loopstart = GetLittleLong(); | |
| FindNextChunk("LIST"); | |
| if (data_p) | |
| { | |
| if (!strncmp(data_p + 28, "mark", 4)) | |
| { | |
| data_p += 24; | |
| i = GetLittleLong(); | |
| info.samples = info.loopstart + i; | |
| } | |
| } | |
| } | |
| else | |
| info.loopstart = -1; | |
| FindChunk("data"); | |
| if (!data_p) | |
| { | |
| Con_Printf("Missing data chunk\n"); | |
| return info; | |
| } | |
| data_p += 4; | |
| samples = GetLittleLong() / info.width; | |
| if (info.samples) | |
| { | |
| if (samples < info.samples) | |
| Sys_Error("Sound %s has a bad loop length", name); | |
| } | |
| else | |
| info.samples = samples; | |
| info.dataofs = data_p - wav; | |
| return info; | |
| } | |
| void Snd_WriteLinearBlastStereo16(void) | |
| { | |
| int32_t i; | |
| int32_t val; | |
| for (i = 0; i < snd_linear_count; i += 2) | |
| { | |
| val = (snd_p[i] * snd_vol) >> 8; | |
| if (val > 0x7fff) | |
| snd_out[i] = 0x7fff; | |
| else | |
| if (val < ((int16_t) 0x8000)) | |
| snd_out[i] = (int16_t) 0x8000; | |
| else | |
| snd_out[i] = val; | |
| val = (snd_p[i + 1] * snd_vol) >> 8; | |
| if (val > 0x7fff) | |
| snd_out[i + 1] = 0x7fff; | |
| else | |
| if (val < ((int16_t) 0x8000)) | |
| snd_out[i + 1] = (int16_t) 0x8000; | |
| else | |
| snd_out[i + 1] = val; | |
| } | |
| } | |
| void S_TransferStereo16(int32_t endtime) | |
| { | |
| int32_t lpos; | |
| int32_t lpaintedtime; | |
| uint32_t *pbuf; | |
| snd_vol = volume.value * 256; | |
| snd_p = (int32_t *) paintbuffer; | |
| lpaintedtime = paintedtime; | |
| pbuf = (uint32_t *) shm->buffer; | |
| while (lpaintedtime < endtime) | |
| { | |
| lpos = lpaintedtime & ((shm->samples >> 1) - 1); | |
| snd_out = ((int16_t *) pbuf) + (lpos << 1); | |
| snd_linear_count = (shm->samples >> 1) - lpos; | |
| if ((lpaintedtime + snd_linear_count) > endtime) | |
| snd_linear_count = endtime - lpaintedtime; | |
| snd_linear_count <<= 1; | |
| Snd_WriteLinearBlastStereo16(); | |
| snd_p += snd_linear_count; | |
| lpaintedtime += snd_linear_count >> 1; | |
| } | |
| } | |
| void S_TransferPaintBuffer(int32_t endtime) | |
| { | |
| int32_t out_idx; | |
| int32_t count; | |
| int32_t out_mask; | |
| int32_t *p; | |
| int32_t step; | |
| int32_t val; | |
| int32_t snd_vol; | |
| uint32_t *pbuf; | |
| if ((shm->samplebits == 16) && (shm->channels == 2)) | |
| { | |
| S_TransferStereo16(endtime); | |
| return; | |
| } | |
| p = (int32_t *) paintbuffer; | |
| count = (endtime - paintedtime) * shm->channels; | |
| out_mask = shm->samples - 1; | |
| out_idx = (paintedtime * shm->channels) & out_mask; | |
| step = 3 - shm->channels; | |
| snd_vol = volume.value * 256; | |
| pbuf = (uint32_t *) shm->buffer; | |
| if (shm->samplebits == 16) | |
| { | |
| int16_t *out = (int16_t *) pbuf; | |
| while (count--) | |
| { | |
| val = ((*p) * snd_vol) >> 8; | |
| p += step; | |
| if (val > 0x7fff) | |
| val = 0x7fff; | |
| else | |
| if (val < ((int16_t) 0x8000)) | |
| val = (int16_t) 0x8000; | |
| out[out_idx] = val; | |
| out_idx = (out_idx + 1) & out_mask; | |
| } | |
| } | |
| else | |
| if (shm->samplebits == 8) | |
| { | |
| unsigned char *out = (unsigned char *) pbuf; | |
| while (count--) | |
| { | |
| val = ((*p) * snd_vol) >> 8; | |
| p += step; | |
| if (val > 0x7fff) | |
| val = 0x7fff; | |
| else | |
| if (val < ((int16_t) 0x8000)) | |
| val = (int16_t) 0x8000; | |
| out[out_idx] = (val >> 8) + 128; | |
| out_idx = (out_idx + 1) & out_mask; | |
| } | |
| } | |
| } | |
| void S_PaintChannels(int32_t endtime) | |
| { | |
| int32_t i; | |
| int32_t end; | |
| channel_t *ch; | |
| sfxcache_t *sc; | |
| int32_t ltime; | |
| int32_t count; | |
| while (paintedtime < endtime) | |
| { | |
| end = endtime; | |
| if ((endtime - paintedtime) > PAINTBUFFER_SIZE) | |
| end = paintedtime + PAINTBUFFER_SIZE; | |
| memset(paintbuffer, 0, (end - paintedtime) * (sizeof(portable_samplepair_t))); | |
| ch = channels; | |
| for (i = 0; i < total_channels; i++, ch++) | |
| { | |
| if (!ch->sfx) | |
| continue; | |
| if ((!ch->leftvol) && (!ch->rightvol)) | |
| continue; | |
| sc = S_LoadSound(ch->sfx); | |
| if (!sc) | |
| continue; | |
| ltime = paintedtime; | |
| while (ltime < end) | |
| { | |
| if (ch->end < end) | |
| count = ch->end - ltime; | |
| else | |
| count = end - ltime; | |
| if (count > 0) | |
| { | |
| if (sc->width == 1) | |
| SND_PaintChannelFrom8(ch, sc, count); | |
| else | |
| SND_PaintChannelFrom16(ch, sc, count); | |
| ltime += count; | |
| } | |
| if (ltime >= ch->end) | |
| { | |
| if (sc->loopstart >= 0) | |
| { | |
| ch->pos = sc->loopstart; | |
| ch->end = (ltime + sc->length) - ch->pos; | |
| } | |
| else | |
| { | |
| ch->sfx = 0; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| S_TransferPaintBuffer(end); | |
| paintedtime = end; | |
| } | |
| } | |
| void SND_InitScaletable(void) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| for (i = 0; i < 32; i++) | |
| for (j = 0; j < 256; j++) | |
| snd_scaletable[i][j] = (((signed char) j) * i) * 8; | |
| } | |
| void SND_PaintChannelFrom8(channel_t *ch, sfxcache_t *sc, int32_t count) | |
| { | |
| int32_t data; | |
| int32_t *lscale; | |
| int32_t *rscale; | |
| unsigned char *sfx; | |
| int32_t i; | |
| if (ch->leftvol > 255) | |
| ch->leftvol = 255; | |
| if (ch->rightvol > 255) | |
| ch->rightvol = 255; | |
| lscale = snd_scaletable[ch->leftvol >> 3]; | |
| rscale = snd_scaletable[ch->rightvol >> 3]; | |
| sfx = ((signed char *) sc->data) + ch->pos; | |
| for (i = 0; i < count; i++) | |
| { | |
| data = sfx[i]; | |
| paintbuffer[i].left += lscale[data]; | |
| paintbuffer[i].right += rscale[data]; | |
| } | |
| ch->pos += count; | |
| } | |
| void SND_PaintChannelFrom16(channel_t *ch, sfxcache_t *sc, int32_t count) | |
| { | |
| int32_t data; | |
| int32_t left; | |
| int32_t right; | |
| int32_t leftvol; | |
| int32_t rightvol; | |
| int16_t *sfx; | |
| int32_t i; | |
| leftvol = ch->leftvol; | |
| rightvol = ch->rightvol; | |
| sfx = ((int16_t *) sc->data) + ch->pos; | |
| for (i = 0; i < count; i++) | |
| { | |
| data = sfx[i]; | |
| left = (data * leftvol) >> 8; | |
| right = (data * rightvol) >> 8; | |
| paintbuffer[i].left += left; | |
| paintbuffer[i].right += right; | |
| } | |
| ch->pos += count; | |
| } | |
| bool SNDDMA_Init(void) | |
| { | |
| int buffer_samples = 1024; | |
| snd_inited = 0; | |
| if ((desired_bits != 8) && (desired_bits != 16)) | |
| { | |
| Con_Printf("Unknown number of audio bits: %d\n", desired_bits); | |
| return 0; | |
| } | |
| InitAudioDevice(); | |
| SetAudioStreamBufferSizeDefault(buffer_samples); | |
| stream = LoadAudioStream(desired_speed, desired_bits, 2); | |
| if (!IsAudioStreamValid(stream)) | |
| { | |
| Con_Printf("Could not create audio stream\n"); | |
| return 0; | |
| } | |
| PlayAudioStream(stream); | |
| mixbuffer = MemAlloc((buffer_samples * 2) * (desired_bits / 8)); | |
| shm = &the_shm; | |
| shm->splitbuffer = 0; | |
| shm->samplebits = desired_bits; | |
| shm->speed = desired_speed; | |
| shm->channels = 2; | |
| shm->samples = buffer_samples * shm->channels; | |
| shm->samplepos = 0; | |
| shm->submission_chunk = 1; | |
| shm->buffer = mixbuffer; | |
| snd_inited = 1; | |
| return 1; | |
| } | |
| int32_t SNDDMA_GetDMAPos(void) | |
| { | |
| return shm->samplepos; | |
| } | |
| void SNDDMA_Shutdown(void) | |
| { | |
| if (snd_inited) | |
| { | |
| MemFree(mixbuffer); | |
| UnloadAudioStream(stream); | |
| CloseAudioDevice(); | |
| snd_inited = 0; | |
| } | |
| } | |
| void SNDDMA_Submit(void) | |
| { | |
| if ((!snd_inited) || (!IsAudioStreamProcessed(stream))) | |
| { | |
| return; | |
| } | |
| int sample_frames = shm->samples / shm->channels; | |
| shm->samplepos += sample_frames; | |
| S_PaintChannels(shm->samplepos); | |
| UpdateAudioStream(stream, shm->buffer, sample_frames); | |
| } | |
| void SV_Init(void) | |
| { | |
| int32_t i; | |
| extern cvar_t sv_maxvelocity; | |
| extern cvar_t sv_gravity; | |
| extern cvar_t sv_nostep; | |
| extern cvar_t sv_friction; | |
| extern cvar_t sv_edgefriction; | |
| extern cvar_t sv_stopspeed; | |
| extern cvar_t sv_maxspeed; | |
| extern cvar_t sv_accelerate; | |
| extern cvar_t sv_idealpitchscale; | |
| extern cvar_t sv_aim; | |
| Cvar_RegisterVariable(&sv_maxvelocity); | |
| Cvar_RegisterVariable(&sv_gravity); | |
| Cvar_RegisterVariable(&sv_friction); | |
| Cvar_RegisterVariable(&sv_edgefriction); | |
| Cvar_RegisterVariable(&sv_stopspeed); | |
| Cvar_RegisterVariable(&sv_maxspeed); | |
| Cvar_RegisterVariable(&sv_accelerate); | |
| Cvar_RegisterVariable(&sv_idealpitchscale); | |
| Cvar_RegisterVariable(&sv_aim); | |
| Cvar_RegisterVariable(&sv_nostep); | |
| for (i = 0; i < MAX_MODELS; i++) | |
| sprintf(localmodels[i], "*%i", i); | |
| } | |
| void SV_StartParticle(vec3_t org, vec3_t dir, int32_t color, int32_t count) | |
| { | |
| int32_t i; | |
| int32_t v; | |
| if (sv.datagram.cursize > (MAX_DATAGRAM - 16)) | |
| return; | |
| MSG_WriteByte(&sv.datagram, svc_particle); | |
| MSG_WriteCoord(&sv.datagram, org[0]); | |
| MSG_WriteCoord(&sv.datagram, org[1]); | |
| MSG_WriteCoord(&sv.datagram, org[2]); | |
| for (i = 0; i < 3; i++) | |
| { | |
| v = dir[i] * 16; | |
| if (v > 127) | |
| v = 127; | |
| else | |
| if (v < (-128)) | |
| v = -128; | |
| MSG_WriteChar(&sv.datagram, v); | |
| } | |
| MSG_WriteByte(&sv.datagram, count); | |
| MSG_WriteByte(&sv.datagram, color); | |
| } | |
| void SV_StartSound(edict_t *entity, int32_t channel, char *sample, int32_t volume, float attenuation) | |
| { | |
| int32_t sound_num; | |
| int32_t field_mask; | |
| int32_t i; | |
| int32_t ent; | |
| if ((volume < 0) || (volume > 255)) | |
| Sys_Error("SV_StartSound: volume = %i", volume); | |
| if ((attenuation < 0) || (attenuation > 4)) | |
| Sys_Error("SV_StartSound: attenuation = %f", attenuation); | |
| if ((channel < 0) || (channel > 7)) | |
| Sys_Error("SV_StartSound: channel = %i", channel); | |
| if (sv.datagram.cursize > (MAX_DATAGRAM - 16)) | |
| return; | |
| for (sound_num = 1; (sound_num < MAX_SOUNDS) && sv.sound_precache[sound_num]; sound_num++) | |
| if (!strcmp(sample, sv.sound_precache[sound_num])) | |
| break; | |
| if ((sound_num == MAX_SOUNDS) || (!sv.sound_precache[sound_num])) | |
| { | |
| Con_Printf("SV_StartSound: %s not precacheed\n", sample); | |
| return; | |
| } | |
| ent = NUM_FOR_EDICT(entity); | |
| channel = (ent << 3) | channel; | |
| field_mask = 0; | |
| if (volume != DEFAULT_SOUND_PACKET_VOLUME) | |
| field_mask |= SND_VOLUME; | |
| if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION) | |
| field_mask |= SND_ATTENUATION; | |
| MSG_WriteByte(&sv.datagram, svc_sound); | |
| MSG_WriteByte(&sv.datagram, field_mask); | |
| if (field_mask & SND_VOLUME) | |
| MSG_WriteByte(&sv.datagram, volume); | |
| if (field_mask & SND_ATTENUATION) | |
| MSG_WriteByte(&sv.datagram, attenuation * 64); | |
| MSG_WriteShort(&sv.datagram, channel); | |
| MSG_WriteByte(&sv.datagram, sound_num); | |
| for (i = 0; i < 3; i++) | |
| MSG_WriteCoord(&sv.datagram, entity->v.origin[i] + (0.5 * (entity->v.mins[i] + entity->v.maxs[i]))); | |
| } | |
| void SV_SendServerinfo(client_t *client) | |
| { | |
| char **s; | |
| char message[2048]; | |
| MSG_WriteByte(&client->message, svc_print); | |
| sprintf(message, "%c\nVERSION %4.2f SERVER (%i CRC)", 2, VERSION, pr_crc); | |
| MSG_WriteString(&client->message, message); | |
| MSG_WriteByte(&client->message, svc_serverinfo); | |
| MSG_WriteLong(&client->message, PROTOCOL_VERSION); | |
| MSG_WriteByte(&client->message, svs.maxclients); | |
| if ((!coop.value) && deathmatch.value) | |
| MSG_WriteByte(&client->message, GAME_DEATHMATCH); | |
| else | |
| MSG_WriteByte(&client->message, GAME_COOP); | |
| sprintf(message, pr_strings + sv.edicts->v.message); | |
| MSG_WriteString(&client->message, message); | |
| for (s = sv.model_precache + 1; *s; s++) | |
| MSG_WriteString(&client->message, *s); | |
| MSG_WriteByte(&client->message, 0); | |
| for (s = sv.sound_precache + 1; *s; s++) | |
| MSG_WriteString(&client->message, *s); | |
| MSG_WriteByte(&client->message, 0); | |
| MSG_WriteByte(&client->message, svc_cdtrack); | |
| MSG_WriteByte(&client->message, sv.edicts->v.sounds); | |
| MSG_WriteByte(&client->message, sv.edicts->v.sounds); | |
| MSG_WriteByte(&client->message, svc_setview); | |
| MSG_WriteShort(&client->message, NUM_FOR_EDICT(client->edict)); | |
| MSG_WriteByte(&client->message, svc_signonnum); | |
| MSG_WriteByte(&client->message, 1); | |
| client->sendsignon = 1; | |
| client->spawned = 0; | |
| } | |
| void SV_ConnectClient(int32_t clientnum) | |
| { | |
| edict_t *ent; | |
| client_t *client; | |
| int32_t edictnum; | |
| struct qsocket_s *netconnection; | |
| int32_t i; | |
| float spawn_parms[NUM_SPAWN_PARMS]; | |
| client = svs.clients + clientnum; | |
| Con_DPrintf("Client %s connected\n", client->netconnection->address); | |
| edictnum = clientnum + 1; | |
| ent = EDICT_NUM(edictnum); | |
| netconnection = client->netconnection; | |
| if (sv.loadgame) | |
| memcpy(spawn_parms, client->spawn_parms, sizeof(spawn_parms)); | |
| memset(client, 0, sizeof(*client)); | |
| client->netconnection = netconnection; | |
| strcpy(client->name, "unconnected"); | |
| client->active = 1; | |
| client->spawned = 0; | |
| client->edict = ent; | |
| client->message.data = client->msgbuf; | |
| client->message.maxsize = sizeof(client->msgbuf); | |
| client->message.allowoverflow = 1; | |
| client->privileged = 0; | |
| if (sv.loadgame) | |
| memcpy(client->spawn_parms, spawn_parms, sizeof(spawn_parms)); | |
| else | |
| { | |
| PR_ExecuteProgram(pr_global_struct->SetNewParms); | |
| for (i = 0; i < NUM_SPAWN_PARMS; i++) | |
| client->spawn_parms[i] = (&pr_global_struct->parm1)[i]; | |
| } | |
| SV_SendServerinfo(client); | |
| } | |
| void SV_CheckForNewClients(void) | |
| { | |
| struct qsocket_s *ret; | |
| int32_t i; | |
| while (1) | |
| { | |
| ret = NET_CheckNewConnections(); | |
| if (!ret) | |
| break; | |
| for (i = 0; i < svs.maxclients; i++) | |
| if (!svs.clients[i].active) | |
| break; | |
| if (i == svs.maxclients) | |
| Sys_Error("Host_CheckForNewClients: no free clients"); | |
| svs.clients[i].netconnection = ret; | |
| SV_ConnectClient(i); | |
| net_activeconnections++; | |
| } | |
| } | |
| void SV_ClearDatagram(void) | |
| { | |
| SZ_Clear(&sv.datagram); | |
| } | |
| void SV_AddToFatPVS(vec3_t org, mnode_t *node) | |
| { | |
| int32_t i; | |
| uint8_t *pvs; | |
| mplane_t *plane; | |
| float d; | |
| while (1) | |
| { | |
| if (node->contents < 0) | |
| { | |
| if (node->contents != CONTENTS_SOLID) | |
| { | |
| pvs = Mod_LeafPVS((mleaf_t *) node, sv.worldmodel); | |
| for (i = 0; i < fatbytes; i++) | |
| fatpvs[i] |= pvs[i]; | |
| } | |
| return; | |
| } | |
| plane = node->plane; | |
| d = DotProduct(org, plane->normal) - plane->dist; | |
| if (d > 8) | |
| node = node->children[0]; | |
| else | |
| if (d < (-8)) | |
| node = node->children[1]; | |
| else | |
| { | |
| SV_AddToFatPVS(org, node->children[0]); | |
| node = node->children[1]; | |
| } | |
| } | |
| } | |
| uint8_t *SV_FatPVS(vec3_t org) | |
| { | |
| fatbytes = (sv.worldmodel->numleafs + 31) >> 3; | |
| memset(fatpvs, 0, fatbytes); | |
| SV_AddToFatPVS(org, sv.worldmodel->nodes); | |
| return fatpvs; | |
| } | |
| void SV_WriteEntitiesToClient(edict_t *clent, sizebuf_t *msg) | |
| { | |
| int32_t e; | |
| int32_t i; | |
| int32_t bits; | |
| uint8_t *pvs; | |
| vec3_t org; | |
| float miss; | |
| edict_t *ent; | |
| VectorAdd(clent->v.origin, clent->v.view_ofs, org); | |
| pvs = SV_FatPVS(org); | |
| ent = NEXT_EDICT(sv.edicts); | |
| for (e = 1; e < sv.num_edicts; e++, ent = NEXT_EDICT(ent)) | |
| { | |
| if (ent != clent) | |
| { | |
| if ((!ent->v.modelindex) || (!pr_strings[ent->v.model])) | |
| continue; | |
| for (i = 0; i < ent->num_leafs; i++) | |
| if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i] & 7))) | |
| break; | |
| if (i == ent->num_leafs) | |
| continue; | |
| } | |
| if ((msg->maxsize - msg->cursize) < 16) | |
| { | |
| Con_Printf("packet overflow\n"); | |
| return; | |
| } | |
| bits = 0; | |
| for (i = 0; i < 3; i++) | |
| { | |
| miss = ent->v.origin[i] - ent->baseline.origin[i]; | |
| if ((miss < (-0.1)) || (miss > 0.1)) | |
| bits |= U_ORIGIN1 << i; | |
| } | |
| if (ent->v.angles[0] != ent->baseline.angles[0]) | |
| bits |= U_ANGLE1; | |
| if (ent->v.angles[1] != ent->baseline.angles[1]) | |
| bits |= U_ANGLE2; | |
| if (ent->v.angles[2] != ent->baseline.angles[2]) | |
| bits |= U_ANGLE3; | |
| if (ent->v.movetype == MOVETYPE_STEP) | |
| bits |= U_NOLERP; | |
| if (ent->baseline.colormap != ent->v.colormap) | |
| bits |= U_COLORMAP; | |
| if (ent->baseline.skin != ent->v.skin) | |
| bits |= U_SKIN; | |
| if (ent->baseline.frame != ent->v.frame) | |
| bits |= U_FRAME; | |
| if (ent->baseline.effects != ent->v.effects) | |
| bits |= U_EFFECTS; | |
| if (ent->baseline.modelindex != ent->v.modelindex) | |
| bits |= U_MODEL; | |
| if (e >= 256) | |
| bits |= U_LONGENTITY; | |
| if (bits >= 256) | |
| bits |= U_MOREBITS; | |
| MSG_WriteByte(msg, bits | U_SIGNAL); | |
| if (bits & U_MOREBITS) | |
| MSG_WriteByte(msg, bits >> 8); | |
| if (bits & U_LONGENTITY) | |
| MSG_WriteShort(msg, e); | |
| else | |
| MSG_WriteByte(msg, e); | |
| if (bits & U_MODEL) | |
| MSG_WriteByte(msg, ent->v.modelindex); | |
| if (bits & U_FRAME) | |
| MSG_WriteByte(msg, ent->v.frame); | |
| if (bits & U_COLORMAP) | |
| MSG_WriteByte(msg, ent->v.colormap); | |
| if (bits & U_SKIN) | |
| MSG_WriteByte(msg, ent->v.skin); | |
| if (bits & U_EFFECTS) | |
| MSG_WriteByte(msg, ent->v.effects); | |
| if (bits & U_ORIGIN1) | |
| MSG_WriteCoord(msg, ent->v.origin[0]); | |
| if (bits & U_ANGLE1) | |
| MSG_WriteAngle(msg, ent->v.angles[0]); | |
| if (bits & U_ORIGIN2) | |
| MSG_WriteCoord(msg, ent->v.origin[1]); | |
| if (bits & U_ANGLE2) | |
| MSG_WriteAngle(msg, ent->v.angles[1]); | |
| if (bits & U_ORIGIN3) | |
| MSG_WriteCoord(msg, ent->v.origin[2]); | |
| if (bits & U_ANGLE3) | |
| MSG_WriteAngle(msg, ent->v.angles[2]); | |
| } | |
| } | |
| void SV_CleanupEnts(void) | |
| { | |
| int32_t e; | |
| edict_t *ent; | |
| ent = NEXT_EDICT(sv.edicts); | |
| for (e = 1; e < sv.num_edicts; e++, ent = NEXT_EDICT(ent)) | |
| { | |
| ent->v.effects = ((int32_t) ent->v.effects) & (~EF_MUZZLEFLASH); | |
| } | |
| } | |
| void SV_WriteClientdataToMessage(edict_t *ent, sizebuf_t *msg) | |
| { | |
| int32_t bits; | |
| int32_t i; | |
| edict_t *other; | |
| int32_t items; | |
| eval_t *val; | |
| if (ent->v.dmg_take || ent->v.dmg_save) | |
| { | |
| other = PROG_TO_EDICT(ent->v.dmg_inflictor); | |
| MSG_WriteByte(msg, svc_damage); | |
| MSG_WriteByte(msg, ent->v.dmg_save); | |
| MSG_WriteByte(msg, ent->v.dmg_take); | |
| for (i = 0; i < 3; i++) | |
| MSG_WriteCoord(msg, other->v.origin[i] + (0.5 * (other->v.mins[i] + other->v.maxs[i]))); | |
| ent->v.dmg_take = 0; | |
| ent->v.dmg_save = 0; | |
| } | |
| SV_SetIdealPitch(); | |
| if (ent->v.fixangle) | |
| { | |
| MSG_WriteByte(msg, svc_setangle); | |
| for (i = 0; i < 3; i++) | |
| MSG_WriteAngle(msg, ent->v.angles[i]); | |
| ent->v.fixangle = 0; | |
| } | |
| bits = 0; | |
| if (ent->v.view_ofs[2] != DEFAULT_VIEWHEIGHT) | |
| bits |= SU_VIEWHEIGHT; | |
| if (ent->v.idealpitch) | |
| bits |= SU_IDEALPITCH; | |
| val = GetEdictFieldValue(ent, "items2"); | |
| if (val) | |
| items = ((int32_t) ent->v.items) | (((int32_t) val->_float) << 23); | |
| else | |
| items = ((int32_t) ent->v.items) | (((int32_t) pr_global_struct->serverflags) << 28); | |
| bits |= SU_ITEMS; | |
| if (((int32_t) ent->v.flags) & FL_ONGROUND) | |
| bits |= SU_ONGROUND; | |
| if (ent->v.waterlevel >= 2) | |
| bits |= SU_INWATER; | |
| for (i = 0; i < 3; i++) | |
| { | |
| if (ent->v.punchangle[i]) | |
| bits |= SU_PUNCH1 << i; | |
| if (ent->v.velocity[i]) | |
| bits |= SU_VELOCITY1 << i; | |
| } | |
| if (ent->v.weaponframe) | |
| bits |= SU_WEAPONFRAME; | |
| if (ent->v.armorvalue) | |
| bits |= SU_ARMOR; | |
| bits |= SU_WEAPON; | |
| MSG_WriteByte(msg, svc_clientdata); | |
| MSG_WriteShort(msg, bits); | |
| if (bits & SU_VIEWHEIGHT) | |
| MSG_WriteChar(msg, ent->v.view_ofs[2]); | |
| if (bits & SU_IDEALPITCH) | |
| MSG_WriteChar(msg, ent->v.idealpitch); | |
| for (i = 0; i < 3; i++) | |
| { | |
| if (bits & (SU_PUNCH1 << i)) | |
| MSG_WriteChar(msg, ent->v.punchangle[i]); | |
| if (bits & (SU_VELOCITY1 << i)) | |
| MSG_WriteChar(msg, ent->v.velocity[i] / 16); | |
| } | |
| MSG_WriteLong(msg, items); | |
| if (bits & SU_WEAPONFRAME) | |
| MSG_WriteByte(msg, ent->v.weaponframe); | |
| if (bits & SU_ARMOR) | |
| MSG_WriteByte(msg, ent->v.armorvalue); | |
| if (bits & SU_WEAPON) | |
| MSG_WriteByte(msg, SV_ModelIndex(pr_strings + ent->v.weaponmodel)); | |
| MSG_WriteShort(msg, ent->v.health); | |
| MSG_WriteByte(msg, ent->v.currentammo); | |
| MSG_WriteByte(msg, ent->v.ammo_shells); | |
| MSG_WriteByte(msg, ent->v.ammo_nails); | |
| MSG_WriteByte(msg, ent->v.ammo_rockets); | |
| MSG_WriteByte(msg, ent->v.ammo_cells); | |
| if (standard_quake) | |
| { | |
| MSG_WriteByte(msg, ent->v.weapon); | |
| } | |
| else | |
| { | |
| for (i = 0; i < 32; i++) | |
| { | |
| if (((int32_t) ent->v.weapon) & (1 << i)) | |
| { | |
| MSG_WriteByte(msg, i); | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| bool SV_SendClientDatagram(client_t *client) | |
| { | |
| uint8_t buf[MAX_DATAGRAM]; | |
| sizebuf_t msg; | |
| msg.data = buf; | |
| msg.maxsize = sizeof(buf); | |
| msg.cursize = 0; | |
| MSG_WriteByte(&msg, svc_time); | |
| MSG_WriteFloat(&msg, sv.time); | |
| SV_WriteClientdataToMessage(client->edict, &msg); | |
| SV_WriteEntitiesToClient(client->edict, &msg); | |
| if ((msg.cursize + sv.datagram.cursize) < msg.maxsize) | |
| SZ_Write(&msg, sv.datagram.data, sv.datagram.cursize); | |
| if (NET_SendUnreliableMessage(client->netconnection, &msg) == (-1)) | |
| { | |
| SV_DropClient(1); | |
| return 0; | |
| } | |
| return 1; | |
| } | |
| void SV_UpdateToReliableMessages(void) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| client_t *client; | |
| for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++) | |
| { | |
| if (host_client->old_frags != host_client->edict->v.frags) | |
| { | |
| for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++) | |
| { | |
| if (!client->active) | |
| continue; | |
| MSG_WriteByte(&client->message, svc_updatefrags); | |
| MSG_WriteByte(&client->message, i); | |
| MSG_WriteShort(&client->message, host_client->edict->v.frags); | |
| } | |
| host_client->old_frags = host_client->edict->v.frags; | |
| } | |
| } | |
| for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++) | |
| { | |
| if (!client->active) | |
| continue; | |
| SZ_Write(&client->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize); | |
| } | |
| SZ_Clear(&sv.reliable_datagram); | |
| } | |
| void SV_SendNop(client_t *client) | |
| { | |
| sizebuf_t msg; | |
| uint8_t buf[4]; | |
| msg.data = buf; | |
| msg.maxsize = sizeof(buf); | |
| msg.cursize = 0; | |
| MSG_WriteChar(&msg, svc_nop); | |
| if (NET_SendUnreliableMessage(client->netconnection, &msg) == (-1)) | |
| SV_DropClient(1); | |
| client->last_message = realtime; | |
| } | |
| void SV_SendClientMessages(void) | |
| { | |
| int32_t i; | |
| SV_UpdateToReliableMessages(); | |
| for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++) | |
| { | |
| if (!host_client->active) | |
| continue; | |
| if (host_client->spawned) | |
| { | |
| if (!SV_SendClientDatagram(host_client)) | |
| continue; | |
| } | |
| else | |
| { | |
| if (!host_client->sendsignon) | |
| { | |
| if ((realtime - host_client->last_message) > 5) | |
| SV_SendNop(host_client); | |
| continue; | |
| } | |
| } | |
| if (host_client->message.overflowed) | |
| { | |
| SV_DropClient(1); | |
| host_client->message.overflowed = 0; | |
| continue; | |
| } | |
| if (host_client->message.cursize || host_client->dropasap) | |
| { | |
| if (!NET_CanSendMessage(host_client->netconnection)) | |
| { | |
| continue; | |
| } | |
| if (host_client->dropasap) | |
| SV_DropClient(0); | |
| else | |
| { | |
| if (NET_SendMessage(host_client->netconnection, &host_client->message) == (-1)) | |
| SV_DropClient(1); | |
| SZ_Clear(&host_client->message); | |
| host_client->last_message = realtime; | |
| host_client->sendsignon = 0; | |
| } | |
| } | |
| } | |
| SV_CleanupEnts(); | |
| } | |
| int32_t SV_ModelIndex(char *name) | |
| { | |
| int32_t i; | |
| if ((!name) || (!name[0])) | |
| return 0; | |
| for (i = 0; (i < MAX_MODELS) && sv.model_precache[i]; i++) | |
| if (!strcmp(sv.model_precache[i], name)) | |
| return i; | |
| if ((i == MAX_MODELS) || (!sv.model_precache[i])) | |
| Sys_Error("SV_ModelIndex: model %s not precached", name); | |
| return i; | |
| } | |
| void SV_CreateBaseline(void) | |
| { | |
| int32_t i; | |
| edict_t *svent; | |
| int32_t entnum; | |
| for (entnum = 0; entnum < sv.num_edicts; entnum++) | |
| { | |
| svent = EDICT_NUM(entnum); | |
| if (svent->free) | |
| continue; | |
| if ((entnum > svs.maxclients) && (!svent->v.modelindex)) | |
| continue; | |
| VectorCopy(svent->v.origin, svent->baseline.origin); | |
| VectorCopy(svent->v.angles, svent->baseline.angles); | |
| svent->baseline.frame = svent->v.frame; | |
| svent->baseline.skin = svent->v.skin; | |
| if ((entnum > 0) && (entnum <= svs.maxclients)) | |
| { | |
| svent->baseline.colormap = entnum; | |
| svent->baseline.modelindex = SV_ModelIndex("progs/player.mdl"); | |
| } | |
| else | |
| { | |
| svent->baseline.colormap = 0; | |
| svent->baseline.modelindex = SV_ModelIndex(pr_strings + svent->v.model); | |
| } | |
| MSG_WriteByte(&sv.signon, svc_spawnbaseline); | |
| MSG_WriteShort(&sv.signon, entnum); | |
| MSG_WriteByte(&sv.signon, svent->baseline.modelindex); | |
| MSG_WriteByte(&sv.signon, svent->baseline.frame); | |
| MSG_WriteByte(&sv.signon, svent->baseline.colormap); | |
| MSG_WriteByte(&sv.signon, svent->baseline.skin); | |
| for (i = 0; i < 3; i++) | |
| { | |
| MSG_WriteCoord(&sv.signon, svent->baseline.origin[i]); | |
| MSG_WriteAngle(&sv.signon, svent->baseline.angles[i]); | |
| } | |
| } | |
| } | |
| void SV_SendReconnect(void) | |
| { | |
| char data[128]; | |
| sizebuf_t msg; | |
| msg.data = data; | |
| msg.cursize = 0; | |
| msg.maxsize = sizeof(data); | |
| MSG_WriteChar(&msg, svc_stufftext); | |
| MSG_WriteString(&msg, "reconnect\n"); | |
| NET_SendToAll(&msg, 5); | |
| if (cls.state != ca_dedicated) | |
| Cmd_ExecuteString("reconnect\n", src_command); | |
| } | |
| void SV_SaveSpawnparms(void) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| svs.serverflags = pr_global_struct->serverflags; | |
| for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++) | |
| { | |
| if (!host_client->active) | |
| continue; | |
| pr_global_struct->self = EDICT_TO_PROG(host_client->edict); | |
| PR_ExecuteProgram(pr_global_struct->SetChangeParms); | |
| for (j = 0; j < NUM_SPAWN_PARMS; j++) | |
| host_client->spawn_parms[j] = (&pr_global_struct->parm1)[j]; | |
| } | |
| } | |
| void SV_SpawnServer(char *server) | |
| { | |
| edict_t *ent; | |
| int32_t i; | |
| if (hostname.string[0] == 0) | |
| Cvar_Set("hostname", "UNNAMED"); | |
| scr_centertime_off = 0; | |
| Con_DPrintf("SpawnServer: %s\n", server); | |
| svs.changelevel_issued = 0; | |
| if (sv.active) | |
| { | |
| SV_SendReconnect(); | |
| } | |
| if (coop.value) | |
| Cvar_SetValue("deathmatch", 0); | |
| current_skill = (int32_t) (skill.value + 0.5); | |
| if (current_skill < 0) | |
| current_skill = 0; | |
| if (current_skill > 3) | |
| current_skill = 3; | |
| Cvar_SetValue("skill", (float) current_skill); | |
| Host_ClearMemory(); | |
| memset(&sv, 0, sizeof(sv)); | |
| strcpy(sv.name, server); | |
| PR_LoadProgs(); | |
| sv.max_edicts = MAX_EDICTS; | |
| sv.edicts = Hunk_AllocName(sv.max_edicts * pr_edict_size, "edicts"); | |
| sv.datagram.maxsize = sizeof(sv.datagram_buf); | |
| sv.datagram.cursize = 0; | |
| sv.datagram.data = sv.datagram_buf; | |
| sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf); | |
| sv.reliable_datagram.cursize = 0; | |
| sv.reliable_datagram.data = sv.reliable_datagram_buf; | |
| sv.signon.maxsize = sizeof(sv.signon_buf); | |
| sv.signon.cursize = 0; | |
| sv.signon.data = sv.signon_buf; | |
| sv.num_edicts = svs.maxclients + 1; | |
| for (i = 0; i < svs.maxclients; i++) | |
| { | |
| ent = EDICT_NUM(i + 1); | |
| svs.clients[i].edict = ent; | |
| } | |
| sv.state = ss_loading; | |
| sv.paused = 0; | |
| sv.time = 1.0; | |
| strcpy(sv.name, server); | |
| sprintf(sv.modelname, "maps/%s.bsp", server); | |
| sv.worldmodel = Mod_ForName(sv.modelname, 0); | |
| if (!sv.worldmodel) | |
| { | |
| Con_Printf("Couldn't spawn server %s\n", sv.modelname); | |
| sv.active = 0; | |
| return; | |
| } | |
| sv.models[1] = sv.worldmodel; | |
| SV_ClearWorld(); | |
| sv.sound_precache[0] = pr_strings; | |
| sv.model_precache[0] = pr_strings; | |
| sv.model_precache[1] = sv.modelname; | |
| for (i = 1; i < sv.worldmodel->numsubmodels; i++) | |
| { | |
| sv.model_precache[1 + i] = localmodels[i]; | |
| sv.models[i + 1] = Mod_ForName(localmodels[i], 0); | |
| } | |
| ent = EDICT_NUM(0); | |
| memset(&ent->v, 0, progs->entityfields * 4); | |
| ent->free = 0; | |
| ent->v.model = sv.worldmodel->name - pr_strings; | |
| ent->v.modelindex = 1; | |
| ent->v.solid = SOLID_BSP; | |
| ent->v.movetype = MOVETYPE_PUSH; | |
| if (coop.value) | |
| pr_global_struct->coop = coop.value; | |
| else | |
| pr_global_struct->deathmatch = deathmatch.value; | |
| pr_global_struct->mapname = sv.name - pr_strings; | |
| pr_global_struct->serverflags = svs.serverflags; | |
| ED_LoadFromFile(sv.worldmodel->entities); | |
| sv.active = 1; | |
| sv.state = ss_active; | |
| host_frametime = 0.1; | |
| SV_Physics(); | |
| SV_Physics(); | |
| SV_CreateBaseline(); | |
| for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++) | |
| if (host_client->active) | |
| SV_SendServerinfo(host_client); | |
| Con_DPrintf("Server spawned.\n"); | |
| } | |
| bool SV_CheckBottom(edict_t *ent) | |
| { | |
| vec3_t mins; | |
| vec3_t maxs; | |
| vec3_t start; | |
| vec3_t stop; | |
| trace_t trace; | |
| int32_t x; | |
| int32_t y; | |
| float mid; | |
| float bottom; | |
| VectorAdd(ent->v.origin, ent->v.mins, mins); | |
| VectorAdd(ent->v.origin, ent->v.maxs, maxs); | |
| start[2] = mins[2] - 1; | |
| for (x = 0; x <= 1; x++) | |
| for (y = 0; y <= 1; y++) | |
| { | |
| start[0] = (x) ? (maxs[0]) : (mins[0]); | |
| start[1] = (y) ? (maxs[1]) : (mins[1]); | |
| if (SV_PointContents(start) != CONTENTS_SOLID) | |
| goto realcheck; | |
| } | |
| c_yes++; | |
| return 1; | |
| realcheck: | |
| c_no++; | |
| start[2] = mins[2]; | |
| start[0] = (stop[0] = (mins[0] + maxs[0]) * 0.5); | |
| start[1] = (stop[1] = (mins[1] + maxs[1]) * 0.5); | |
| stop[2] = start[2] - (2 * STEPSIZE); | |
| trace = SV_Move(start, vec3_origin, vec3_origin, stop, 1, ent); | |
| if (trace.fraction == 1.0) | |
| return 0; | |
| mid = (bottom = trace.endpos[2]); | |
| for (x = 0; x <= 1; x++) | |
| for (y = 0; y <= 1; y++) | |
| { | |
| start[0] = (stop[0] = (x) ? (maxs[0]) : (mins[0])); | |
| start[1] = (stop[1] = (y) ? (maxs[1]) : (mins[1])); | |
| trace = SV_Move(start, vec3_origin, vec3_origin, stop, 1, ent); | |
| if ((trace.fraction != 1.0) && (trace.endpos[2] > bottom)) | |
| bottom = trace.endpos[2]; | |
| if ((trace.fraction == 1.0) || ((mid - trace.endpos[2]) > STEPSIZE)) | |
| return 0; | |
| } | |
| c_yes++; | |
| return 1; | |
| } | |
| bool SV_movestep(edict_t *ent, vec3_t move, bool relink) | |
| { | |
| float dz; | |
| vec3_t oldorg; | |
| vec3_t neworg; | |
| vec3_t end; | |
| trace_t trace; | |
| int32_t i; | |
| edict_t *enemy; | |
| VectorCopy(ent->v.origin, oldorg); | |
| VectorAdd(ent->v.origin, move, neworg); | |
| if (((int32_t) ent->v.flags) & (FL_SWIM | FL_FLY)) | |
| { | |
| for (i = 0; i < 2; i++) | |
| { | |
| VectorAdd(ent->v.origin, move, neworg); | |
| enemy = PROG_TO_EDICT(ent->v.enemy); | |
| if ((i == 0) && (enemy != sv.edicts)) | |
| { | |
| dz = ent->v.origin[2] - PROG_TO_EDICT(ent->v.enemy)->v.origin[2]; | |
| if (dz > 40) | |
| neworg[2] -= 8; | |
| if (dz < 30) | |
| neworg[2] += 8; | |
| } | |
| trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, neworg, 0, ent); | |
| if (trace.fraction == 1) | |
| { | |
| if ((((int32_t) ent->v.flags) & FL_SWIM) && (SV_PointContents(trace.endpos) == CONTENTS_EMPTY)) | |
| return 0; | |
| VectorCopy(trace.endpos, ent->v.origin); | |
| if (relink) | |
| SV_LinkEdict(ent, 1); | |
| return 1; | |
| } | |
| if (enemy == sv.edicts) | |
| break; | |
| } | |
| return 0; | |
| } | |
| neworg[2] += STEPSIZE; | |
| VectorCopy(neworg, end); | |
| end[2] -= STEPSIZE * 2; | |
| trace = SV_Move(neworg, ent->v.mins, ent->v.maxs, end, 0, ent); | |
| if (trace.allsolid) | |
| return 0; | |
| if (trace.startsolid) | |
| { | |
| neworg[2] -= STEPSIZE; | |
| trace = SV_Move(neworg, ent->v.mins, ent->v.maxs, end, 0, ent); | |
| if (trace.allsolid || trace.startsolid) | |
| return 0; | |
| } | |
| if (trace.fraction == 1) | |
| { | |
| if (((int32_t) ent->v.flags) & FL_PARTIALGROUND) | |
| { | |
| VectorAdd(ent->v.origin, move, ent->v.origin); | |
| if (relink) | |
| SV_LinkEdict(ent, 1); | |
| ent->v.flags = ((int32_t) ent->v.flags) & (~FL_ONGROUND); | |
| return 1; | |
| } | |
| return 0; | |
| } | |
| VectorCopy(trace.endpos, ent->v.origin); | |
| if (!SV_CheckBottom(ent)) | |
| { | |
| if (((int32_t) ent->v.flags) & FL_PARTIALGROUND) | |
| { | |
| if (relink) | |
| SV_LinkEdict(ent, 1); | |
| return 1; | |
| } | |
| VectorCopy(oldorg, ent->v.origin); | |
| return 0; | |
| } | |
| if (((int32_t) ent->v.flags) & FL_PARTIALGROUND) | |
| { | |
| ent->v.flags = ((int32_t) ent->v.flags) & (~FL_PARTIALGROUND); | |
| } | |
| ent->v.groundentity = EDICT_TO_PROG(trace.ent); | |
| if (relink) | |
| SV_LinkEdict(ent, 1); | |
| return 1; | |
| } | |
| bool SV_StepDirection(edict_t *ent, float yaw, float dist) | |
| { | |
| vec3_t move; | |
| vec3_t oldorigin; | |
| float delta; | |
| ent->v.ideal_yaw = yaw; | |
| PF_changeyaw(); | |
| yaw = ((yaw * M_PI) * 2) / 360; | |
| move[0] = cos(yaw) * dist; | |
| move[1] = sin(yaw) * dist; | |
| move[2] = 0; | |
| VectorCopy(ent->v.origin, oldorigin); | |
| if (SV_movestep(ent, move, 0)) | |
| { | |
| delta = ent->v.angles[YAW] - ent->v.ideal_yaw; | |
| if ((delta > 45) && (delta < 315)) | |
| { | |
| VectorCopy(oldorigin, ent->v.origin); | |
| } | |
| SV_LinkEdict(ent, 1); | |
| return 1; | |
| } | |
| SV_LinkEdict(ent, 1); | |
| return 0; | |
| } | |
| void SV_FixCheckBottom(edict_t *ent) | |
| { | |
| ent->v.flags = ((int32_t) ent->v.flags) | FL_PARTIALGROUND; | |
| } | |
| void SV_NewChaseDir(edict_t *actor, edict_t *enemy, float dist) | |
| { | |
| float deltax; | |
| float deltay; | |
| float d[3]; | |
| float tdir; | |
| float olddir; | |
| float turnaround; | |
| olddir = anglemod(((int32_t) (actor->v.ideal_yaw / 45)) * 45); | |
| turnaround = anglemod(olddir - 180); | |
| deltax = enemy->v.origin[0] - actor->v.origin[0]; | |
| deltay = enemy->v.origin[1] - actor->v.origin[1]; | |
| if (deltax > 10) | |
| d[1] = 0; | |
| else | |
| if (deltax < (-10)) | |
| d[1] = 180; | |
| else | |
| d[1] = DI_NODIR; | |
| if (deltay < (-10)) | |
| d[2] = 270; | |
| else | |
| if (deltay > 10) | |
| d[2] = 90; | |
| else | |
| d[2] = DI_NODIR; | |
| if ((d[1] != DI_NODIR) && (d[2] != DI_NODIR)) | |
| { | |
| if (d[1] == 0) | |
| tdir = (d[2] == 90) ? (45) : (315); | |
| else | |
| tdir = (d[2] == 90) ? (135) : (215); | |
| if ((tdir != turnaround) && SV_StepDirection(actor, tdir, dist)) | |
| return; | |
| } | |
| if (((rand() & 3) & 1) || (fabsf(deltay) > fabsf(deltax))) | |
| { | |
| tdir = d[1]; | |
| d[1] = d[2]; | |
| d[2] = tdir; | |
| } | |
| if (((d[1] != DI_NODIR) && (d[1] != turnaround)) && SV_StepDirection(actor, d[1], dist)) | |
| return; | |
| if (((d[2] != DI_NODIR) && (d[2] != turnaround)) && SV_StepDirection(actor, d[2], dist)) | |
| return; | |
| if ((olddir != DI_NODIR) && SV_StepDirection(actor, olddir, dist)) | |
| return; | |
| if (rand() & 1) | |
| { | |
| for (tdir = 0; tdir <= 315; tdir += 45) | |
| if ((tdir != turnaround) && SV_StepDirection(actor, tdir, dist)) | |
| return; | |
| } | |
| else | |
| { | |
| for (tdir = 315; tdir >= 0; tdir -= 45) | |
| if ((tdir != turnaround) && SV_StepDirection(actor, tdir, dist)) | |
| return; | |
| } | |
| if ((turnaround != DI_NODIR) && SV_StepDirection(actor, turnaround, dist)) | |
| return; | |
| actor->v.ideal_yaw = olddir; | |
| if (!SV_CheckBottom(actor)) | |
| SV_FixCheckBottom(actor); | |
| } | |
| bool SV_CloseEnough(edict_t *ent, edict_t *goal, float dist) | |
| { | |
| int32_t i; | |
| for (i = 0; i < 3; i++) | |
| { | |
| if (goal->v.absmin[i] > (ent->v.absmax[i] + dist)) | |
| return 0; | |
| if (goal->v.absmax[i] < (ent->v.absmin[i] - dist)) | |
| return 0; | |
| } | |
| return 1; | |
| } | |
| void SV_MoveToGoal(void) | |
| { | |
| edict_t *ent; | |
| edict_t *goal; | |
| float dist; | |
| ent = PROG_TO_EDICT(pr_global_struct->self); | |
| goal = PROG_TO_EDICT(ent->v.goalentity); | |
| dist = G_FLOAT(OFS_PARM0); | |
| if (!(((int32_t) ent->v.flags) & ((FL_ONGROUND | FL_FLY) | FL_SWIM))) | |
| { | |
| G_FLOAT(OFS_RETURN) = 0; | |
| return; | |
| } | |
| if ((PROG_TO_EDICT(ent->v.enemy) != sv.edicts) && SV_CloseEnough(ent, goal, dist)) | |
| return; | |
| if (((rand() & 3) == 1) || (!SV_StepDirection(ent, ent->v.ideal_yaw, dist))) | |
| { | |
| SV_NewChaseDir(ent, goal, dist); | |
| } | |
| } | |
| void SV_CheckAllEnts(void) | |
| { | |
| int32_t e; | |
| edict_t *check; | |
| check = NEXT_EDICT(sv.edicts); | |
| for (e = 1; e < sv.num_edicts; e++, check = NEXT_EDICT(check)) | |
| { | |
| if (check->free) | |
| continue; | |
| if (((check->v.movetype == MOVETYPE_PUSH) || (check->v.movetype == MOVETYPE_NONE)) || (check->v.movetype == MOVETYPE_NOCLIP)) | |
| continue; | |
| if (SV_TestEntityPosition(check)) | |
| Con_Printf("entity in invalid position\n"); | |
| } | |
| } | |
| void SV_CheckVelocity(edict_t *ent) | |
| { | |
| int32_t i; | |
| for (i = 0; i < 3; i++) | |
| { | |
| if (IS_NAN(ent->v.velocity[i])) | |
| { | |
| Con_Printf("Got a NaN velocity on %s\n", pr_strings + ent->v.classname); | |
| ent->v.velocity[i] = 0; | |
| } | |
| if (IS_NAN(ent->v.origin[i])) | |
| { | |
| Con_Printf("Got a NaN origin on %s\n", pr_strings + ent->v.classname); | |
| ent->v.origin[i] = 0; | |
| } | |
| if (ent->v.velocity[i] > sv_maxvelocity.value) | |
| ent->v.velocity[i] = sv_maxvelocity.value; | |
| else | |
| if (ent->v.velocity[i] < (-sv_maxvelocity.value)) | |
| ent->v.velocity[i] = -sv_maxvelocity.value; | |
| } | |
| } | |
| bool SV_RunThink(edict_t *ent) | |
| { | |
| float thinktime; | |
| thinktime = ent->v.nextthink; | |
| if ((thinktime <= 0) || (thinktime > (sv.time + host_frametime))) | |
| return 1; | |
| if (thinktime < sv.time) | |
| thinktime = sv.time; | |
| ent->v.nextthink = 0; | |
| pr_global_struct->time = thinktime; | |
| pr_global_struct->self = EDICT_TO_PROG(ent); | |
| pr_global_struct->other = EDICT_TO_PROG(sv.edicts); | |
| PR_ExecuteProgram(ent->v.think); | |
| return !ent->free; | |
| } | |
| void SV_Impact(edict_t *e1, edict_t *e2) | |
| { | |
| int32_t old_self; | |
| int32_t old_other; | |
| old_self = pr_global_struct->self; | |
| old_other = pr_global_struct->other; | |
| pr_global_struct->time = sv.time; | |
| if (e1->v.touch && (e1->v.solid != SOLID_NOT)) | |
| { | |
| pr_global_struct->self = EDICT_TO_PROG(e1); | |
| pr_global_struct->other = EDICT_TO_PROG(e2); | |
| PR_ExecuteProgram(e1->v.touch); | |
| } | |
| if (e2->v.touch && (e2->v.solid != SOLID_NOT)) | |
| { | |
| pr_global_struct->self = EDICT_TO_PROG(e2); | |
| pr_global_struct->other = EDICT_TO_PROG(e1); | |
| PR_ExecuteProgram(e2->v.touch); | |
| } | |
| pr_global_struct->self = old_self; | |
| pr_global_struct->other = old_other; | |
| } | |
| int32_t ClipVelocity(vec3_t in, vec3_t normal, vec3_t out, float overbounce) | |
| { | |
| float backoff; | |
| float change; | |
| int32_t i; | |
| int32_t blocked; | |
| blocked = 0; | |
| if (normal[2] > 0) | |
| blocked |= 1; | |
| if (!normal[2]) | |
| blocked |= 2; | |
| backoff = DotProduct(in, normal) * overbounce; | |
| for (i = 0; i < 3; i++) | |
| { | |
| change = normal[i] * backoff; | |
| out[i] = in[i] - change; | |
| if ((out[i] > (-STOP_EPSILON)) && (out[i] < STOP_EPSILON)) | |
| out[i] = 0; | |
| } | |
| return blocked; | |
| } | |
| int32_t SV_FlyMove(edict_t *ent, float time, trace_t *steptrace) | |
| { | |
| int32_t bumpcount; | |
| int32_t numbumps; | |
| vec3_t dir; | |
| float d; | |
| int32_t numplanes; | |
| vec3_t planes[MAX_CLIP_PLANES]; | |
| vec3_t primal_velocity; | |
| vec3_t original_velocity; | |
| vec3_t new_velocity; | |
| int32_t i; | |
| int32_t j; | |
| trace_t trace; | |
| vec3_t end; | |
| float time_left; | |
| int32_t blocked; | |
| numbumps = 4; | |
| blocked = 0; | |
| VectorCopy(ent->v.velocity, original_velocity); | |
| VectorCopy(ent->v.velocity, primal_velocity); | |
| numplanes = 0; | |
| time_left = time; | |
| for (bumpcount = 0; bumpcount < numbumps; bumpcount++) | |
| { | |
| if (((!ent->v.velocity[0]) && (!ent->v.velocity[1])) && (!ent->v.velocity[2])) | |
| break; | |
| for (i = 0; i < 3; i++) | |
| end[i] = ent->v.origin[i] + (time_left * ent->v.velocity[i]); | |
| trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, 0, ent); | |
| if (trace.allsolid) | |
| { | |
| VectorCopy(vec3_origin, ent->v.velocity); | |
| return 3; | |
| } | |
| if (trace.fraction > 0) | |
| { | |
| VectorCopy(trace.endpos, ent->v.origin); | |
| VectorCopy(ent->v.velocity, original_velocity); | |
| numplanes = 0; | |
| } | |
| if (trace.fraction == 1) | |
| break; | |
| if (!trace.ent) | |
| Sys_Error("SV_FlyMove: !trace.ent"); | |
| if (trace.plane.normal[2] > 0.7) | |
| { | |
| blocked |= 1; | |
| if (trace.ent->v.solid == SOLID_BSP) | |
| { | |
| ent->v.flags = ((int32_t) ent->v.flags) | FL_ONGROUND; | |
| ent->v.groundentity = EDICT_TO_PROG(trace.ent); | |
| } | |
| } | |
| if (!trace.plane.normal[2]) | |
| { | |
| blocked |= 2; | |
| if (steptrace) | |
| *steptrace = trace; | |
| } | |
| SV_Impact(ent, trace.ent); | |
| if (ent->free) | |
| break; | |
| time_left -= time_left * trace.fraction; | |
| if (numplanes >= MAX_CLIP_PLANES) | |
| { | |
| VectorCopy(vec3_origin, ent->v.velocity); | |
| return 3; | |
| } | |
| VectorCopy(trace.plane.normal, planes[numplanes]); | |
| numplanes++; | |
| for (i = 0; i < numplanes; i++) | |
| { | |
| ClipVelocity(original_velocity, planes[i], new_velocity, 1); | |
| for (j = 0; j < numplanes; j++) | |
| if (j != i) | |
| { | |
| if (DotProduct(new_velocity, planes[j]) < 0) | |
| break; | |
| } | |
| if (j == numplanes) | |
| break; | |
| } | |
| if (i != numplanes) | |
| { | |
| VectorCopy(new_velocity, ent->v.velocity); | |
| } | |
| else | |
| { | |
| if (numplanes != 2) | |
| { | |
| VectorCopy(vec3_origin, ent->v.velocity); | |
| return 7; | |
| } | |
| CrossProduct(planes[0], planes[1], dir); | |
| d = DotProduct(dir, ent->v.velocity); | |
| VectorScale(dir, d, ent->v.velocity); | |
| } | |
| if (DotProduct(ent->v.velocity, primal_velocity) <= 0) | |
| { | |
| VectorCopy(vec3_origin, ent->v.velocity); | |
| return blocked; | |
| } | |
| } | |
| return blocked; | |
| } | |
| void SV_AddGravity(edict_t *ent) | |
| { | |
| float ent_gravity; | |
| eval_t *val; | |
| val = GetEdictFieldValue(ent, "gravity"); | |
| if (val && val->_float) | |
| ent_gravity = val->_float; | |
| else | |
| ent_gravity = 1.0; | |
| ent->v.velocity[2] -= (ent_gravity * sv_gravity.value) * host_frametime; | |
| } | |
| trace_t SV_PushEntity(edict_t *ent, vec3_t push) | |
| { | |
| trace_t trace; | |
| vec3_t end; | |
| VectorAdd(ent->v.origin, push, end); | |
| if (ent->v.movetype == MOVETYPE_FLYMISSILE) | |
| trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent); | |
| else | |
| if ((ent->v.solid == SOLID_TRIGGER) || (ent->v.solid == SOLID_NOT)) | |
| trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent); | |
| else | |
| trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent); | |
| VectorCopy(trace.endpos, ent->v.origin); | |
| SV_LinkEdict(ent, 1); | |
| if (trace.ent) | |
| SV_Impact(ent, trace.ent); | |
| return trace; | |
| } | |
| void SV_PushMove(edict_t *pusher, float movetime) | |
| { | |
| int32_t i; | |
| int32_t e; | |
| edict_t *check; | |
| edict_t *block; | |
| vec3_t mins; | |
| vec3_t maxs; | |
| vec3_t move; | |
| vec3_t entorig; | |
| vec3_t pushorig; | |
| int32_t num_moved; | |
| edict_t *moved_edict[MAX_EDICTS]; | |
| vec3_t moved_from[MAX_EDICTS]; | |
| if (((!pusher->v.velocity[0]) && (!pusher->v.velocity[1])) && (!pusher->v.velocity[2])) | |
| { | |
| pusher->v.ltime += movetime; | |
| return; | |
| } | |
| for (i = 0; i < 3; i++) | |
| { | |
| move[i] = pusher->v.velocity[i] * movetime; | |
| mins[i] = pusher->v.absmin[i] + move[i]; | |
| maxs[i] = pusher->v.absmax[i] + move[i]; | |
| } | |
| VectorCopy(pusher->v.origin, pushorig); | |
| VectorAdd(pusher->v.origin, move, pusher->v.origin); | |
| pusher->v.ltime += movetime; | |
| SV_LinkEdict(pusher, 0); | |
| num_moved = 0; | |
| check = NEXT_EDICT(sv.edicts); | |
| for (e = 1; e < sv.num_edicts; e++, check = NEXT_EDICT(check)) | |
| { | |
| if (check->free) | |
| continue; | |
| if (((check->v.movetype == MOVETYPE_PUSH) || (check->v.movetype == MOVETYPE_NONE)) || (check->v.movetype == MOVETYPE_NOCLIP)) | |
| continue; | |
| if (!((((int32_t) check->v.flags) & FL_ONGROUND) && (PROG_TO_EDICT(check->v.groundentity) == pusher))) | |
| { | |
| if ((((((check->v.absmin[0] >= maxs[0]) || (check->v.absmin[1] >= maxs[1])) || (check->v.absmin[2] >= maxs[2])) || (check->v.absmax[0] <= mins[0])) || (check->v.absmax[1] <= mins[1])) || (check->v.absmax[2] <= mins[2])) | |
| continue; | |
| if (!SV_TestEntityPosition(check)) | |
| continue; | |
| } | |
| if (check->v.movetype != MOVETYPE_WALK) | |
| check->v.flags = ((int32_t) check->v.flags) & (~FL_ONGROUND); | |
| VectorCopy(check->v.origin, entorig); | |
| VectorCopy(check->v.origin, moved_from[num_moved]); | |
| moved_edict[num_moved] = check; | |
| num_moved++; | |
| pusher->v.solid = SOLID_NOT; | |
| SV_PushEntity(check, move); | |
| pusher->v.solid = SOLID_BSP; | |
| block = SV_TestEntityPosition(check); | |
| if (block) | |
| { | |
| if (check->v.mins[0] == check->v.maxs[0]) | |
| continue; | |
| if ((check->v.solid == SOLID_NOT) || (check->v.solid == SOLID_TRIGGER)) | |
| { | |
| check->v.mins[0] = (check->v.mins[1] = 0); | |
| VectorCopy(check->v.mins, check->v.maxs); | |
| continue; | |
| } | |
| VectorCopy(entorig, check->v.origin); | |
| SV_LinkEdict(check, 1); | |
| VectorCopy(pushorig, pusher->v.origin); | |
| SV_LinkEdict(pusher, 0); | |
| pusher->v.ltime -= movetime; | |
| if (pusher->v.blocked) | |
| { | |
| pr_global_struct->self = EDICT_TO_PROG(pusher); | |
| pr_global_struct->other = EDICT_TO_PROG(check); | |
| PR_ExecuteProgram(pusher->v.blocked); | |
| } | |
| for (i = 0; i < num_moved; i++) | |
| { | |
| VectorCopy(moved_from[i], moved_edict[i]->v.origin); | |
| SV_LinkEdict(moved_edict[i], 0); | |
| } | |
| return; | |
| } | |
| } | |
| } | |
| void SV_Physics_Pusher(edict_t *ent) | |
| { | |
| float thinktime; | |
| float oldltime; | |
| float movetime; | |
| oldltime = ent->v.ltime; | |
| thinktime = ent->v.nextthink; | |
| if (thinktime < (ent->v.ltime + host_frametime)) | |
| { | |
| movetime = thinktime - ent->v.ltime; | |
| if (movetime < 0) | |
| movetime = 0; | |
| } | |
| else | |
| movetime = host_frametime; | |
| if (movetime) | |
| { | |
| SV_PushMove(ent, movetime); | |
| } | |
| if ((thinktime > oldltime) && (thinktime <= ent->v.ltime)) | |
| { | |
| ent->v.nextthink = 0; | |
| pr_global_struct->time = sv.time; | |
| pr_global_struct->self = EDICT_TO_PROG(ent); | |
| pr_global_struct->other = EDICT_TO_PROG(sv.edicts); | |
| PR_ExecuteProgram(ent->v.think); | |
| if (ent->free) | |
| return; | |
| } | |
| } | |
| void SV_CheckStuck(edict_t *ent) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| int32_t z; | |
| vec3_t org; | |
| if (!SV_TestEntityPosition(ent)) | |
| { | |
| VectorCopy(ent->v.origin, ent->v.oldorigin); | |
| return; | |
| } | |
| VectorCopy(ent->v.origin, org); | |
| VectorCopy(ent->v.oldorigin, ent->v.origin); | |
| if (!SV_TestEntityPosition(ent)) | |
| { | |
| Con_DPrintf("Unstuck.\n"); | |
| SV_LinkEdict(ent, 1); | |
| return; | |
| } | |
| for (z = 0; z < 18; z++) | |
| for (i = -1; i <= 1; i++) | |
| for (j = -1; j <= 1; j++) | |
| { | |
| ent->v.origin[0] = org[0] + i; | |
| ent->v.origin[1] = org[1] + j; | |
| ent->v.origin[2] = org[2] + z; | |
| if (!SV_TestEntityPosition(ent)) | |
| { | |
| Con_DPrintf("Unstuck.\n"); | |
| SV_LinkEdict(ent, 1); | |
| return; | |
| } | |
| } | |
| VectorCopy(org, ent->v.origin); | |
| Con_DPrintf("player is stuck.\n"); | |
| } | |
| bool SV_CheckWater(edict_t *ent) | |
| { | |
| vec3_t point; | |
| int32_t cont; | |
| point[0] = ent->v.origin[0]; | |
| point[1] = ent->v.origin[1]; | |
| point[2] = (ent->v.origin[2] + ent->v.mins[2]) + 1; | |
| ent->v.waterlevel = 0; | |
| ent->v.watertype = CONTENTS_EMPTY; | |
| cont = SV_PointContents(point); | |
| if (cont <= CONTENTS_WATER) | |
| { | |
| ent->v.watertype = cont; | |
| ent->v.waterlevel = 1; | |
| point[2] = ent->v.origin[2] + ((ent->v.mins[2] + ent->v.maxs[2]) * 0.5); | |
| cont = SV_PointContents(point); | |
| if (cont <= CONTENTS_WATER) | |
| { | |
| ent->v.waterlevel = 2; | |
| point[2] = ent->v.origin[2] + ent->v.view_ofs[2]; | |
| cont = SV_PointContents(point); | |
| if (cont <= CONTENTS_WATER) | |
| ent->v.waterlevel = 3; | |
| } | |
| } | |
| return ent->v.waterlevel > 1; | |
| } | |
| void SV_WallFriction(edict_t *ent, trace_t *trace) | |
| { | |
| vec3_t forward; | |
| vec3_t right; | |
| vec3_t up; | |
| float d; | |
| float i; | |
| vec3_t into; | |
| vec3_t side; | |
| AngleVectors(ent->v.v_angle, forward, right, up); | |
| d = DotProduct(trace->plane.normal, forward); | |
| d += 0.5; | |
| if (d >= 0) | |
| return; | |
| i = DotProduct(trace->plane.normal, ent->v.velocity); | |
| VectorScale(trace->plane.normal, i, into); | |
| VectorSubtract(ent->v.velocity, into, side); | |
| ent->v.velocity[0] = side[0] * (1 + d); | |
| ent->v.velocity[1] = side[1] * (1 + d); | |
| } | |
| int32_t SV_TryUnstick(edict_t *ent, vec3_t oldvel) | |
| { | |
| int32_t i; | |
| vec3_t oldorg; | |
| vec3_t dir; | |
| int32_t clip; | |
| trace_t steptrace; | |
| VectorCopy(ent->v.origin, oldorg); | |
| VectorCopy(vec3_origin, dir); | |
| for (i = 0; i < 8; i++) | |
| { | |
| switch (i) | |
| { | |
| case 0: | |
| dir[0] = 2; | |
| dir[1] = 0; | |
| break; | |
| case 1: | |
| dir[0] = 0; | |
| dir[1] = 2; | |
| break; | |
| case 2: | |
| dir[0] = -2; | |
| dir[1] = 0; | |
| break; | |
| case 3: | |
| dir[0] = 0; | |
| dir[1] = -2; | |
| break; | |
| case 4: | |
| dir[0] = 2; | |
| dir[1] = 2; | |
| break; | |
| case 5: | |
| dir[0] = -2; | |
| dir[1] = 2; | |
| break; | |
| case 6: | |
| dir[0] = 2; | |
| dir[1] = -2; | |
| break; | |
| case 7: | |
| dir[0] = -2; | |
| dir[1] = -2; | |
| break; | |
| } | |
| SV_PushEntity(ent, dir); | |
| ent->v.velocity[0] = oldvel[0]; | |
| ent->v.velocity[1] = oldvel[1]; | |
| ent->v.velocity[2] = 0; | |
| clip = SV_FlyMove(ent, 0.1, &steptrace); | |
| if ((fabs(oldorg[1] - ent->v.origin[1]) > 4) || (fabs(oldorg[0] - ent->v.origin[0]) > 4)) | |
| { | |
| return clip; | |
| } | |
| VectorCopy(oldorg, ent->v.origin); | |
| } | |
| VectorCopy(vec3_origin, ent->v.velocity); | |
| return 7; | |
| } | |
| void SV_WalkMove(edict_t *ent) | |
| { | |
| vec3_t upmove; | |
| vec3_t downmove; | |
| vec3_t oldorg; | |
| vec3_t oldvel; | |
| vec3_t nosteporg; | |
| vec3_t nostepvel; | |
| int32_t clip; | |
| int32_t oldonground; | |
| trace_t steptrace; | |
| trace_t downtrace; | |
| oldonground = ((int32_t) ent->v.flags) & FL_ONGROUND; | |
| ent->v.flags = ((int32_t) ent->v.flags) & (~FL_ONGROUND); | |
| VectorCopy(ent->v.origin, oldorg); | |
| VectorCopy(ent->v.velocity, oldvel); | |
| clip = SV_FlyMove(ent, host_frametime, &steptrace); | |
| if (!(clip & 2)) | |
| return; | |
| if ((!oldonground) && (ent->v.waterlevel == 0)) | |
| return; | |
| if (ent->v.movetype != MOVETYPE_WALK) | |
| return; | |
| if (sv_nostep.value) | |
| return; | |
| if (((int32_t) sv_player->v.flags) & FL_WATERJUMP) | |
| return; | |
| VectorCopy(ent->v.origin, nosteporg); | |
| VectorCopy(ent->v.velocity, nostepvel); | |
| VectorCopy(oldorg, ent->v.origin); | |
| VectorCopy(vec3_origin, upmove); | |
| VectorCopy(vec3_origin, downmove); | |
| upmove[2] = STEPSIZE; | |
| downmove[2] = (-STEPSIZE) + (oldvel[2] * host_frametime); | |
| SV_PushEntity(ent, upmove); | |
| ent->v.velocity[0] = oldvel[0]; | |
| ent->v.velocity[1] = oldvel[1]; | |
| ent->v.velocity[2] = 0; | |
| clip = SV_FlyMove(ent, host_frametime, &steptrace); | |
| if (clip) | |
| { | |
| if ((fabs(oldorg[1] - ent->v.origin[1]) < 0.03125) && (fabs(oldorg[0] - ent->v.origin[0]) < 0.03125)) | |
| { | |
| clip = SV_TryUnstick(ent, oldvel); | |
| } | |
| } | |
| if (clip & 2) | |
| SV_WallFriction(ent, &steptrace); | |
| downtrace = SV_PushEntity(ent, downmove); | |
| if (downtrace.plane.normal[2] > 0.7) | |
| { | |
| if (ent->v.solid == SOLID_BSP) | |
| { | |
| ent->v.flags = ((int32_t) ent->v.flags) | FL_ONGROUND; | |
| ent->v.groundentity = EDICT_TO_PROG(downtrace.ent); | |
| } | |
| } | |
| else | |
| { | |
| VectorCopy(nosteporg, ent->v.origin); | |
| VectorCopy(nostepvel, ent->v.velocity); | |
| } | |
| } | |
| void SV_Physics_Client(edict_t *ent, int32_t num) | |
| { | |
| if (!svs.clients[num - 1].active) | |
| return; | |
| pr_global_struct->time = sv.time; | |
| pr_global_struct->self = EDICT_TO_PROG(ent); | |
| PR_ExecuteProgram(pr_global_struct->PlayerPreThink); | |
| SV_CheckVelocity(ent); | |
| switch ((int32_t) ent->v.movetype) | |
| { | |
| case MOVETYPE_NONE: | |
| if (!SV_RunThink(ent)) | |
| return; | |
| break; | |
| case MOVETYPE_WALK: | |
| if (!SV_RunThink(ent)) | |
| return; | |
| if ((!SV_CheckWater(ent)) && (!(((int32_t) ent->v.flags) & FL_WATERJUMP))) | |
| SV_AddGravity(ent); | |
| SV_CheckStuck(ent); | |
| SV_WalkMove(ent); | |
| break; | |
| case MOVETYPE_TOSS: | |
| case MOVETYPE_BOUNCE: | |
| SV_Physics_Toss(ent); | |
| break; | |
| case MOVETYPE_FLY: | |
| if (!SV_RunThink(ent)) | |
| return; | |
| SV_FlyMove(ent, host_frametime, 0); | |
| break; | |
| case MOVETYPE_NOCLIP: | |
| if (!SV_RunThink(ent)) | |
| return; | |
| VectorMA(ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin); | |
| break; | |
| default: | |
| Sys_Error("SV_Physics_client: bad movetype %i", (int32_t) ent->v.movetype); | |
| } | |
| SV_LinkEdict(ent, 1); | |
| pr_global_struct->time = sv.time; | |
| pr_global_struct->self = EDICT_TO_PROG(ent); | |
| PR_ExecuteProgram(pr_global_struct->PlayerPostThink); | |
| } | |
| void SV_Physics_None(edict_t *ent) | |
| { | |
| SV_RunThink(ent); | |
| } | |
| void SV_Physics_Noclip(edict_t *ent) | |
| { | |
| if (!SV_RunThink(ent)) | |
| return; | |
| VectorMA(ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles); | |
| VectorMA(ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin); | |
| SV_LinkEdict(ent, 0); | |
| } | |
| void SV_CheckWaterTransition(edict_t *ent) | |
| { | |
| int32_t cont; | |
| cont = SV_PointContents(ent->v.origin); | |
| if (!ent->v.watertype) | |
| { | |
| ent->v.watertype = cont; | |
| ent->v.waterlevel = 1; | |
| return; | |
| } | |
| if (cont <= CONTENTS_WATER) | |
| { | |
| if (ent->v.watertype == CONTENTS_EMPTY) | |
| { | |
| SV_StartSound(ent, 0, "misc/h2ohit1.wav", 255, 1); | |
| } | |
| ent->v.watertype = cont; | |
| ent->v.waterlevel = 1; | |
| } | |
| else | |
| { | |
| if (ent->v.watertype != CONTENTS_EMPTY) | |
| { | |
| SV_StartSound(ent, 0, "misc/h2ohit1.wav", 255, 1); | |
| } | |
| ent->v.watertype = CONTENTS_EMPTY; | |
| ent->v.waterlevel = cont; | |
| } | |
| } | |
| void SV_Physics_Toss(edict_t *ent) | |
| { | |
| trace_t trace; | |
| vec3_t move; | |
| float backoff; | |
| if (!SV_RunThink(ent)) | |
| return; | |
| if (((int32_t) ent->v.flags) & FL_ONGROUND) | |
| return; | |
| SV_CheckVelocity(ent); | |
| if ((ent->v.movetype != MOVETYPE_FLY) && (ent->v.movetype != MOVETYPE_FLYMISSILE)) | |
| SV_AddGravity(ent); | |
| VectorMA(ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles); | |
| VectorScale(ent->v.velocity, host_frametime, move); | |
| trace = SV_PushEntity(ent, move); | |
| if (trace.fraction == 1) | |
| return; | |
| if (ent->free) | |
| return; | |
| if (ent->v.movetype == MOVETYPE_BOUNCE) | |
| backoff = 1.5; | |
| else | |
| backoff = 1; | |
| ClipVelocity(ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff); | |
| if (trace.plane.normal[2] > 0.7) | |
| { | |
| if ((ent->v.velocity[2] < 60) || (ent->v.movetype != MOVETYPE_BOUNCE)) | |
| { | |
| ent->v.flags = ((int32_t) ent->v.flags) | FL_ONGROUND; | |
| ent->v.groundentity = EDICT_TO_PROG(trace.ent); | |
| VectorCopy(vec3_origin, ent->v.velocity); | |
| VectorCopy(vec3_origin, ent->v.avelocity); | |
| } | |
| } | |
| SV_CheckWaterTransition(ent); | |
| } | |
| void SV_Physics_Step(edict_t *ent) | |
| { | |
| bool hitsound; | |
| if (!(((int32_t) ent->v.flags) & ((FL_ONGROUND | FL_FLY) | FL_SWIM))) | |
| { | |
| if (ent->v.velocity[2] < (sv_gravity.value * (-0.1))) | |
| hitsound = 1; | |
| else | |
| hitsound = 0; | |
| SV_AddGravity(ent); | |
| SV_CheckVelocity(ent); | |
| SV_FlyMove(ent, host_frametime, 0); | |
| SV_LinkEdict(ent, 1); | |
| if (((int32_t) ent->v.flags) & FL_ONGROUND) | |
| { | |
| if (hitsound) | |
| SV_StartSound(ent, 0, "demon/dland2.wav", 255, 1); | |
| } | |
| } | |
| SV_RunThink(ent); | |
| SV_CheckWaterTransition(ent); | |
| } | |
| void SV_Physics(void) | |
| { | |
| int32_t i; | |
| edict_t *ent; | |
| pr_global_struct->self = EDICT_TO_PROG(sv.edicts); | |
| pr_global_struct->other = EDICT_TO_PROG(sv.edicts); | |
| pr_global_struct->time = sv.time; | |
| PR_ExecuteProgram(pr_global_struct->StartFrame); | |
| ent = sv.edicts; | |
| for (i = 0; i < sv.num_edicts; i++, ent = NEXT_EDICT(ent)) | |
| { | |
| if (ent->free) | |
| continue; | |
| if (pr_global_struct->force_retouch) | |
| { | |
| SV_LinkEdict(ent, 1); | |
| } | |
| if ((i > 0) && (i <= svs.maxclients)) | |
| SV_Physics_Client(ent, i); | |
| else | |
| if (ent->v.movetype == MOVETYPE_PUSH) | |
| SV_Physics_Pusher(ent); | |
| else | |
| if (ent->v.movetype == MOVETYPE_NONE) | |
| SV_Physics_None(ent); | |
| else | |
| if (ent->v.movetype == MOVETYPE_NOCLIP) | |
| SV_Physics_Noclip(ent); | |
| else | |
| if (ent->v.movetype == MOVETYPE_STEP) | |
| SV_Physics_Step(ent); | |
| else | |
| if ((((ent->v.movetype == MOVETYPE_TOSS) || (ent->v.movetype == MOVETYPE_BOUNCE)) || (ent->v.movetype == MOVETYPE_FLY)) || (ent->v.movetype == MOVETYPE_FLYMISSILE)) | |
| SV_Physics_Toss(ent); | |
| else | |
| Sys_Error("SV_Physics: bad movetype %i", (int32_t) ent->v.movetype); | |
| } | |
| if (pr_global_struct->force_retouch) | |
| pr_global_struct->force_retouch--; | |
| sv.time += host_frametime; | |
| } | |
| void SV_SetIdealPitch(void) | |
| { | |
| float angleval; | |
| float sinval; | |
| float cosval; | |
| trace_t tr; | |
| vec3_t top; | |
| vec3_t bottom; | |
| float z[MAX_FORWARD]; | |
| int32_t i; | |
| int32_t j; | |
| int32_t step; | |
| int32_t dir; | |
| int32_t steps; | |
| if (!(((int32_t) sv_player->v.flags) & FL_ONGROUND)) | |
| return; | |
| angleval = ((sv_player->v.angles[YAW] * M_PI) * 2) / 360; | |
| sinval = sin(angleval); | |
| cosval = cos(angleval); | |
| for (i = 0; i < MAX_FORWARD; i++) | |
| { | |
| top[0] = sv_player->v.origin[0] + ((cosval * (i + 3)) * 12); | |
| top[1] = sv_player->v.origin[1] + ((sinval * (i + 3)) * 12); | |
| top[2] = sv_player->v.origin[2] + sv_player->v.view_ofs[2]; | |
| bottom[0] = top[0]; | |
| bottom[1] = top[1]; | |
| bottom[2] = top[2] - 160; | |
| tr = SV_Move(top, vec3_origin, vec3_origin, bottom, 1, sv_player); | |
| if (tr.allsolid) | |
| return; | |
| if (tr.fraction == 1) | |
| return; | |
| z[i] = top[2] + (tr.fraction * (bottom[2] - top[2])); | |
| } | |
| dir = 0; | |
| steps = 0; | |
| for (j = 1; j < i; j++) | |
| { | |
| step = z[j] - z[j - 1]; | |
| if ((step > (-ON_EPSILON)) && (step < ON_EPSILON)) | |
| continue; | |
| if (dir && (((step - dir) > ON_EPSILON) || ((step - dir) < (-ON_EPSILON)))) | |
| return; | |
| steps++; | |
| dir = step; | |
| } | |
| if (!dir) | |
| { | |
| sv_player->v.idealpitch = 0; | |
| return; | |
| } | |
| if (steps < 2) | |
| return; | |
| sv_player->v.idealpitch = (-dir) * sv_idealpitchscale.value; | |
| } | |
| void SV_UserFriction(void) | |
| { | |
| float *vel; | |
| float speed; | |
| float newspeed; | |
| float control; | |
| vec3_t start; | |
| vec3_t stop; | |
| float friction; | |
| trace_t trace; | |
| vel = velocity; | |
| speed = sqrt((vel[0] * vel[0]) + (vel[1] * vel[1])); | |
| if (!speed) | |
| return; | |
| start[0] = (stop[0] = origin[0] + ((vel[0] / speed) * 16)); | |
| start[1] = (stop[1] = origin[1] + ((vel[1] / speed) * 16)); | |
| start[2] = origin[2] + sv_player->v.mins[2]; | |
| stop[2] = start[2] - 34; | |
| trace = SV_Move(start, vec3_origin, vec3_origin, stop, 1, sv_player); | |
| if (trace.fraction == 1.0) | |
| friction = sv_friction.value * sv_edgefriction.value; | |
| else | |
| friction = sv_friction.value; | |
| control = (speed < sv_stopspeed.value) ? (sv_stopspeed.value) : (speed); | |
| newspeed = speed - ((host_frametime * control) * friction); | |
| if (newspeed < 0) | |
| newspeed = 0; | |
| newspeed /= speed; | |
| vel[0] = vel[0] * newspeed; | |
| vel[1] = vel[1] * newspeed; | |
| vel[2] = vel[2] * newspeed; | |
| } | |
| void SV_Accelerate(void) | |
| { | |
| int32_t i; | |
| float addspeed; | |
| float accelspeed; | |
| float currentspeed; | |
| currentspeed = DotProduct(velocity, wishdir); | |
| addspeed = wishspeed - currentspeed; | |
| if (addspeed <= 0) | |
| return; | |
| accelspeed = (sv_accelerate.value * host_frametime) * wishspeed; | |
| if (accelspeed > addspeed) | |
| accelspeed = addspeed; | |
| for (i = 0; i < 3; i++) | |
| velocity[i] += accelspeed * wishdir[i]; | |
| } | |
| void SV_AirAccelerate(vec3_t wishveloc) | |
| { | |
| int32_t i; | |
| float addspeed; | |
| float wishspd; | |
| float accelspeed; | |
| float currentspeed; | |
| wishspd = VectorNormalize(wishveloc); | |
| if (wishspd > 30) | |
| wishspd = 30; | |
| currentspeed = DotProduct(velocity, wishveloc); | |
| addspeed = wishspd - currentspeed; | |
| if (addspeed <= 0) | |
| return; | |
| accelspeed = (sv_accelerate.value * wishspeed) * host_frametime; | |
| if (accelspeed > addspeed) | |
| accelspeed = addspeed; | |
| for (i = 0; i < 3; i++) | |
| velocity[i] += accelspeed * wishveloc[i]; | |
| } | |
| void DropPunchAngle(void) | |
| { | |
| float len; | |
| len = VectorNormalize(sv_player->v.punchangle); | |
| len -= 10 * host_frametime; | |
| if (len < 0) | |
| len = 0; | |
| VectorScale(sv_player->v.punchangle, len, sv_player->v.punchangle); | |
| } | |
| void SV_WaterMove(void) | |
| { | |
| int32_t i; | |
| vec3_t wishvel; | |
| float speed; | |
| float newspeed; | |
| float wishspeed; | |
| float addspeed; | |
| float accelspeed; | |
| AngleVectors(sv_player->v.v_angle, forward, right, up); | |
| for (i = 0; i < 3; i++) | |
| wishvel[i] = (forward[i] * cmd.forwardmove) + (right[i] * cmd.sidemove); | |
| if (((!cmd.forwardmove) && (!cmd.sidemove)) && (!cmd.upmove)) | |
| wishvel[2] -= 60; | |
| else | |
| wishvel[2] += cmd.upmove; | |
| wishspeed = Length(wishvel); | |
| if (wishspeed > sv_maxspeed.value) | |
| { | |
| VectorScale(wishvel, sv_maxspeed.value / wishspeed, wishvel); | |
| wishspeed = sv_maxspeed.value; | |
| } | |
| wishspeed *= 0.7; | |
| speed = Length(velocity); | |
| if (speed) | |
| { | |
| newspeed = speed - ((host_frametime * speed) * sv_friction.value); | |
| if (newspeed < 0) | |
| newspeed = 0; | |
| VectorScale(velocity, newspeed / speed, velocity); | |
| } | |
| else | |
| newspeed = 0; | |
| if (!wishspeed) | |
| return; | |
| addspeed = wishspeed - newspeed; | |
| if (addspeed <= 0) | |
| return; | |
| VectorNormalize(wishvel); | |
| accelspeed = (sv_accelerate.value * wishspeed) * host_frametime; | |
| if (accelspeed > addspeed) | |
| accelspeed = addspeed; | |
| for (i = 0; i < 3; i++) | |
| velocity[i] += accelspeed * wishvel[i]; | |
| } | |
| void SV_WaterJump(void) | |
| { | |
| if ((sv.time > sv_player->v.teleport_time) || (!sv_player->v.waterlevel)) | |
| { | |
| sv_player->v.flags = ((int32_t) sv_player->v.flags) & (~FL_WATERJUMP); | |
| sv_player->v.teleport_time = 0; | |
| } | |
| sv_player->v.velocity[0] = sv_player->v.movedir[0]; | |
| sv_player->v.velocity[1] = sv_player->v.movedir[1]; | |
| } | |
| void SV_AirMove(void) | |
| { | |
| int32_t i; | |
| vec3_t wishvel; | |
| float fmove; | |
| float smove; | |
| AngleVectors(sv_player->v.angles, forward, right, up); | |
| fmove = cmd.forwardmove; | |
| smove = cmd.sidemove; | |
| if ((sv.time < sv_player->v.teleport_time) && (fmove < 0)) | |
| fmove = 0; | |
| for (i = 0; i < 3; i++) | |
| wishvel[i] = (forward[i] * fmove) + (right[i] * smove); | |
| if (((int32_t) sv_player->v.movetype) != MOVETYPE_WALK) | |
| wishvel[2] = cmd.upmove; | |
| else | |
| wishvel[2] = 0; | |
| VectorCopy(wishvel, wishdir); | |
| wishspeed = VectorNormalize(wishdir); | |
| if (wishspeed > sv_maxspeed.value) | |
| { | |
| VectorScale(wishvel, sv_maxspeed.value / wishspeed, wishvel); | |
| wishspeed = sv_maxspeed.value; | |
| } | |
| if (sv_player->v.movetype == MOVETYPE_NOCLIP) | |
| { | |
| VectorCopy(wishvel, velocity); | |
| } | |
| else | |
| if (onground) | |
| { | |
| SV_UserFriction(); | |
| SV_Accelerate(); | |
| } | |
| else | |
| { | |
| SV_AirAccelerate(wishvel); | |
| } | |
| } | |
| void SV_ClientThink(void) | |
| { | |
| vec3_t v_angle; | |
| if (sv_player->v.movetype == MOVETYPE_NONE) | |
| return; | |
| onground = ((int32_t) sv_player->v.flags) & FL_ONGROUND; | |
| origin = sv_player->v.origin; | |
| velocity = sv_player->v.velocity; | |
| DropPunchAngle(); | |
| if (sv_player->v.health <= 0) | |
| return; | |
| cmd = host_client->cmd; | |
| angles = sv_player->v.angles; | |
| VectorAdd(sv_player->v.v_angle, sv_player->v.punchangle, v_angle); | |
| angles[ROLL] = V_CalcRoll(sv_player->v.angles, sv_player->v.velocity) * 4; | |
| if (!sv_player->v.fixangle) | |
| { | |
| angles[PITCH] = (-v_angle[PITCH]) / 3; | |
| angles[YAW] = v_angle[YAW]; | |
| } | |
| if (((int32_t) sv_player->v.flags) & FL_WATERJUMP) | |
| { | |
| SV_WaterJump(); | |
| return; | |
| } | |
| if ((sv_player->v.waterlevel >= 2) && (sv_player->v.movetype != MOVETYPE_NOCLIP)) | |
| { | |
| SV_WaterMove(); | |
| return; | |
| } | |
| SV_AirMove(); | |
| } | |
| void SV_ReadClientMove(usercmd_t *move) | |
| { | |
| int32_t i; | |
| vec3_t angle; | |
| int32_t bits; | |
| host_client->ping_times[host_client->num_pings % NUM_PING_TIMES] = sv.time - MSG_ReadFloat(); | |
| host_client->num_pings++; | |
| for (i = 0; i < 3; i++) | |
| angle[i] = MSG_ReadAngle(); | |
| VectorCopy(angle, host_client->edict->v.v_angle); | |
| move->forwardmove = MSG_ReadShort(); | |
| move->sidemove = MSG_ReadShort(); | |
| move->upmove = MSG_ReadShort(); | |
| bits = MSG_ReadByte(); | |
| host_client->edict->v.button0 = bits & 1; | |
| host_client->edict->v.button2 = (bits & 2) >> 1; | |
| i = MSG_ReadByte(); | |
| if (i) | |
| host_client->edict->v.impulse = i; | |
| } | |
| bool SV_ReadClientMessage(void) | |
| { | |
| int32_t ret; | |
| int32_t cmd; | |
| char *s; | |
| do | |
| { | |
| nextmsg: | |
| ret = NET_GetMessage(host_client->netconnection); | |
| if (ret == (-1)) | |
| { | |
| Sys_Printf("SV_ReadClientMessage: NET_GetMessage failed\n"); | |
| return 0; | |
| } | |
| if (!ret) | |
| return 1; | |
| MSG_BeginReading(); | |
| while (1) | |
| { | |
| if (!host_client->active) | |
| return 0; | |
| if (msg_badread) | |
| { | |
| Sys_Printf("SV_ReadClientMessage: badread\n"); | |
| return 0; | |
| } | |
| cmd = MSG_ReadChar(); | |
| switch (cmd) | |
| { | |
| case -1: | |
| goto nextmsg; | |
| default: | |
| Sys_Printf("SV_ReadClientMessage: unknown command char\n"); | |
| return 0; | |
| case clc_nop: | |
| break; | |
| case clc_stringcmd: | |
| s = MSG_ReadString(); | |
| if (host_client->privileged) | |
| ret = 2; | |
| else | |
| ret = 0; | |
| if (strncasecmp(s, "status", 6) == 0) | |
| ret = 1; | |
| else | |
| if (strncasecmp(s, "god", 3) == 0) | |
| ret = 1; | |
| else | |
| if (strncasecmp(s, "notarget", 8) == 0) | |
| ret = 1; | |
| else | |
| if (strncasecmp(s, "fly", 3) == 0) | |
| ret = 1; | |
| else | |
| if (strncasecmp(s, "name", 4) == 0) | |
| ret = 1; | |
| else | |
| if (strncasecmp(s, "noclip", 6) == 0) | |
| ret = 1; | |
| else | |
| if (strncasecmp(s, "say", 3) == 0) | |
| ret = 1; | |
| else | |
| if (strncasecmp(s, "say_team", 8) == 0) | |
| ret = 1; | |
| else | |
| if (strncasecmp(s, "tell", 4) == 0) | |
| ret = 1; | |
| else | |
| if (strncasecmp(s, "color", 5) == 0) | |
| ret = 1; | |
| else | |
| if (strncasecmp(s, "kill", 4) == 0) | |
| ret = 1; | |
| else | |
| if (strncasecmp(s, "pause", 5) == 0) | |
| ret = 1; | |
| else | |
| if (strncasecmp(s, "spawn", 5) == 0) | |
| ret = 1; | |
| else | |
| if (strncasecmp(s, "begin", 5) == 0) | |
| ret = 1; | |
| else | |
| if (strncasecmp(s, "prespawn", 8) == 0) | |
| ret = 1; | |
| else | |
| if (strncasecmp(s, "kick", 4) == 0) | |
| ret = 1; | |
| else | |
| if (strncasecmp(s, "ping", 4) == 0) | |
| ret = 1; | |
| else | |
| if (strncasecmp(s, "give", 4) == 0) | |
| ret = 1; | |
| else | |
| if (strncasecmp(s, "ban", 3) == 0) | |
| ret = 1; | |
| if (ret == 2) | |
| Cbuf_InsertText(s); | |
| else | |
| if (ret == 1) | |
| Cmd_ExecuteString(s, src_client); | |
| else | |
| Con_DPrintf("%s tried to %s\n", host_client->name, s); | |
| break; | |
| case clc_disconnect: | |
| return 0; | |
| case clc_move: | |
| SV_ReadClientMove(&host_client->cmd); | |
| break; | |
| } | |
| } | |
| } | |
| while (ret == 1); | |
| return 1; | |
| } | |
| void SV_RunClients(void) | |
| { | |
| int32_t i; | |
| for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++) | |
| { | |
| if (!host_client->active) | |
| continue; | |
| sv_player = host_client->edict; | |
| if (!SV_ReadClientMessage()) | |
| { | |
| SV_DropClient(0); | |
| continue; | |
| } | |
| if (!host_client->spawned) | |
| { | |
| memset(&host_client->cmd, 0, sizeof(host_client->cmd)); | |
| continue; | |
| } | |
| if ((!sv.paused) && ((svs.maxclients > 1) || (key_dest == key_game))) | |
| SV_ClientThink(); | |
| } | |
| } | |
| void Sys_DebugNumber(int32_t y, int32_t val) | |
| { | |
| } | |
| void Sys_Printf(char *fmt, ...) | |
| { | |
| va_list argptr; | |
| char text[1024]; | |
| va_start(argptr, fmt); | |
| vsnprintf(text, sizeof(text), fmt, argptr); | |
| va_end(argptr); | |
| TraceLog(LOG_INFO, text); | |
| } | |
| void Sys_Quit(void) | |
| { | |
| Host_Shutdown(); | |
| exit(0); | |
| } | |
| void Sys_Init(void) | |
| { | |
| } | |
| void Sys_LowFPPrecision(void) | |
| { | |
| } | |
| void Sys_HighFPPrecision(void) | |
| { | |
| } | |
| void Sys_Error(char *error, ...) | |
| { | |
| va_list argptr; | |
| char string[1024]; | |
| va_start(argptr, error); | |
| vsnprintf(string, sizeof(string), error, argptr); | |
| va_end(argptr); | |
| TraceLog(LOG_ERROR, string); | |
| Host_Shutdown(); | |
| exit(1); | |
| } | |
| void Sys_Warn(char *warning, ...) | |
| { | |
| va_list argptr; | |
| char string[1024]; | |
| va_start(argptr, warning); | |
| vsnprintf(string, sizeof(string), warning, argptr); | |
| va_end(argptr); | |
| TraceLog(LOG_WARNING, string); | |
| } | |
| int32_t findhandle(void) | |
| { | |
| for (int i = 1; i < MAX_HANDLES; i++) | |
| { | |
| if (!sys_handles[i]) | |
| return i; | |
| } | |
| Sys_Error("out of handles"); | |
| return -1; | |
| } | |
| static int32_t Qfilelength(FILE *f) | |
| { | |
| int32_t pos; | |
| int32_t end; | |
| pos = ftell(f); | |
| fseek(f, 0, 2); | |
| end = ftell(f); | |
| fseek(f, pos, 0); | |
| return end; | |
| } | |
| int32_t Sys_FileOpenRead(char *path, int32_t *hndl) | |
| { | |
| FILE *f; | |
| int32_t i = findhandle(); | |
| f = fopen(path, "rb"); | |
| if (!f) | |
| { | |
| *hndl = -1; | |
| return -1; | |
| } | |
| sys_handles[i] = f; | |
| *hndl = i; | |
| return Qfilelength(f); | |
| } | |
| int32_t Sys_FileOpenWrite(char *path) | |
| { | |
| FILE *f; | |
| int32_t i = findhandle(); | |
| f = fopen(path, "wb"); | |
| if (!f) | |
| Sys_Error("Error opening %s: %s", path, strerror(errno)); | |
| sys_handles[i] = f; | |
| return i; | |
| } | |
| void Sys_FileClose(int32_t handle) | |
| { | |
| if (((handle >= 0) && (handle < MAX_HANDLES)) && sys_handles[handle]) | |
| { | |
| fclose(sys_handles[handle]); | |
| sys_handles[handle] = 0; | |
| } | |
| } | |
| void Sys_FileSeek(int32_t handle, int32_t position) | |
| { | |
| if (((handle >= 0) && (handle < MAX_HANDLES)) && sys_handles[handle]) | |
| { | |
| fseek(sys_handles[handle], position, 0); | |
| } | |
| } | |
| int32_t Sys_FileRead(int32_t handle, void *dst, int32_t count) | |
| { | |
| if (((handle < 0) || (handle >= MAX_HANDLES)) || (!sys_handles[handle])) | |
| { | |
| return 0; | |
| } | |
| return fread(dst, 1, count, sys_handles[handle]); | |
| } | |
| int32_t Sys_FileWrite(int32_t handle, void *src, int32_t count) | |
| { | |
| if (((handle < 0) || (handle >= MAX_HANDLES)) || (!sys_handles[handle])) | |
| { | |
| return 0; | |
| } | |
| return fwrite(src, 1, count, sys_handles[handle]); | |
| } | |
| int32_t Sys_FileTime(char *path) | |
| { | |
| return (FileExists(path)) ? (1) : (-1); | |
| } | |
| void Sys_mkdir(char *path) | |
| { | |
| mkdir(path, 0777); | |
| } | |
| void Sys_DebugLog(char *file, char *fmt, ...) | |
| { | |
| va_list argptr; | |
| char data[1024]; | |
| FILE *fp; | |
| va_start(argptr, fmt); | |
| vsnprintf(data, sizeof(data), fmt, argptr); | |
| va_end(argptr); | |
| fp = fopen(file, "a"); | |
| if (fp) | |
| { | |
| fwrite(data, strlen(data), 1, fp); | |
| fclose(fp); | |
| } | |
| } | |
| double Sys_FloatTime(void) | |
| { | |
| return GetTime(); | |
| } | |
| int main(int argc, char *argv[]) | |
| { | |
| quakeparms_t parms; | |
| parms.memsize = (32 * 1024) * 1024; | |
| parms.membase = malloc(parms.memsize); | |
| parms.basedir = basedir; | |
| parms.cachedir = 0; | |
| COM_InitArgv(argc, argv); | |
| parms.argc = com_argc; | |
| parms.argv = com_argv; | |
| Sys_Init(); | |
| Host_Init(&parms); | |
| Cvar_RegisterVariable(&sys_nostdout); | |
| while (!WindowShouldClose()) | |
| { | |
| Host_Frame(GetFrameTime()); | |
| } | |
| Host_Shutdown(); | |
| return 0; | |
| } | |
| void VID_SetPalette(unsigned char *palette_data) | |
| { | |
| for (int i = 0; i < 256; ++i) | |
| { | |
| palette[i].r = *(palette_data++); | |
| palette[i].g = *(palette_data++); | |
| palette[i].b = *(palette_data++); | |
| palette[i].a = 255; | |
| } | |
| } | |
| void VID_ShiftPalette(unsigned char *palette) | |
| { | |
| VID_SetPalette(palette); | |
| } | |
| void VID_Init(unsigned char *palette) | |
| { | |
| int pnum; | |
| int chunk; | |
| uint8_t *cache; | |
| int cachesize; | |
| vid.width = BASEWIDTH; | |
| vid.height = BASEHEIGHT; | |
| vid.maxwarpwidth = WARP_WIDTH; | |
| vid.maxwarpheight = WARP_HEIGHT; | |
| if (pnum = COM_CheckParm("-winsize")) | |
| { | |
| if (pnum >= (com_argc - 2)) | |
| Sys_Error("VID: -winsize <width> <height>\n"); | |
| vid.width = (int32_t) strtol(com_argv[pnum + 1], 0, 0); | |
| vid.height = (int32_t) strtol(com_argv[pnum + 2], 0, 0); | |
| if ((!vid.width) || (!vid.height)) | |
| Sys_Error("VID: Bad window width/height\n"); | |
| } | |
| int window_width = BASEWIDTH * 2; | |
| int window_height = BASEHEIGHT * 2; | |
| if (COM_CheckParm("-fullscreen")) | |
| { | |
| SetConfigFlags(FLAG_FULLSCREEN_MODE); | |
| window_width = GetMonitorWidth(0); | |
| window_height = GetMonitorHeight(0); | |
| } | |
| InitWindow(window_width, window_height, "Quake"); | |
| image8bpp.data = MemAlloc(vid.width * vid.height); | |
| image8bpp.width = vid.width; | |
| image8bpp.height = vid.height; | |
| image8bpp.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE; | |
| image8bpp.mipmaps = 1; | |
| image32bpp = GenImageColor(vid.width, vid.height, (Color){0, 0, 0, 255}); | |
| screenTexture = LoadTextureFromImage(image32bpp); | |
| VID_SetPalette(palette); | |
| vid.conwidth = vid.width; | |
| vid.conheight = vid.height; | |
| vid.aspect = (((float) vid.height) / ((float) vid.width)) * (320.0 / 240.0); | |
| vid.numpages = 1; | |
| vid.colormap = host_colormap; | |
| vid.fullbright = 256 - (*(((int *) vid.colormap) + 2048)); | |
| vid.buffer = image8bpp.data; | |
| vid.rowbytes = vid.width; | |
| vid.conbuffer = vid.buffer; | |
| vid.conrowbytes = vid.rowbytes; | |
| vid.direct = 0; | |
| chunk = (vid.width * vid.height) * (sizeof(*d_pzbuffer)); | |
| cachesize = D_SurfaceCacheForRes(vid.width, vid.height); | |
| chunk += cachesize; | |
| d_pzbuffer = Hunk_HighAllocName(chunk, "video"); | |
| if (d_pzbuffer == 0) | |
| Sys_Error("Not enough memory for video mode\n"); | |
| cache = ((uint8_t *) d_pzbuffer) + ((vid.width * vid.height) * (sizeof(*d_pzbuffer))); | |
| D_InitCaches(cache, cachesize); | |
| HideCursor(); | |
| DisableCursor(); | |
| } | |
| void VID_Shutdown(void) | |
| { | |
| UnloadTexture(screenTexture); | |
| UnloadImage(image32bpp); | |
| MemFree(image8bpp.data); | |
| CloseWindow(); | |
| } | |
| void VID_Update(vrect_t *rects) | |
| { | |
| unsigned char *src = (unsigned char *) vid.buffer; | |
| Color *dest = (Color *) image32bpp.data; | |
| for (int i = 0; i < (vid.width * vid.height); i++) | |
| { | |
| dest[i] = palette[src[i]]; | |
| } | |
| UpdateTexture(screenTexture, dest); | |
| BeginDrawing(); | |
| ClearBackground((Color){0, 0, 0, 255}); | |
| DrawTexturePro(screenTexture, (Rectangle){0, 0, vid.width, vid.height}, (Rectangle){0, 0, GetScreenWidth(), GetScreenHeight()}, (Vector2){0, 0}, 0, (Color){255, 255, 255, 255}); | |
| EndDrawing(); | |
| } | |
| static int TranslateKey(int key) | |
| { | |
| switch (key) | |
| { | |
| case KEY_DELETE: | |
| return K_DEL; | |
| case KEY_BACKSPACE: | |
| return K_BACKSPACE; | |
| case KEY_F1: | |
| return K_F1; | |
| case KEY_F2: | |
| return K_F2; | |
| case KEY_F3: | |
| return K_F3; | |
| case KEY_F4: | |
| return K_F4; | |
| case KEY_F5: | |
| return K_F5; | |
| case KEY_F6: | |
| return K_F6; | |
| case KEY_F7: | |
| return K_F7; | |
| case KEY_F8: | |
| return K_F8; | |
| case KEY_F9: | |
| return K_F9; | |
| case KEY_F10: | |
| return K_F10; | |
| case KEY_F11: | |
| return K_F11; | |
| case KEY_F12: | |
| return K_F12; | |
| case KEY_PAUSE: | |
| return K_PAUSE; | |
| case KEY_UP: | |
| return K_UPARROW; | |
| case KEY_DOWN: | |
| return K_DOWNARROW; | |
| case KEY_RIGHT: | |
| return K_RIGHTARROW; | |
| case KEY_LEFT: | |
| return K_LEFTARROW; | |
| case KEY_INSERT: | |
| return K_INS; | |
| case KEY_HOME: | |
| return K_HOME; | |
| case KEY_END: | |
| return K_END; | |
| case KEY_PAGE_UP: | |
| return K_PGUP; | |
| case KEY_PAGE_DOWN: | |
| return K_PGDN; | |
| case KEY_LEFT_SHIFT: | |
| case KEY_RIGHT_SHIFT: | |
| return K_SHIFT; | |
| case KEY_LEFT_CONTROL: | |
| case KEY_RIGHT_CONTROL: | |
| return K_CTRL; | |
| case KEY_LEFT_ALT: | |
| case KEY_RIGHT_ALT: | |
| return K_ALT; | |
| case KEY_KP_DIVIDE: | |
| return '/'; | |
| case KEY_KP_MULTIPLY: | |
| return '*'; | |
| case KEY_KP_SUBTRACT: | |
| return '-'; | |
| case KEY_KP_ADD: | |
| return '+'; | |
| case KEY_KP_ENTER: | |
| return K_ENTER; | |
| case KEY_KP_EQUAL: | |
| return '='; | |
| case KEY_ENTER: | |
| return K_ENTER; | |
| default: | |
| return tolower(key); | |
| } | |
| } | |
| void Sys_SendKeyEvents(void) | |
| { | |
| if (WindowShouldClose()) | |
| { | |
| CL_Disconnect(); | |
| Host_ShutdownServer(0); | |
| Sys_Quit(); | |
| } | |
| for (int i = 32; i < 349; i++) | |
| { | |
| if (IsKeyPressed(i)) | |
| Key_Event(TranslateKey(i), 1); | |
| if (IsKeyReleased(i)) | |
| Key_Event(TranslateKey(i), 0); | |
| } | |
| Vector2 delta = GetMouseDelta(); | |
| mouse_x = delta.x * 10; | |
| mouse_y = delta.y * 10; | |
| } | |
| void IN_Init(void) | |
| { | |
| if (COM_CheckParm("-nomouse")) | |
| return; | |
| mouse_x = (mouse_y = 0.0); | |
| mouse_avail = 1; | |
| } | |
| void IN_Shutdown(void) | |
| { | |
| mouse_avail = 0; | |
| } | |
| void IN_Commands(void) | |
| { | |
| int mouse_buttonstate = 0; | |
| if (!mouse_avail) | |
| return; | |
| if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) | |
| mouse_buttonstate |= 1; | |
| if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT)) | |
| mouse_buttonstate |= 2; | |
| if (IsMouseButtonDown(MOUSE_BUTTON_MIDDLE)) | |
| mouse_buttonstate |= 4; | |
| int quake_buttonstate = ((mouse_buttonstate & (~0x06)) | ((mouse_buttonstate & 0x02) << 1)) | ((mouse_buttonstate & 0x04) >> 1); | |
| for (int i = 0; i < 3; i++) | |
| { | |
| if ((quake_buttonstate & (1 << i)) && (!(mouse_oldbuttonstate & (1 << i)))) | |
| Key_Event(K_MOUSE1 + i, 1); | |
| if ((!(quake_buttonstate & (1 << i))) && (mouse_oldbuttonstate & (1 << i))) | |
| Key_Event(K_MOUSE1 + i, 0); | |
| } | |
| mouse_oldbuttonstate = quake_buttonstate; | |
| } | |
| void IN_Move(usercmd_t *cmd) | |
| { | |
| if (!mouse_avail) | |
| return; | |
| mouse_x *= sensitivity.value; | |
| mouse_y *= sensitivity.value; | |
| if ((in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1))) | |
| cmd->sidemove += m_side.value * mouse_x; | |
| else | |
| cl.viewangles[YAW] -= m_yaw.value * mouse_x; | |
| if (in_mlook.state & 1) | |
| V_StopPitchDrift(); | |
| if ((in_mlook.state & 1) && (!(in_strafe.state & 1))) | |
| { | |
| cl.viewangles[PITCH] += m_pitch.value * mouse_y; | |
| if (cl.viewangles[PITCH] > 80) | |
| cl.viewangles[PITCH] = 80; | |
| if (cl.viewangles[PITCH] < (-70)) | |
| cl.viewangles[PITCH] = -70; | |
| } | |
| else | |
| { | |
| if ((in_strafe.state & 1) && noclip_anglehack) | |
| cmd->upmove -= m_forward.value * mouse_y; | |
| else | |
| cmd->forwardmove -= m_forward.value * mouse_y; | |
| } | |
| mouse_x = 0.0; | |
| mouse_y = 0.0; | |
| } | |
| char *Sys_ConsoleInput(void) | |
| { | |
| return 0; | |
| } | |
| void VID_LockBuffer() | |
| { | |
| } | |
| void VID_UnlockBuffer() | |
| { | |
| } | |
| void VID_HandlePause(bool pause) | |
| { | |
| } | |
| float V_CalcRoll(vec3_t angles, vec3_t velocity) | |
| { | |
| float sign; | |
| float side; | |
| float value; | |
| AngleVectors(angles, forward, right, up); | |
| side = DotProduct(velocity, right); | |
| sign = (side < 0) ? (-1) : (1); | |
| side = fabs(side); | |
| value = cl_rollangle.value; | |
| if (side < cl_rollspeed.value) | |
| side = (side * value) / cl_rollspeed.value; | |
| else | |
| side = value; | |
| return side * sign; | |
| } | |
| float V_CalcBob(void) | |
| { | |
| float bob; | |
| float cycle; | |
| cycle = cl.time - (((int32_t) (cl.time / cl_bobcycle.value)) * cl_bobcycle.value); | |
| cycle /= cl_bobcycle.value; | |
| if (cycle < cl_bobup.value) | |
| cycle = (M_PI * cycle) / cl_bobup.value; | |
| else | |
| cycle = M_PI + ((M_PI * (cycle - cl_bobup.value)) / (1.0 - cl_bobup.value)); | |
| bob = sqrt((cl.velocity[0] * cl.velocity[0]) + (cl.velocity[1] * cl.velocity[1])) * cl_bob.value; | |
| bob = (bob * 0.3) + ((bob * 0.7) * sin(cycle)); | |
| if (bob > 4) | |
| bob = 4; | |
| else | |
| if (bob < (-7)) | |
| bob = -7; | |
| return bob; | |
| } | |
| void V_StartPitchDrift(void) | |
| { | |
| if (cl.laststop == cl.time) | |
| { | |
| return; | |
| } | |
| if (cl.nodrift || (!cl.pitchvel)) | |
| { | |
| cl.pitchvel = v_centerspeed.value; | |
| cl.nodrift = 0; | |
| cl.driftmove = 0; | |
| } | |
| } | |
| void V_StopPitchDrift(void) | |
| { | |
| cl.laststop = cl.time; | |
| cl.nodrift = 1; | |
| cl.pitchvel = 0; | |
| } | |
| void V_DriftPitch(void) | |
| { | |
| float delta; | |
| float move; | |
| if ((noclip_anglehack || (!cl.onground)) || cls.demoplayback) | |
| { | |
| cl.driftmove = 0; | |
| cl.pitchvel = 0; | |
| return; | |
| } | |
| if (cl.nodrift) | |
| { | |
| if (fabs(cl.cmd.forwardmove) < cl_forwardspeed.value) | |
| cl.driftmove = 0; | |
| else | |
| cl.driftmove += host_frametime; | |
| if (cl.driftmove > v_centermove.value) | |
| { | |
| V_StartPitchDrift(); | |
| } | |
| return; | |
| } | |
| delta = cl.idealpitch - cl.viewangles[PITCH]; | |
| if (!delta) | |
| { | |
| cl.pitchvel = 0; | |
| return; | |
| } | |
| move = host_frametime * cl.pitchvel; | |
| cl.pitchvel += host_frametime * v_centerspeed.value; | |
| if (delta > 0) | |
| { | |
| if (move > delta) | |
| { | |
| cl.pitchvel = 0; | |
| move = delta; | |
| } | |
| cl.viewangles[PITCH] += move; | |
| } | |
| else | |
| if (delta < 0) | |
| { | |
| if (move > (-delta)) | |
| { | |
| cl.pitchvel = 0; | |
| move = -delta; | |
| } | |
| cl.viewangles[PITCH] -= move; | |
| } | |
| } | |
| void BuildGammaTable(float g) | |
| { | |
| int32_t i; | |
| int32_t inf; | |
| if (g == 1.0) | |
| { | |
| for (i = 0; i < 256; i++) | |
| gammatable[i] = i; | |
| return; | |
| } | |
| for (i = 0; i < 256; i++) | |
| { | |
| inf = (255 * pow((i + 0.5) / 255.5, g)) + 0.5; | |
| if (inf < 0) | |
| inf = 0; | |
| if (inf > 255) | |
| inf = 255; | |
| gammatable[i] = inf; | |
| } | |
| } | |
| bool V_CheckGamma(void) | |
| { | |
| static float oldgammavalue; | |
| if (v_gamma.value == oldgammavalue) | |
| return 0; | |
| oldgammavalue = v_gamma.value; | |
| BuildGammaTable(v_gamma.value); | |
| vid.recalc_refdef = 1; | |
| return 1; | |
| } | |
| void V_ParseDamage(void) | |
| { | |
| int32_t armor; | |
| int32_t blood; | |
| vec3_t from; | |
| int32_t i; | |
| vec3_t forward; | |
| vec3_t right; | |
| vec3_t up; | |
| entity_t *ent; | |
| float side; | |
| float count; | |
| armor = MSG_ReadByte(); | |
| blood = MSG_ReadByte(); | |
| for (i = 0; i < 3; i++) | |
| from[i] = MSG_ReadCoord(); | |
| count = (blood * 0.5) + (armor * 0.5); | |
| if (count < 10) | |
| count = 10; | |
| cl.faceanimtime = cl.time + 0.2; | |
| cl.cshifts[CSHIFT_DAMAGE].percent += 3 * count; | |
| if (cl.cshifts[CSHIFT_DAMAGE].percent < 0) | |
| cl.cshifts[CSHIFT_DAMAGE].percent = 0; | |
| if (cl.cshifts[CSHIFT_DAMAGE].percent > 150) | |
| cl.cshifts[CSHIFT_DAMAGE].percent = 150; | |
| if (armor > blood) | |
| { | |
| cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200; | |
| cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100; | |
| cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 100; | |
| } | |
| else | |
| if (armor) | |
| { | |
| cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 220; | |
| cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 50; | |
| cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 50; | |
| } | |
| else | |
| { | |
| cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 255; | |
| cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 0; | |
| cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 0; | |
| } | |
| ent = &cl_entities[cl.viewentity]; | |
| VectorSubtract(from, ent->origin, from); | |
| VectorNormalize(from); | |
| AngleVectors(ent->angles, forward, right, up); | |
| side = DotProduct(from, right); | |
| v_dmg_roll = (count * side) * v_kickroll.value; | |
| side = DotProduct(from, forward); | |
| v_dmg_pitch = (count * side) * v_kickpitch.value; | |
| v_dmg_time = v_kicktime.value; | |
| } | |
| void V_cshift_f(void) | |
| { | |
| cshift_empty.destcolor[0] = atoi(Cmd_Argv(1)); | |
| cshift_empty.destcolor[1] = atoi(Cmd_Argv(2)); | |
| cshift_empty.destcolor[2] = atoi(Cmd_Argv(3)); | |
| cshift_empty.percent = atoi(Cmd_Argv(4)); | |
| } | |
| void V_BonusFlash_f(void) | |
| { | |
| cl.cshifts[CSHIFT_BONUS].destcolor[0] = 215; | |
| cl.cshifts[CSHIFT_BONUS].destcolor[1] = 186; | |
| cl.cshifts[CSHIFT_BONUS].destcolor[2] = 69; | |
| cl.cshifts[CSHIFT_BONUS].percent = 50; | |
| } | |
| void V_SetContentsColor(int32_t contents) | |
| { | |
| switch (contents) | |
| { | |
| case CONTENTS_EMPTY: | |
| case CONTENTS_SOLID: | |
| cl.cshifts[CSHIFT_CONTENTS] = cshift_empty; | |
| break; | |
| case CONTENTS_LAVA: | |
| cl.cshifts[CSHIFT_CONTENTS] = cshift_lava; | |
| break; | |
| case CONTENTS_SLIME: | |
| cl.cshifts[CSHIFT_CONTENTS] = cshift_slime; | |
| break; | |
| default: | |
| cl.cshifts[CSHIFT_CONTENTS] = cshift_water; | |
| } | |
| } | |
| void V_CalcPowerupCshift(void) | |
| { | |
| if (cl.items & IT_QUAD) | |
| { | |
| cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0; | |
| cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 0; | |
| cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 255; | |
| cl.cshifts[CSHIFT_POWERUP].percent = 30; | |
| } | |
| else | |
| if (cl.items & IT_SUIT) | |
| { | |
| cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0; | |
| cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255; | |
| cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0; | |
| cl.cshifts[CSHIFT_POWERUP].percent = 20; | |
| } | |
| else | |
| if (cl.items & IT_INVISIBILITY) | |
| { | |
| cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 100; | |
| cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 100; | |
| cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 100; | |
| cl.cshifts[CSHIFT_POWERUP].percent = 100; | |
| } | |
| else | |
| if (cl.items & IT_INVULNERABILITY) | |
| { | |
| cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 255; | |
| cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255; | |
| cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0; | |
| cl.cshifts[CSHIFT_POWERUP].percent = 30; | |
| } | |
| else | |
| cl.cshifts[CSHIFT_POWERUP].percent = 0; | |
| } | |
| void V_UpdatePalette(void) | |
| { | |
| int32_t i; | |
| int32_t j; | |
| bool new; | |
| uint8_t *basepal; | |
| uint8_t *newpal; | |
| uint8_t pal[768]; | |
| int32_t r; | |
| int32_t g; | |
| int32_t b; | |
| bool force; | |
| V_CalcPowerupCshift(); | |
| new = 0; | |
| for (i = 0; i < NUM_CSHIFTS; i++) | |
| { | |
| if (cl.cshifts[i].percent != cl.prev_cshifts[i].percent) | |
| { | |
| new = 1; | |
| cl.prev_cshifts[i].percent = cl.cshifts[i].percent; | |
| } | |
| for (j = 0; j < 3; j++) | |
| if (cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j]) | |
| { | |
| new = 1; | |
| cl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j]; | |
| } | |
| } | |
| cl.cshifts[CSHIFT_DAMAGE].percent -= host_frametime * 150; | |
| if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0) | |
| cl.cshifts[CSHIFT_DAMAGE].percent = 0; | |
| cl.cshifts[CSHIFT_BONUS].percent -= host_frametime * 100; | |
| if (cl.cshifts[CSHIFT_BONUS].percent <= 0) | |
| cl.cshifts[CSHIFT_BONUS].percent = 0; | |
| force = V_CheckGamma(); | |
| if ((!new) && (!force)) | |
| return; | |
| basepal = host_basepal; | |
| newpal = pal; | |
| for (i = 0; i < 256; i++) | |
| { | |
| r = basepal[0]; | |
| g = basepal[1]; | |
| b = basepal[2]; | |
| basepal += 3; | |
| for (j = 0; j < NUM_CSHIFTS; j++) | |
| { | |
| r += (cl.cshifts[j].percent * (cl.cshifts[j].destcolor[0] - r)) >> 8; | |
| g += (cl.cshifts[j].percent * (cl.cshifts[j].destcolor[1] - g)) >> 8; | |
| b += (cl.cshifts[j].percent * (cl.cshifts[j].destcolor[2] - b)) >> 8; | |
| } | |
| newpal[0] = gammatable[r]; | |
| newpal[1] = gammatable[g]; | |
| newpal[2] = gammatable[b]; | |
| newpal += 3; | |
| } | |
| VID_ShiftPalette(pal); | |
| } | |
| float angledelta(float a) | |
| { | |
| a = anglemod(a); | |
| if (a > 180) | |
| a -= 360; | |
| return a; | |
| } | |
| void CalcGunAngle(void) | |
| { | |
| float yaw; | |
| float pitch; | |
| float move; | |
| static float oldyaw = 0; | |
| static float oldpitch = 0; | |
| yaw = r_refdef.viewangles[YAW]; | |
| pitch = -r_refdef.viewangles[PITCH]; | |
| yaw = angledelta(yaw - r_refdef.viewangles[YAW]) * 0.4; | |
| if (yaw > 10) | |
| yaw = 10; | |
| if (yaw < (-10)) | |
| yaw = -10; | |
| pitch = angledelta((-pitch) - r_refdef.viewangles[PITCH]) * 0.4; | |
| if (pitch > 10) | |
| pitch = 10; | |
| if (pitch < (-10)) | |
| pitch = -10; | |
| move = host_frametime * 20; | |
| if (yaw > oldyaw) | |
| { | |
| if ((oldyaw + move) < yaw) | |
| yaw = oldyaw + move; | |
| } | |
| else | |
| { | |
| if ((oldyaw - move) > yaw) | |
| yaw = oldyaw - move; | |
| } | |
| if (pitch > oldpitch) | |
| { | |
| if ((oldpitch + move) < pitch) | |
| pitch = oldpitch + move; | |
| } | |
| else | |
| { | |
| if ((oldpitch - move) > pitch) | |
| pitch = oldpitch - move; | |
| } | |
| oldyaw = yaw; | |
| oldpitch = pitch; | |
| cl.viewent.angles[YAW] = r_refdef.viewangles[YAW] + yaw; | |
| cl.viewent.angles[PITCH] = -(r_refdef.viewangles[PITCH] + pitch); | |
| cl.viewent.angles[ROLL] -= (v_idlescale.value * sin(cl.time * v_iroll_cycle.value)) * v_iroll_level.value; | |
| cl.viewent.angles[PITCH] -= (v_idlescale.value * sin(cl.time * v_ipitch_cycle.value)) * v_ipitch_level.value; | |
| cl.viewent.angles[YAW] -= (v_idlescale.value * sin(cl.time * v_iyaw_cycle.value)) * v_iyaw_level.value; | |
| } | |
| void V_BoundOffsets(void) | |
| { | |
| entity_t *ent; | |
| ent = &cl_entities[cl.viewentity]; | |
| if (r_refdef.vieworg[0] < (ent->origin[0] - 14)) | |
| r_refdef.vieworg[0] = ent->origin[0] - 14; | |
| else | |
| if (r_refdef.vieworg[0] > (ent->origin[0] + 14)) | |
| r_refdef.vieworg[0] = ent->origin[0] + 14; | |
| if (r_refdef.vieworg[1] < (ent->origin[1] - 14)) | |
| r_refdef.vieworg[1] = ent->origin[1] - 14; | |
| else | |
| if (r_refdef.vieworg[1] > (ent->origin[1] + 14)) | |
| r_refdef.vieworg[1] = ent->origin[1] + 14; | |
| if (r_refdef.vieworg[2] < (ent->origin[2] - 22)) | |
| r_refdef.vieworg[2] = ent->origin[2] - 22; | |
| else | |
| if (r_refdef.vieworg[2] > (ent->origin[2] + 30)) | |
| r_refdef.vieworg[2] = ent->origin[2] + 30; | |
| } | |
| void V_AddIdle(void) | |
| { | |
| r_refdef.viewangles[ROLL] += (v_idlescale.value * sin(cl.time * v_iroll_cycle.value)) * v_iroll_level.value; | |
| r_refdef.viewangles[PITCH] += (v_idlescale.value * sin(cl.time * v_ipitch_cycle.value)) * v_ipitch_level.value; | |
| r_refdef.viewangles[YAW] += (v_idlescale.value * sin(cl.time * v_iyaw_cycle.value)) * v_iyaw_level.value; | |
| } | |
| void V_CalcViewRoll(void) | |
| { | |
| float side; | |
| side = V_CalcRoll(cl_entities[cl.viewentity].angles, cl.velocity); | |
| r_refdef.viewangles[ROLL] += side; | |
| if (v_dmg_time > 0) | |
| { | |
| r_refdef.viewangles[ROLL] += (v_dmg_time / v_kicktime.value) * v_dmg_roll; | |
| r_refdef.viewangles[PITCH] += (v_dmg_time / v_kicktime.value) * v_dmg_pitch; | |
| v_dmg_time -= host_frametime; | |
| } | |
| if (cl.stats[STAT_HEALTH] <= 0) | |
| { | |
| r_refdef.viewangles[ROLL] = 80; | |
| return; | |
| } | |
| } | |
| void V_CalcIntermissionRefdef(void) | |
| { | |
| entity_t *ent; | |
| entity_t *view; | |
| float old; | |
| ent = &cl_entities[cl.viewentity]; | |
| view = &cl.viewent; | |
| VectorCopy(ent->origin, r_refdef.vieworg); | |
| VectorCopy(ent->angles, r_refdef.viewangles); | |
| view->model = 0; | |
| old = v_idlescale.value; | |
| v_idlescale.value = 1; | |
| V_AddIdle(); | |
| v_idlescale.value = old; | |
| } | |
| void V_CalcRefdef(void) | |
| { | |
| entity_t *ent; | |
| entity_t *view; | |
| int32_t i; | |
| vec3_t forward; | |
| vec3_t right; | |
| vec3_t up; | |
| vec3_t angles; | |
| float bob; | |
| static float oldz = 0; | |
| V_DriftPitch(); | |
| ent = &cl_entities[cl.viewentity]; | |
| view = &cl.viewent; | |
| ent->angles[YAW] = cl.viewangles[YAW]; | |
| ent->angles[PITCH] = -cl.viewangles[PITCH]; | |
| bob = V_CalcBob(); | |
| VectorCopy(ent->origin, r_refdef.vieworg); | |
| r_refdef.vieworg[2] += cl.viewheight + bob; | |
| r_refdef.vieworg[0] += 1.0 / 32; | |
| r_refdef.vieworg[1] += 1.0 / 32; | |
| r_refdef.vieworg[2] += 1.0 / 32; | |
| VectorCopy(cl.viewangles, r_refdef.viewangles); | |
| V_CalcViewRoll(); | |
| V_AddIdle(); | |
| angles[PITCH] = -ent->angles[PITCH]; | |
| angles[YAW] = ent->angles[YAW]; | |
| angles[ROLL] = ent->angles[ROLL]; | |
| AngleVectors(angles, forward, right, up); | |
| for (i = 0; i < 3; i++) | |
| r_refdef.vieworg[i] += ((scr_ofsx.value * forward[i]) + (scr_ofsy.value * right[i])) + (scr_ofsz.value * up[i]); | |
| V_BoundOffsets(); | |
| VectorCopy(cl.viewangles, view->angles); | |
| CalcGunAngle(); | |
| VectorCopy(ent->origin, view->origin); | |
| view->origin[2] += cl.viewheight; | |
| for (i = 0; i < 3; i++) | |
| { | |
| view->origin[i] += (forward[i] * bob) * 0.4; | |
| } | |
| view->origin[2] += bob; | |
| if (scr_viewsize.value == 110) | |
| view->origin[2] += 1; | |
| else | |
| if (scr_viewsize.value == 100) | |
| view->origin[2] += 2; | |
| else | |
| if (scr_viewsize.value == 90) | |
| view->origin[2] += 1; | |
| else | |
| if (scr_viewsize.value == 80) | |
| view->origin[2] += 0.5; | |
| view->model = cl.model_precache[cl.stats[STAT_WEAPON]]; | |
| view->frame = cl.stats[STAT_WEAPONFRAME]; | |
| view->colormap = vid.colormap; | |
| VectorAdd(r_refdef.viewangles, cl.punchangle, r_refdef.viewangles); | |
| if (cl.onground && ((ent->origin[2] - oldz) > 0)) | |
| { | |
| float steptime; | |
| steptime = cl.time - cl.oldtime; | |
| if (steptime < 0) | |
| steptime = 0; | |
| oldz += steptime * 80; | |
| if (oldz > ent->origin[2]) | |
| oldz = ent->origin[2]; | |
| if ((ent->origin[2] - oldz) > 12) | |
| oldz = ent->origin[2] - 12; | |
| r_refdef.vieworg[2] += oldz - ent->origin[2]; | |
| view->origin[2] += oldz - ent->origin[2]; | |
| } | |
| else | |
| oldz = ent->origin[2]; | |
| if (chase_active.value) | |
| Chase_Update(); | |
| } | |
| void V_RenderView(void) | |
| { | |
| if (con_forcedup) | |
| return; | |
| if (cl.maxclients > 1) | |
| { | |
| Cvar_Set("scr_ofsx", "0"); | |
| Cvar_Set("scr_ofsy", "0"); | |
| Cvar_Set("scr_ofsz", "0"); | |
| } | |
| if (cl.intermission) | |
| { | |
| V_CalcIntermissionRefdef(); | |
| } | |
| else | |
| { | |
| if (!cl.paused) | |
| V_CalcRefdef(); | |
| } | |
| R_PushDlights(); | |
| if (lcd_x.value) | |
| { | |
| int32_t i; | |
| vid.rowbytes <<= 1; | |
| vid.aspect *= 0.5; | |
| r_refdef.viewangles[YAW] -= lcd_yaw.value; | |
| for (i = 0; i < 3; i++) | |
| r_refdef.vieworg[i] -= right[i] * lcd_x.value; | |
| R_RenderView(); | |
| vid.buffer += vid.rowbytes >> 1; | |
| R_PushDlights(); | |
| r_refdef.viewangles[YAW] += lcd_yaw.value * 2; | |
| for (i = 0; i < 3; i++) | |
| r_refdef.vieworg[i] += (2 * right[i]) * lcd_x.value; | |
| R_RenderView(); | |
| vid.buffer -= vid.rowbytes >> 1; | |
| r_refdef.vrect.height <<= 1; | |
| vid.rowbytes >>= 1; | |
| vid.aspect *= 2; | |
| } | |
| else | |
| { | |
| R_RenderView(); | |
| } | |
| if (crosshair.value) | |
| Draw_Character((scr_vrect.x + (scr_vrect.width / 2)) + cl_crossx.value, (scr_vrect.y + (scr_vrect.height / 2)) + cl_crossy.value, '+'); | |
| } | |
| void V_Init(void) | |
| { | |
| Cmd_AddCommand("v_cshift", V_cshift_f); | |
| Cmd_AddCommand("bf", V_BonusFlash_f); | |
| Cmd_AddCommand("centerview", V_StartPitchDrift); | |
| Cvar_RegisterVariable(&lcd_x); | |
| Cvar_RegisterVariable(&lcd_yaw); | |
| Cvar_RegisterVariable(&v_centermove); | |
| Cvar_RegisterVariable(&v_centerspeed); | |
| Cvar_RegisterVariable(&v_iyaw_cycle); | |
| Cvar_RegisterVariable(&v_iroll_cycle); | |
| Cvar_RegisterVariable(&v_ipitch_cycle); | |
| Cvar_RegisterVariable(&v_iyaw_level); | |
| Cvar_RegisterVariable(&v_iroll_level); | |
| Cvar_RegisterVariable(&v_ipitch_level); | |
| Cvar_RegisterVariable(&v_idlescale); | |
| Cvar_RegisterVariable(&crosshair); | |
| Cvar_RegisterVariable(&cl_crossx); | |
| Cvar_RegisterVariable(&cl_crossy); | |
| Cvar_RegisterVariable(&gl_cshiftpercent); | |
| Cvar_RegisterVariable(&scr_ofsx); | |
| Cvar_RegisterVariable(&scr_ofsy); | |
| Cvar_RegisterVariable(&scr_ofsz); | |
| Cvar_RegisterVariable(&cl_rollspeed); | |
| Cvar_RegisterVariable(&cl_rollangle); | |
| Cvar_RegisterVariable(&cl_bob); | |
| Cvar_RegisterVariable(&cl_bobcycle); | |
| Cvar_RegisterVariable(&cl_bobup); | |
| Cvar_RegisterVariable(&v_kicktime); | |
| Cvar_RegisterVariable(&v_kickroll); | |
| Cvar_RegisterVariable(&v_kickpitch); | |
| BuildGammaTable(1.0); | |
| Cvar_RegisterVariable(&v_gamma); | |
| } | |
| void W_CleanupName(char *in, char *out) | |
| { | |
| int32_t i; | |
| int32_t c; | |
| for (i = 0; i < 16; i++) | |
| { | |
| c = in[i]; | |
| if (!c) | |
| break; | |
| if ((c >= 'A') && (c <= 'Z')) | |
| c += 'a' - 'A'; | |
| out[i] = c; | |
| } | |
| for (; i < 16; i++) | |
| out[i] = 0; | |
| } | |
| void W_LoadWadFile(char *filename) | |
| { | |
| lumpinfo_t *lump_p; | |
| wadinfo_t *header; | |
| uint32_t i; | |
| int32_t infotableofs; | |
| wad_base = COM_LoadHunkFile(filename); | |
| if (!wad_base) | |
| Sys_Error("W_LoadWadFile: couldn't load %s", filename); | |
| header = (wadinfo_t *) wad_base; | |
| if ((((header->identification[0] != 'W') || (header->identification[1] != 'A')) || (header->identification[2] != 'D')) || (header->identification[3] != '2')) | |
| Sys_Error("Wad file %s doesn't have WAD2 id\n", filename); | |
| wad_numlumps = header->numlumps; | |
| infotableofs = header->infotableofs; | |
| wad_lumps = (lumpinfo_t *) (wad_base + infotableofs); | |
| for (i = 0, lump_p = wad_lumps; i < wad_numlumps; i++, lump_p++) | |
| { | |
| lump_p->filepos = lump_p->filepos; | |
| lump_p->size = lump_p->size; | |
| W_CleanupName(lump_p->name, lump_p->name); | |
| if (lump_p->type == TYP_QPIC) | |
| SwapPic((qpic_t *) (wad_base + lump_p->filepos)); | |
| } | |
| } | |
| lumpinfo_t *W_GetLumpinfo(char *name) | |
| { | |
| int32_t i; | |
| lumpinfo_t *lump_p; | |
| char clean[16]; | |
| W_CleanupName(name, clean); | |
| for (lump_p = wad_lumps, i = 0; i < wad_numlumps; i++, lump_p++) | |
| { | |
| if (!strcmp(clean, lump_p->name)) | |
| return lump_p; | |
| } | |
| Sys_Error("W_GetLumpinfo: %s not found", name); | |
| return 0; | |
| } | |
| void *W_GetLumpName(char *name) | |
| { | |
| lumpinfo_t *lump; | |
| lump = W_GetLumpinfo(name); | |
| return (void *) (wad_base + lump->filepos); | |
| } | |
| void *W_GetLumpNum(int32_t num) | |
| { | |
| lumpinfo_t *lump; | |
| if ((num < 0) || (num > wad_numlumps)) | |
| Sys_Error("W_GetLumpNum: bad number: %i", num); | |
| lump = wad_lumps + num; | |
| return (void *) (wad_base + lump->filepos); | |
| } | |
| void SwapPic(qpic_t *pic) | |
| { | |
| pic->width = pic->width; | |
| pic->height = pic->height; | |
| } | |
| void SV_InitBoxHull(void) | |
| { | |
| int32_t i; | |
| int32_t side; | |
| box_hull.clipnodes = box_clipnodes; | |
| box_hull.planes = box_planes; | |
| box_hull.firstclipnode = 0; | |
| box_hull.lastclipnode = 5; | |
| for (i = 0; i < 6; i++) | |
| { | |
| box_clipnodes[i].planenum = i; | |
| side = i & 1; | |
| box_clipnodes[i].children[side] = CONTENTS_EMPTY; | |
| if (i != 5) | |
| box_clipnodes[i].children[side ^ 1] = i + 1; | |
| else | |
| box_clipnodes[i].children[side ^ 1] = CONTENTS_SOLID; | |
| box_planes[i].type = i >> 1; | |
| box_planes[i].normal[i >> 1] = 1; | |
| } | |
| } | |
| hull_t *SV_HullForBox(vec3_t mins, vec3_t maxs) | |
| { | |
| box_planes[0].dist = maxs[0]; | |
| box_planes[1].dist = mins[0]; | |
| box_planes[2].dist = maxs[1]; | |
| box_planes[3].dist = mins[1]; | |
| box_planes[4].dist = maxs[2]; | |
| box_planes[5].dist = mins[2]; | |
| return &box_hull; | |
| } | |
| hull_t *SV_HullForEntity(edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t offset) | |
| { | |
| model_t *model; | |
| vec3_t size; | |
| vec3_t hullmins; | |
| vec3_t hullmaxs; | |
| hull_t *hull; | |
| if (ent->v.solid == SOLID_BSP) | |
| { | |
| if (ent->v.movetype != MOVETYPE_PUSH) | |
| Sys_Error("SOLID_BSP without MOVETYPE_PUSH"); | |
| model = sv.models[(int32_t) ent->v.modelindex]; | |
| if ((!model) || (model->type != mod_brush)) | |
| Sys_Error("MOVETYPE_PUSH with a non bsp model"); | |
| VectorSubtract(maxs, mins, size); | |
| if (size[0] < 3) | |
| hull = &model->hulls[0]; | |
| else | |
| if (size[0] <= 32) | |
| hull = &model->hulls[1]; | |
| else | |
| hull = &model->hulls[2]; | |
| VectorSubtract(hull->clip_mins, mins, offset); | |
| VectorAdd(offset, ent->v.origin, offset); | |
| } | |
| else | |
| { | |
| VectorSubtract(ent->v.mins, maxs, hullmins); | |
| VectorSubtract(ent->v.maxs, mins, hullmaxs); | |
| hull = SV_HullForBox(hullmins, hullmaxs); | |
| VectorCopy(ent->v.origin, offset); | |
| } | |
| return hull; | |
| } | |
| areanode_t *SV_CreateAreaNode(int32_t depth, vec3_t mins, vec3_t maxs) | |
| { | |
| areanode_t *anode; | |
| vec3_t size; | |
| vec3_t mins1; | |
| vec3_t maxs1; | |
| vec3_t mins2; | |
| vec3_t maxs2; | |
| anode = &sv_areanodes[sv_numareanodes]; | |
| sv_numareanodes++; | |
| ClearLink(&anode->trigger_edicts); | |
| ClearLink(&anode->solid_edicts); | |
| if (depth == AREA_DEPTH) | |
| { | |
| anode->axis = -1; | |
| anode->children[0] = (anode->children[1] = 0); | |
| return anode; | |
| } | |
| VectorSubtract(maxs, mins, size); | |
| if (size[0] > size[1]) | |
| anode->axis = 0; | |
| else | |
| anode->axis = 1; | |
| anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]); | |
| VectorCopy(mins, mins1); | |
| VectorCopy(mins, mins2); | |
| VectorCopy(maxs, maxs1); | |
| VectorCopy(maxs, maxs2); | |
| maxs1[anode->axis] = (mins2[anode->axis] = anode->dist); | |
| anode->children[0] = SV_CreateAreaNode(depth + 1, mins2, maxs2); | |
| anode->children[1] = SV_CreateAreaNode(depth + 1, mins1, maxs1); | |
| return anode; | |
| } | |
| void SV_ClearWorld(void) | |
| { | |
| SV_InitBoxHull(); | |
| memset(sv_areanodes, 0, sizeof(sv_areanodes)); | |
| sv_numareanodes = 0; | |
| SV_CreateAreaNode(0, sv.worldmodel->mins, sv.worldmodel->maxs); | |
| } | |
| void SV_UnlinkEdict(edict_t *ent) | |
| { | |
| if (!ent->area.prev) | |
| return; | |
| RemoveLink(&ent->area); | |
| ent->area.prev = (ent->area.next = 0); | |
| } | |
| void SV_TouchLinks(edict_t *ent, areanode_t *node) | |
| { | |
| link_t *l; | |
| link_t *next; | |
| edict_t *touch; | |
| int32_t old_self; | |
| int32_t old_other; | |
| for (l = node->trigger_edicts.next; l != (&node->trigger_edicts); l = next) | |
| { | |
| next = l->next; | |
| touch = EDICT_FROM_AREA(l); | |
| if (touch == ent) | |
| continue; | |
| if ((!touch->v.touch) || (touch->v.solid != SOLID_TRIGGER)) | |
| continue; | |
| if ((((((ent->v.absmin[0] > touch->v.absmax[0]) || (ent->v.absmin[1] > touch->v.absmax[1])) || (ent->v.absmin[2] > touch->v.absmax[2])) || (ent->v.absmax[0] < touch->v.absmin[0])) || (ent->v.absmax[1] < touch->v.absmin[1])) || (ent->v.absmax[2] < touch->v.absmin[2])) | |
| continue; | |
| old_self = pr_global_struct->self; | |
| old_other = pr_global_struct->other; | |
| pr_global_struct->self = EDICT_TO_PROG(touch); | |
| pr_global_struct->other = EDICT_TO_PROG(ent); | |
| pr_global_struct->time = sv.time; | |
| PR_ExecuteProgram(touch->v.touch); | |
| pr_global_struct->self = old_self; | |
| pr_global_struct->other = old_other; | |
| } | |
| if (node->axis == (-1)) | |
| return; | |
| if (ent->v.absmax[node->axis] > node->dist) | |
| SV_TouchLinks(ent, node->children[0]); | |
| if (ent->v.absmin[node->axis] < node->dist) | |
| SV_TouchLinks(ent, node->children[1]); | |
| } | |
| void SV_FindTouchedLeafs(edict_t *ent, mnode_t *node) | |
| { | |
| mplane_t *splitplane; | |
| mleaf_t *leaf; | |
| int32_t sides; | |
| int32_t leafnum; | |
| if (node->contents == CONTENTS_SOLID) | |
| return; | |
| if (node->contents < 0) | |
| { | |
| if (ent->num_leafs == MAX_ENT_LEAFS) | |
| return; | |
| leaf = (mleaf_t *) node; | |
| leafnum = (leaf - sv.worldmodel->leafs) - 1; | |
| ent->leafnums[ent->num_leafs] = leafnum; | |
| ent->num_leafs++; | |
| return; | |
| } | |
| splitplane = node->plane; | |
| sides = BOX_ON_PLANE_SIDE(ent->v.absmin, ent->v.absmax, splitplane); | |
| if (sides & 1) | |
| SV_FindTouchedLeafs(ent, node->children[0]); | |
| if (sides & 2) | |
| SV_FindTouchedLeafs(ent, node->children[1]); | |
| } | |
| void SV_LinkEdict(edict_t *ent, bool touch_triggers) | |
| { | |
| areanode_t *node; | |
| if (ent->area.prev) | |
| SV_UnlinkEdict(ent); | |
| if (ent == sv.edicts) | |
| return; | |
| if (ent->free) | |
| return; | |
| VectorAdd(ent->v.origin, ent->v.mins, ent->v.absmin); | |
| VectorAdd(ent->v.origin, ent->v.maxs, ent->v.absmax); | |
| if (((int32_t) ent->v.flags) & FL_ITEM) | |
| { | |
| ent->v.absmin[0] -= 15; | |
| ent->v.absmin[1] -= 15; | |
| ent->v.absmax[0] += 15; | |
| ent->v.absmax[1] += 15; | |
| } | |
| else | |
| { | |
| ent->v.absmin[0] -= 1; | |
| ent->v.absmin[1] -= 1; | |
| ent->v.absmin[2] -= 1; | |
| ent->v.absmax[0] += 1; | |
| ent->v.absmax[1] += 1; | |
| ent->v.absmax[2] += 1; | |
| } | |
| ent->num_leafs = 0; | |
| if (ent->v.modelindex) | |
| SV_FindTouchedLeafs(ent, sv.worldmodel->nodes); | |
| if (ent->v.solid == SOLID_NOT) | |
| return; | |
| node = sv_areanodes; | |
| while (1) | |
| { | |
| if (node->axis == (-1)) | |
| break; | |
| if (ent->v.absmin[node->axis] > node->dist) | |
| node = node->children[0]; | |
| else | |
| if (ent->v.absmax[node->axis] < node->dist) | |
| node = node->children[1]; | |
| else | |
| break; | |
| } | |
| if (ent->v.solid == SOLID_TRIGGER) | |
| InsertLinkBefore(&ent->area, &node->trigger_edicts); | |
| else | |
| InsertLinkBefore(&ent->area, &node->solid_edicts); | |
| if (touch_triggers) | |
| SV_TouchLinks(ent, sv_areanodes); | |
| } | |
| int32_t SV_HullPointContents(hull_t *hull, int32_t num, vec3_t p) | |
| { | |
| float d; | |
| dclipnode_t *node; | |
| mplane_t *plane; | |
| while (num >= 0) | |
| { | |
| if ((num < hull->firstclipnode) || (num > hull->lastclipnode)) | |
| Sys_Error("SV_HullPointContents: bad node number"); | |
| node = hull->clipnodes + num; | |
| plane = hull->planes + node->planenum; | |
| if (plane->type < 3) | |
| d = p[plane->type] - plane->dist; | |
| else | |
| d = DotProduct(plane->normal, p) - plane->dist; | |
| if (d < 0) | |
| num = node->children[1]; | |
| else | |
| num = node->children[0]; | |
| } | |
| return num; | |
| } | |
| int32_t SV_PointContents(vec3_t p) | |
| { | |
| int32_t cont; | |
| cont = SV_HullPointContents(&sv.worldmodel->hulls[0], 0, p); | |
| if ((cont <= CONTENTS_CURRENT_0) && (cont >= CONTENTS_CURRENT_DOWN)) | |
| cont = CONTENTS_WATER; | |
| return cont; | |
| } | |
| int32_t SV_TruePointContents(vec3_t p) | |
| { | |
| return SV_HullPointContents(&sv.worldmodel->hulls[0], 0, p); | |
| } | |
| edict_t *SV_TestEntityPosition(edict_t *ent) | |
| { | |
| trace_t trace; | |
| trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, 0, ent); | |
| if (trace.startsolid) | |
| return sv.edicts; | |
| return 0; | |
| } | |
| bool SV_RecursiveHullCheck(hull_t *hull, int32_t num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace) | |
| { | |
| dclipnode_t *node; | |
| mplane_t *plane; | |
| float t1; | |
| float t2; | |
| float frac; | |
| int32_t i; | |
| vec3_t mid; | |
| int32_t side; | |
| float midf; | |
| if (num < 0) | |
| { | |
| if (num != CONTENTS_SOLID) | |
| { | |
| trace->allsolid = 0; | |
| if (num == CONTENTS_EMPTY) | |
| trace->inopen = 1; | |
| else | |
| trace->inwater = 1; | |
| } | |
| else | |
| trace->startsolid = 1; | |
| return 1; | |
| } | |
| if ((num < hull->firstclipnode) || (num > hull->lastclipnode)) | |
| Sys_Error("SV_RecursiveHullCheck: bad node number"); | |
| node = hull->clipnodes + num; | |
| plane = hull->planes + node->planenum; | |
| if (plane->type < 3) | |
| { | |
| t1 = p1[plane->type] - plane->dist; | |
| t2 = p2[plane->type] - plane->dist; | |
| } | |
| else | |
| { | |
| t1 = DotProduct(plane->normal, p1) - plane->dist; | |
| t2 = DotProduct(plane->normal, p2) - plane->dist; | |
| } | |
| if ((t1 >= 0) && (t2 >= 0)) | |
| return SV_RecursiveHullCheck(hull, node->children[0], p1f, p2f, p1, p2, trace); | |
| if ((t1 < 0) && (t2 < 0)) | |
| return SV_RecursiveHullCheck(hull, node->children[1], p1f, p2f, p1, p2, trace); | |
| if (t1 < 0) | |
| frac = (t1 + DIST_EPSILON) / (t1 - t2); | |
| else | |
| frac = (t1 - DIST_EPSILON) / (t1 - t2); | |
| if (frac < 0) | |
| frac = 0; | |
| if (frac > 1) | |
| frac = 1; | |
| midf = p1f + ((p2f - p1f) * frac); | |
| for (i = 0; i < 3; i++) | |
| mid[i] = p1[i] + (frac * (p2[i] - p1[i])); | |
| side = t1 < 0; | |
| if (!SV_RecursiveHullCheck(hull, node->children[side], p1f, midf, p1, mid, trace)) | |
| return 0; | |
| if (SV_HullPointContents(hull, node->children[side ^ 1], mid) != CONTENTS_SOLID) | |
| return SV_RecursiveHullCheck(hull, node->children[side ^ 1], midf, p2f, mid, p2, trace); | |
| if (trace->allsolid) | |
| return 0; | |
| if (!side) | |
| { | |
| VectorCopy(plane->normal, trace->plane.normal); | |
| trace->plane.dist = plane->dist; | |
| } | |
| else | |
| { | |
| VectorSubtract(vec3_origin, plane->normal, trace->plane.normal); | |
| trace->plane.dist = -plane->dist; | |
| } | |
| while (SV_HullPointContents(hull, hull->firstclipnode, mid) == CONTENTS_SOLID) | |
| { | |
| frac -= 0.1; | |
| if (frac < 0) | |
| { | |
| trace->fraction = midf; | |
| VectorCopy(mid, trace->endpos); | |
| Con_DPrintf("backup past 0\n"); | |
| return 0; | |
| } | |
| midf = p1f + ((p2f - p1f) * frac); | |
| for (i = 0; i < 3; i++) | |
| mid[i] = p1[i] + (frac * (p2[i] - p1[i])); | |
| } | |
| trace->fraction = midf; | |
| VectorCopy(mid, trace->endpos); | |
| return 0; | |
| } | |
| trace_t SV_ClipMoveToEntity(edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end) | |
| { | |
| trace_t trace; | |
| vec3_t offset; | |
| vec3_t start_l; | |
| vec3_t end_l; | |
| hull_t *hull; | |
| memset(&trace, 0, sizeof(trace_t)); | |
| trace.fraction = 1; | |
| trace.allsolid = 1; | |
| VectorCopy(end, trace.endpos); | |
| hull = SV_HullForEntity(ent, mins, maxs, offset); | |
| VectorSubtract(start, offset, start_l); | |
| VectorSubtract(end, offset, end_l); | |
| SV_RecursiveHullCheck(hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace); | |
| if ((ent->v.solid == SOLID_BSP) && ((ent->v.angles[0] || ent->v.angles[1]) || ent->v.angles[2])) | |
| { | |
| vec3_t a; | |
| vec3_t forward; | |
| vec3_t right; | |
| vec3_t up; | |
| vec3_t temp; | |
| if (trace.fraction != 1) | |
| { | |
| VectorSubtract(vec3_origin, ent->v.angles, a); | |
| AngleVectors(a, forward, right, up); | |
| VectorCopy(trace.endpos, temp); | |
| trace.endpos[0] = DotProduct(temp, forward); | |
| trace.endpos[1] = -DotProduct(temp, right); | |
| trace.endpos[2] = DotProduct(temp, up); | |
| VectorCopy(trace.plane.normal, temp); | |
| trace.plane.normal[0] = DotProduct(temp, forward); | |
| trace.plane.normal[1] = -DotProduct(temp, right); | |
| trace.plane.normal[2] = DotProduct(temp, up); | |
| } | |
| } | |
| if (trace.fraction != 1) | |
| VectorAdd(trace.endpos, offset, trace.endpos); | |
| if ((trace.fraction < 1) || trace.startsolid) | |
| trace.ent = ent; | |
| return trace; | |
| } | |
| void SV_ClipToLinks(areanode_t *node, moveclip_t *clip) | |
| { | |
| link_t *l; | |
| link_t *next; | |
| edict_t *touch; | |
| trace_t trace; | |
| for (l = node->solid_edicts.next; l != (&node->solid_edicts); l = next) | |
| { | |
| next = l->next; | |
| touch = EDICT_FROM_AREA(l); | |
| if (touch->v.solid == SOLID_NOT) | |
| continue; | |
| if (touch == clip->passedict) | |
| continue; | |
| if (touch->v.solid == SOLID_TRIGGER) | |
| Sys_Error("Trigger in clipping list"); | |
| if ((clip->type == MOVE_NOMONSTERS) && (touch->v.solid != SOLID_BSP)) | |
| continue; | |
| if ((((((clip->boxmins[0] > touch->v.absmax[0]) || (clip->boxmins[1] > touch->v.absmax[1])) || (clip->boxmins[2] > touch->v.absmax[2])) || (clip->boxmaxs[0] < touch->v.absmin[0])) || (clip->boxmaxs[1] < touch->v.absmin[1])) || (clip->boxmaxs[2] < touch->v.absmin[2])) | |
| continue; | |
| if ((clip->passedict && clip->passedict->v.size[0]) && (!touch->v.size[0])) | |
| continue; | |
| if (clip->trace.allsolid) | |
| return; | |
| if (clip->passedict) | |
| { | |
| if (PROG_TO_EDICT(touch->v.owner) == clip->passedict) | |
| continue; | |
| if (PROG_TO_EDICT(clip->passedict->v.owner) == touch) | |
| continue; | |
| } | |
| if (((int32_t) touch->v.flags) & FL_MONSTER) | |
| trace = SV_ClipMoveToEntity(touch, clip->start, clip->mins2, clip->maxs2, clip->end); | |
| else | |
| trace = SV_ClipMoveToEntity(touch, clip->start, clip->mins, clip->maxs, clip->end); | |
| if ((trace.allsolid || trace.startsolid) || (trace.fraction < clip->trace.fraction)) | |
| { | |
| trace.ent = touch; | |
| if (clip->trace.startsolid) | |
| { | |
| clip->trace = trace; | |
| clip->trace.startsolid = 1; | |
| } | |
| else | |
| clip->trace = trace; | |
| } | |
| else | |
| if (trace.startsolid) | |
| clip->trace.startsolid = 1; | |
| } | |
| if (node->axis == (-1)) | |
| return; | |
| if (clip->boxmaxs[node->axis] > node->dist) | |
| SV_ClipToLinks(node->children[0], clip); | |
| if (clip->boxmins[node->axis] < node->dist) | |
| SV_ClipToLinks(node->children[1], clip); | |
| } | |
| void SV_MoveBounds(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t boxmins, vec3_t boxmaxs) | |
| { | |
| int32_t i; | |
| for (i = 0; i < 3; i++) | |
| { | |
| if (end[i] > start[i]) | |
| { | |
| boxmins[i] = (start[i] + mins[i]) - 1; | |
| boxmaxs[i] = (end[i] + maxs[i]) + 1; | |
| } | |
| else | |
| { | |
| boxmins[i] = (end[i] + mins[i]) - 1; | |
| boxmaxs[i] = (start[i] + maxs[i]) + 1; | |
| } | |
| } | |
| } | |
| trace_t SV_Move(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int32_t type, edict_t *passedict) | |
| { | |
| moveclip_t clip; | |
| int32_t i; | |
| memset(&clip, 0, sizeof(moveclip_t)); | |
| clip.trace = SV_ClipMoveToEntity(sv.edicts, start, mins, maxs, end); | |
| clip.start = start; | |
| clip.end = end; | |
| clip.mins = mins; | |
| clip.maxs = maxs; | |
| clip.type = type; | |
| clip.passedict = passedict; | |
| if (type == MOVE_MISSILE) | |
| { | |
| for (i = 0; i < 3; i++) | |
| { | |
| clip.mins2[i] = -15; | |
| clip.maxs2[i] = 15; | |
| } | |
| } | |
| else | |
| { | |
| VectorCopy(mins, clip.mins2); | |
| VectorCopy(maxs, clip.maxs2); | |
| } | |
| SV_MoveBounds(start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs); | |
| SV_ClipToLinks(sv_areanodes, &clip); | |
| return clip.trace; | |
| } | |
| void Z_ClearZone(memzone_t *zone, int32_t size) | |
| { | |
| memblock_t *block; | |
| zone->blocklist.next = (zone->blocklist.prev = (block = (memblock_t *) (((uint8_t *) zone) + (sizeof(memzone_t))))); | |
| zone->blocklist.tag = 1; | |
| zone->blocklist.id = 0; | |
| zone->blocklist.size = 0; | |
| zone->rover = block; | |
| block->prev = (block->next = &zone->blocklist); | |
| block->tag = 0; | |
| block->id = ZONEID; | |
| block->size = size - (sizeof(memzone_t)); | |
| } | |
| void Z_Free(void *ptr) | |
| { | |
| memblock_t *block; | |
| memblock_t *other; | |
| if (!ptr) | |
| Sys_Error("Z_Free: NULL pointer"); | |
| block = (memblock_t *) (((uint8_t *) ptr) - (sizeof(memblock_t))); | |
| if (block->id != ZONEID) | |
| Sys_Error("Z_Free: freed a pointer without ZONEID"); | |
| if (block->tag == 0) | |
| Sys_Error("Z_Free: freed a freed pointer"); | |
| block->tag = 0; | |
| other = block->prev; | |
| if (!other->tag) | |
| { | |
| other->size += block->size; | |
| other->next = block->next; | |
| other->next->prev = other; | |
| if (block == mainzone->rover) | |
| mainzone->rover = other; | |
| block = other; | |
| } | |
| other = block->next; | |
| if (!other->tag) | |
| { | |
| block->size += other->size; | |
| block->next = other->next; | |
| block->next->prev = block; | |
| if (other == mainzone->rover) | |
| mainzone->rover = block; | |
| } | |
| } | |
| void *Z_Malloc(int32_t size) | |
| { | |
| void *buf; | |
| Z_CheckHeap(); | |
| buf = Z_TagMalloc(size, 1); | |
| if (!buf) | |
| Sys_Error("Z_Malloc: failed on allocation of %i bytes", size); | |
| memset(buf, 0, size); | |
| return buf; | |
| } | |
| void *Z_TagMalloc(int32_t size, int32_t tag) | |
| { | |
| int32_t extra; | |
| memblock_t *start; | |
| memblock_t *rover; | |
| memblock_t *new; | |
| memblock_t *base; | |
| if (!tag) | |
| Sys_Error("Z_TagMalloc: tried to use a 0 tag"); | |
| size += sizeof(memblock_t); | |
| size += 4; | |
| size = (size + 7) & (~7); | |
| base = (rover = mainzone->rover); | |
| start = base->prev; | |
| do | |
| { | |
| if (rover == start) | |
| return 0; | |
| if (rover->tag) | |
| base = (rover = rover->next); | |
| else | |
| rover = rover->next; | |
| } | |
| while (base->tag || (base->size < size)); | |
| extra = base->size - size; | |
| if (extra > MINFRAGMENT) | |
| { | |
| new = (memblock_t *) (((uint8_t *) base) + size); | |
| new->size = extra; | |
| new->tag = 0; | |
| new->prev = base; | |
| new->id = ZONEID; | |
| new->next = base->next; | |
| new->next->prev = new; | |
| base->next = new; | |
| base->size = size; | |
| } | |
| base->tag = tag; | |
| mainzone->rover = base->next; | |
| base->id = ZONEID; | |
| *((int32_t *) ((((uint8_t *) base) + base->size) - 4)) = ZONEID; | |
| return (void *) (((uint8_t *) base) + (sizeof(memblock_t))); | |
| } | |
| void Z_Print(memzone_t *zone) | |
| { | |
| memblock_t *block; | |
| Con_Printf("zone size: %i location: %p\n", mainzone->size, mainzone); | |
| for (block = zone->blocklist.next;; block = block->next) | |
| { | |
| Con_Printf("block:%p size:%7i tag:%3i\n", block, block->size, block->tag); | |
| if (block->next == (&zone->blocklist)) | |
| break; | |
| if ((((uint8_t *) block) + block->size) != ((uint8_t *) block->next)) | |
| Con_Printf("ERROR: block size does not touch the next block\n"); | |
| if (block->next->prev != block) | |
| Con_Printf("ERROR: next block doesn't have proper back link\n"); | |
| if ((!block->tag) && (!block->next->tag)) | |
| Con_Printf("ERROR: two consecutive free blocks\n"); | |
| } | |
| } | |
| void Z_CheckHeap(void) | |
| { | |
| memblock_t *block; | |
| for (block = mainzone->blocklist.next;; block = block->next) | |
| { | |
| if (block->next == (&mainzone->blocklist)) | |
| break; | |
| if ((((uint8_t *) block) + block->size) != ((uint8_t *) block->next)) | |
| Sys_Error("Z_CheckHeap: block size does not touch the next block\n"); | |
| if (block->next->prev != block) | |
| Sys_Error("Z_CheckHeap: next block doesn't have proper back link\n"); | |
| if ((!block->tag) && (!block->next->tag)) | |
| Sys_Error("Z_CheckHeap: two consecutive free blocks\n"); | |
| } | |
| } | |
| void Hunk_Check(void) | |
| { | |
| hunk_t *h; | |
| for (h = (hunk_t *) hunk_base; ((uint8_t *) h) != (hunk_base + hunk_low_used);) | |
| { | |
| if (h->sentinal != HUNK_SENTINAL) | |
| Sys_Error("Hunk_Check: trahsed sentinal"); | |
| if ((h->size < 16) || (((h->size + ((uint8_t *) h)) - hunk_base) > hunk_size)) | |
| Sys_Error("Hunk_Check: bad size"); | |
| h = (hunk_t *) (((uint8_t *) h) + h->size); | |
| } | |
| } | |
| void Hunk_Print(bool all) | |
| { | |
| hunk_t *h; | |
| hunk_t *next; | |
| hunk_t *endlow; | |
| hunk_t *starthigh; | |
| hunk_t *endhigh; | |
| int32_t count; | |
| int32_t sum; | |
| int32_t totalblocks; | |
| char name[9]; | |
| name[8] = 0; | |
| count = 0; | |
| sum = 0; | |
| totalblocks = 0; | |
| h = (hunk_t *) hunk_base; | |
| endlow = (hunk_t *) (hunk_base + hunk_low_used); | |
| starthigh = (hunk_t *) ((hunk_base + hunk_size) - hunk_high_used); | |
| endhigh = (hunk_t *) (hunk_base + hunk_size); | |
| Con_Printf(" :%8i total hunk size\n", hunk_size); | |
| Con_Printf("-------------------------\n"); | |
| while (1) | |
| { | |
| if (h == endlow) | |
| { | |
| Con_Printf("-------------------------\n"); | |
| Con_Printf(" :%8i REMAINING\n", (hunk_size - hunk_low_used) - hunk_high_used); | |
| Con_Printf("-------------------------\n"); | |
| h = starthigh; | |
| } | |
| if (h == endhigh) | |
| break; | |
| if (h->sentinal != HUNK_SENTINAL) | |
| Sys_Error("Hunk_Check: trahsed sentinal"); | |
| if ((h->size < 16) || (((h->size + ((uint8_t *) h)) - hunk_base) > hunk_size)) | |
| Sys_Error("Hunk_Check: bad size"); | |
| next = (hunk_t *) (((uint8_t *) h) + h->size); | |
| count++; | |
| totalblocks++; | |
| sum += h->size; | |
| memcpy(name, h->name, 8); | |
| if (all) | |
| Con_Printf("%8p :%8i %8s\n", h, h->size, name); | |
| if (((next == endlow) || (next == endhigh)) || strncmp(h->name, next->name, 8)) | |
| { | |
| if (!all) | |
| Con_Printf(" :%8i %8s (TOTAL)\n", sum, name); | |
| count = 0; | |
| sum = 0; | |
| } | |
| h = next; | |
| } | |
| Con_Printf("-------------------------\n"); | |
| Con_Printf("%8i total blocks\n", totalblocks); | |
| } | |
| void *Hunk_AllocName(int32_t size, char *name) | |
| { | |
| hunk_t *h; | |
| if (size < 0) | |
| Sys_Error("Hunk_Alloc: bad size: %i", size); | |
| size = (sizeof(hunk_t)) + ((size + 15) & (~15)); | |
| if (((hunk_size - hunk_low_used) - hunk_high_used) < size) | |
| Sys_Error("Hunk_Alloc: failed on %i bytes", size); | |
| h = (hunk_t *) (hunk_base + hunk_low_used); | |
| hunk_low_used += size; | |
| Cache_FreeLow(hunk_low_used); | |
| memset(h, 0, size); | |
| h->size = size; | |
| h->sentinal = HUNK_SENTINAL; | |
| strncpy(h->name, name, 8); | |
| return (void *) (h + 1); | |
| } | |
| void *Hunk_Alloc(int32_t size) | |
| { | |
| return Hunk_AllocName(size, "unknown"); | |
| } | |
| int32_t Hunk_LowMark(void) | |
| { | |
| return hunk_low_used; | |
| } | |
| void Hunk_FreeToLowMark(int32_t mark) | |
| { | |
| if ((mark < 0) || (mark > hunk_low_used)) | |
| Sys_Error("Hunk_FreeToLowMark: bad mark %i", mark); | |
| memset(hunk_base + mark, 0, hunk_low_used - mark); | |
| hunk_low_used = mark; | |
| } | |
| int32_t Hunk_HighMark(void) | |
| { | |
| if (hunk_tempactive) | |
| { | |
| hunk_tempactive = 0; | |
| Hunk_FreeToHighMark(hunk_tempmark); | |
| } | |
| return hunk_high_used; | |
| } | |
| void Hunk_FreeToHighMark(int32_t mark) | |
| { | |
| if (hunk_tempactive) | |
| { | |
| hunk_tempactive = 0; | |
| Hunk_FreeToHighMark(hunk_tempmark); | |
| } | |
| if ((mark < 0) || (mark > hunk_high_used)) | |
| Sys_Error("Hunk_FreeToHighMark: bad mark %i", mark); | |
| memset((hunk_base + hunk_size) - hunk_high_used, 0, hunk_high_used - mark); | |
| hunk_high_used = mark; | |
| } | |
| void *Hunk_HighAllocName(int32_t size, char *name) | |
| { | |
| hunk_t *h; | |
| if (size < 0) | |
| Sys_Error("Hunk_HighAllocName: bad size: %i", size); | |
| if (hunk_tempactive) | |
| { | |
| Hunk_FreeToHighMark(hunk_tempmark); | |
| hunk_tempactive = 0; | |
| } | |
| size = (sizeof(hunk_t)) + ((size + 15) & (~15)); | |
| if (((hunk_size - hunk_low_used) - hunk_high_used) < size) | |
| { | |
| Con_Printf("Hunk_HighAlloc: failed on %i bytes\n", size); | |
| return 0; | |
| } | |
| hunk_high_used += size; | |
| Cache_FreeHigh(hunk_high_used); | |
| h = (hunk_t *) ((hunk_base + hunk_size) - hunk_high_used); | |
| memset(h, 0, size); | |
| h->size = size; | |
| h->sentinal = HUNK_SENTINAL; | |
| strncpy(h->name, name, 8); | |
| return (void *) (h + 1); | |
| } | |
| void *Hunk_TempAlloc(int32_t size) | |
| { | |
| void *buf; | |
| size = (size + 15) & (~15); | |
| if (hunk_tempactive) | |
| { | |
| Hunk_FreeToHighMark(hunk_tempmark); | |
| hunk_tempactive = 0; | |
| } | |
| hunk_tempmark = Hunk_HighMark(); | |
| buf = Hunk_HighAllocName(size, "temp"); | |
| hunk_tempactive = 1; | |
| return buf; | |
| } | |
| void Cache_Move(cache_system_t *c) | |
| { | |
| cache_system_t *new; | |
| new = Cache_TryAlloc(c->size, 1); | |
| if (new) | |
| { | |
| memcpy(new + 1, c + 1, c->size - (sizeof(cache_system_t))); | |
| new->user = c->user; | |
| memcpy(new->name, c->name, sizeof(new->name)); | |
| Cache_Free(c->user); | |
| new->user->data = (void *) (new + 1); | |
| } | |
| else | |
| { | |
| Cache_Free(c->user); | |
| } | |
| } | |
| void Cache_FreeLow(int32_t new_low_hunk) | |
| { | |
| cache_system_t *c; | |
| while (1) | |
| { | |
| c = cache_head.next; | |
| if (c == (&cache_head)) | |
| return; | |
| if (((uint8_t *) c) >= (hunk_base + new_low_hunk)) | |
| return; | |
| Cache_Move(c); | |
| } | |
| } | |
| void Cache_FreeHigh(int32_t new_high_hunk) | |
| { | |
| cache_system_t *c; | |
| cache_system_t *prev; | |
| prev = 0; | |
| while (1) | |
| { | |
| c = cache_head.prev; | |
| if (c == (&cache_head)) | |
| return; | |
| if ((((uint8_t *) c) + c->size) <= ((hunk_base + hunk_size) - new_high_hunk)) | |
| return; | |
| if (c == prev) | |
| Cache_Free(c->user); | |
| else | |
| { | |
| Cache_Move(c); | |
| prev = c; | |
| } | |
| } | |
| } | |
| void Cache_UnlinkLRU(cache_system_t *cs) | |
| { | |
| if ((!cs->lru_next) || (!cs->lru_prev)) | |
| Sys_Error("Cache_UnlinkLRU: NULL link"); | |
| cs->lru_next->lru_prev = cs->lru_prev; | |
| cs->lru_prev->lru_next = cs->lru_next; | |
| cs->lru_prev = (cs->lru_next = 0); | |
| } | |
| void Cache_MakeLRU(cache_system_t *cs) | |
| { | |
| if (cs->lru_next || cs->lru_prev) | |
| Sys_Error("Cache_MakeLRU: active link"); | |
| cache_head.lru_next->lru_prev = cs; | |
| cs->lru_next = cache_head.lru_next; | |
| cs->lru_prev = &cache_head; | |
| cache_head.lru_next = cs; | |
| } | |
| cache_system_t *Cache_TryAlloc(int32_t size, bool nobottom) | |
| { | |
| cache_system_t *cs; | |
| cache_system_t *new; | |
| if ((!nobottom) && (cache_head.prev == (&cache_head))) | |
| { | |
| if (((hunk_size - hunk_high_used) - hunk_low_used) < size) | |
| Sys_Error("Cache_TryAlloc: %i is greater then free hunk", size); | |
| new = (cache_system_t *) (hunk_base + hunk_low_used); | |
| memset(new, 0, sizeof(*new)); | |
| new->size = size; | |
| cache_head.prev = (cache_head.next = new); | |
| new->prev = (new->next = &cache_head); | |
| Cache_MakeLRU(new); | |
| return new; | |
| } | |
| new = (cache_system_t *) (hunk_base + hunk_low_used); | |
| cs = cache_head.next; | |
| do | |
| { | |
| if ((!nobottom) || (cs != cache_head.next)) | |
| { | |
| if ((((uint8_t *) cs) - ((uint8_t *) new)) >= size) | |
| { | |
| memset(new, 0, sizeof(*new)); | |
| new->size = size; | |
| new->next = cs; | |
| new->prev = cs->prev; | |
| cs->prev->next = new; | |
| cs->prev = new; | |
| Cache_MakeLRU(new); | |
| return new; | |
| } | |
| } | |
| new = (cache_system_t *) (((uint8_t *) cs) + cs->size); | |
| cs = cs->next; | |
| } | |
| while (cs != (&cache_head)); | |
| if ((((hunk_base + hunk_size) - hunk_high_used) - ((uint8_t *) new)) >= size) | |
| { | |
| memset(new, 0, sizeof(*new)); | |
| new->size = size; | |
| new->next = &cache_head; | |
| new->prev = cache_head.prev; | |
| cache_head.prev->next = new; | |
| cache_head.prev = new; | |
| Cache_MakeLRU(new); | |
| return new; | |
| } | |
| return 0; | |
| } | |
| void Cache_Flush(void) | |
| { | |
| while (cache_head.next != (&cache_head)) | |
| Cache_Free(cache_head.next->user); | |
| } | |
| void Cache_Print(void) | |
| { | |
| cache_system_t *cd; | |
| for (cd = cache_head.next; cd != (&cache_head); cd = cd->next) | |
| { | |
| Con_Printf("%8i : %s\n", cd->size, cd->name); | |
| } | |
| } | |
| void Cache_Report(void) | |
| { | |
| Con_DPrintf("%4.1f megabyte data cache\n", ((hunk_size - hunk_high_used) - hunk_low_used) / ((float) (1024 * 1024))); | |
| } | |
| void Cache_Compact(void) | |
| { | |
| } | |
| void Cache_Init(void) | |
| { | |
| cache_head.next = (cache_head.prev = &cache_head); | |
| cache_head.lru_next = (cache_head.lru_prev = &cache_head); | |
| Cmd_AddCommand("flush", Cache_Flush); | |
| } | |
| void Cache_Free(cache_user_t *c) | |
| { | |
| cache_system_t *cs; | |
| if (!c->data) | |
| Sys_Error("Cache_Free: not allocated"); | |
| cs = ((cache_system_t *) c->data) - 1; | |
| cs->prev->next = cs->next; | |
| cs->next->prev = cs->prev; | |
| cs->next = (cs->prev = 0); | |
| c->data = 0; | |
| Cache_UnlinkLRU(cs); | |
| } | |
| void *Cache_Check(cache_user_t *c) | |
| { | |
| cache_system_t *cs; | |
| if (!c->data) | |
| return 0; | |
| cs = ((cache_system_t *) c->data) - 1; | |
| Cache_UnlinkLRU(cs); | |
| Cache_MakeLRU(cs); | |
| return c->data; | |
| } | |
| void *Cache_Alloc(cache_user_t *c, int32_t size, char *name) | |
| { | |
| cache_system_t *cs; | |
| if (c->data) | |
| Sys_Error("Cache_Alloc: allready allocated"); | |
| if (size <= 0) | |
| Sys_Error("Cache_Alloc: size %i", size); | |
| size = ((size + (sizeof(cache_system_t))) + 15) & (~15); | |
| while (1) | |
| { | |
| cs = Cache_TryAlloc(size, 0); | |
| if (cs) | |
| { | |
| strncpy(cs->name, name, (sizeof(cs->name)) - 1); | |
| c->data = (void *) (cs + 1); | |
| cs->user = c; | |
| break; | |
| } | |
| if (cache_head.lru_prev == (&cache_head)) | |
| Sys_Error("Cache_Alloc: out of memory"); | |
| Cache_Free(cache_head.lru_prev->user); | |
| } | |
| return Cache_Check(c); | |
| } | |
| void Memory_Init(void *buf, int32_t size) | |
| { | |
| int32_t p; | |
| int32_t zonesize = DYNAMIC_SIZE; | |
| hunk_base = buf; | |
| hunk_size = size; | |
| hunk_low_used = 0; | |
| hunk_high_used = 0; | |
| Cache_Init(); | |
| p = COM_CheckParm("-zone"); | |
| if (p) | |
| { | |
| if (p < (com_argc - 1)) | |
| zonesize = ((int32_t) strtol(com_argv[p + 1], 0, 0)) * 1024; | |
| else | |
| Sys_Error("Memory_Init: you must specify a size in KB after -zone"); | |
| } | |
| mainzone = Hunk_AllocName(zonesize, "zone"); | |
| Z_ClearZone(mainzone, zonesize); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment