mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-10 11:59:58 -05:00
Quack
This commit is contained in:
committed by
GitHub
parent
e58d83b4a8
commit
b585e51a81
1058
client/adivtab.h
Normal file
1058
client/adivtab.h
Normal file
File diff suppressed because it is too large
Load Diff
181
client/anorms.h
Normal file
181
client/anorms.h
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
{-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},
|
81
client/asm_i386.h
Normal file
81
client/asm_i386.h
Normal file
@ -0,0 +1,81 @@
|
||||
|
||||
#ifndef __ASM_I386__
|
||||
#define __ASM_I386__
|
||||
|
||||
#ifdef ELF
|
||||
#define C(label) label
|
||||
#else
|
||||
#define C(label) _##label
|
||||
#endif
|
||||
|
||||
//
|
||||
// !!! note that this file must match the corresponding C structures at all
|
||||
// times !!!
|
||||
//
|
||||
|
||||
// plane_t structure
|
||||
// !!! if this is changed, it must be changed in model.h too !!!
|
||||
// !!! if the size of this is changed, the array lookup in SV_HullPointContents
|
||||
// must be changed too !!!
|
||||
#define pl_normal 0
|
||||
#define pl_dist 12
|
||||
#define pl_type 16
|
||||
#define pl_signbits 17
|
||||
#define pl_pad 18
|
||||
#define pl_size 20
|
||||
|
||||
// hull_t structure
|
||||
// !!! if this is changed, it must be changed in model.h too !!!
|
||||
#define hu_clipnodes 0
|
||||
#define hu_planes 4
|
||||
#define hu_firstclipnode 8
|
||||
#define hu_lastclipnode 12
|
||||
#define hu_clip_mins 16
|
||||
#define hu_clip_maxs 28
|
||||
#define hu_size 40
|
||||
|
||||
// dnode_t structure
|
||||
// !!! if this is changed, it must be changed in bspfile.h too !!!
|
||||
#define nd_planenum 0
|
||||
#define nd_children 4
|
||||
#define nd_mins 8
|
||||
#define nd_maxs 20
|
||||
#define nd_firstface 32
|
||||
#define nd_numfaces 36
|
||||
#define nd_size 40
|
||||
|
||||
// sfxcache_t structure
|
||||
// !!! if this is changed, it much be changed in sound.h too !!!
|
||||
#define sfxc_length 0
|
||||
#define sfxc_loopstart 4
|
||||
#define sfxc_speed 8
|
||||
#define sfxc_width 12
|
||||
#define sfxc_stereo 16
|
||||
#define sfxc_data 20
|
||||
|
||||
// channel_t structure
|
||||
// !!! if this is changed, it much be changed in sound.h too !!!
|
||||
#define ch_sfx 0
|
||||
#define ch_leftvol 4
|
||||
#define ch_rightvol 8
|
||||
#define ch_end 12
|
||||
#define ch_pos 16
|
||||
#define ch_looping 20
|
||||
#define ch_entnum 24
|
||||
#define ch_entchannel 28
|
||||
#define ch_origin 32
|
||||
#define ch_dist_mult 44
|
||||
#define ch_master_vol 48
|
||||
#define ch_size 52
|
||||
|
||||
// portable_samplepair_t structure
|
||||
// !!! if this is changed, it much be changed in sound.h too !!!
|
||||
#define psp_left 0
|
||||
#define psp_right 4
|
||||
#define psp_size 8
|
||||
|
||||
// !!! must be kept the same as in d_iface.h !!!
|
||||
#define TRANSPARENT_COLOR 255
|
||||
|
||||
#endif
|
||||
|
123
client/block16.h
Normal file
123
client/block16.h
Normal file
@ -0,0 +1,123 @@
|
||||
LEnter16_16:
|
||||
movb (%esi),%al
|
||||
movb (%esi,%ebx,),%cl
|
||||
movb %dh,%ah
|
||||
addl %ebp,%edx
|
||||
movb %dh,%ch
|
||||
leal (%esi,%ebx,2),%esi
|
||||
movw 0x12345678(,%eax,2),%ax
|
||||
LBPatch0:
|
||||
addl %ebp,%edx
|
||||
movw %ax,(%edi)
|
||||
movw 0x12345678(,%ecx,2),%cx
|
||||
LBPatch1:
|
||||
movw %cx,2(%edi)
|
||||
addl $0x4,%edi
|
||||
|
||||
movb (%esi),%al
|
||||
movb (%esi,%ebx,),%cl
|
||||
movb %dh,%ah
|
||||
addl %ebp,%edx
|
||||
movb %dh,%ch
|
||||
leal (%esi,%ebx,2),%esi
|
||||
movw 0x12345678(,%eax,2),%ax
|
||||
LBPatch2:
|
||||
addl %ebp,%edx
|
||||
movw %ax,(%edi)
|
||||
movw 0x12345678(,%ecx,2),%cx
|
||||
LBPatch3:
|
||||
movw %cx,2(%edi)
|
||||
addl $0x4,%edi
|
||||
|
||||
movb (%esi),%al
|
||||
movb (%esi,%ebx,),%cl
|
||||
movb %dh,%ah
|
||||
addl %ebp,%edx
|
||||
movb %dh,%ch
|
||||
leal (%esi,%ebx,2),%esi
|
||||
movw 0x12345678(,%eax,2),%ax
|
||||
LBPatch4:
|
||||
addl %ebp,%edx
|
||||
movw %ax,(%edi)
|
||||
movw 0x12345678(,%ecx,2),%cx
|
||||
LBPatch5:
|
||||
movw %cx,2(%edi)
|
||||
addl $0x4,%edi
|
||||
|
||||
movb (%esi),%al
|
||||
movb (%esi,%ebx,),%cl
|
||||
movb %dh,%ah
|
||||
addl %ebp,%edx
|
||||
movb %dh,%ch
|
||||
leal (%esi,%ebx,2),%esi
|
||||
movw 0x12345678(,%eax,2),%ax
|
||||
LBPatch6:
|
||||
addl %ebp,%edx
|
||||
movw %ax,(%edi)
|
||||
movw 0x12345678(,%ecx,2),%cx
|
||||
LBPatch7:
|
||||
movw %cx,2(%edi)
|
||||
addl $0x4,%edi
|
||||
|
||||
LEnter8_16:
|
||||
movb (%esi),%al
|
||||
movb (%esi,%ebx,),%cl
|
||||
movb %dh,%ah
|
||||
addl %ebp,%edx
|
||||
movb %dh,%ch
|
||||
leal (%esi,%ebx,2),%esi
|
||||
movw 0x12345678(,%eax,2),%ax
|
||||
LBPatch8:
|
||||
addl %ebp,%edx
|
||||
movw %ax,(%edi)
|
||||
movw 0x12345678(,%ecx,2),%cx
|
||||
LBPatch9:
|
||||
movw %cx,2(%edi)
|
||||
addl $0x4,%edi
|
||||
|
||||
movb (%esi),%al
|
||||
movb (%esi,%ebx,),%cl
|
||||
movb %dh,%ah
|
||||
addl %ebp,%edx
|
||||
movb %dh,%ch
|
||||
leal (%esi,%ebx,2),%esi
|
||||
movw 0x12345678(,%eax,2),%ax
|
||||
LBPatch10:
|
||||
addl %ebp,%edx
|
||||
movw %ax,(%edi)
|
||||
movw 0x12345678(,%ecx,2),%cx
|
||||
LBPatch11:
|
||||
movw %cx,2(%edi)
|
||||
addl $0x4,%edi
|
||||
|
||||
LEnter4_16:
|
||||
movb (%esi),%al
|
||||
movb (%esi,%ebx,),%cl
|
||||
movb %dh,%ah
|
||||
addl %ebp,%edx
|
||||
movb %dh,%ch
|
||||
leal (%esi,%ebx,2),%esi
|
||||
movw 0x12345678(,%eax,2),%ax
|
||||
LBPatch12:
|
||||
addl %ebp,%edx
|
||||
movw %ax,(%edi)
|
||||
movw 0x12345678(,%ecx,2),%cx
|
||||
LBPatch13:
|
||||
movw %cx,2(%edi)
|
||||
addl $0x4,%edi
|
||||
|
||||
LEnter2_16:
|
||||
movb (%esi),%al
|
||||
movb (%esi,%ebx,),%cl
|
||||
movb %dh,%ah
|
||||
addl %ebp,%edx
|
||||
movb %dh,%ch
|
||||
leal (%esi,%ebx,2),%esi
|
||||
movw 0x12345678(,%eax,2),%ax
|
||||
LBPatch14:
|
||||
addl %ebp,%edx
|
||||
movw %ax,(%edi)
|
||||
movw 0x12345678(,%ecx,2),%cx
|
||||
LBPatch15:
|
||||
movw %cx,2(%edi)
|
||||
addl $0x4,%edi
|
124
client/block8.h
Normal file
124
client/block8.h
Normal file
@ -0,0 +1,124 @@
|
||||
LEnter16_8:
|
||||
movb (%esi),%al
|
||||
movb (%esi,%ebx,),%cl
|
||||
movb %dh,%ah
|
||||
addl %ebp,%edx
|
||||
movb %dh,%ch
|
||||
leal (%esi,%ebx,2),%esi
|
||||
movb 0x12345678(%eax),%al
|
||||
LBPatch0:
|
||||
addl %ebp,%edx
|
||||
movb %al,(%edi)
|
||||
movb 0x12345678(%ecx),%cl
|
||||
LBPatch1:
|
||||
movb %cl,1(%edi)
|
||||
addl $0x2,%edi
|
||||
|
||||
movb (%esi),%al
|
||||
movb (%esi,%ebx,),%cl
|
||||
movb %dh,%ah
|
||||
addl %ebp,%edx
|
||||
movb %dh,%ch
|
||||
leal (%esi,%ebx,2),%esi
|
||||
movb 0x12345678(%eax),%al
|
||||
LBPatch2:
|
||||
addl %ebp,%edx
|
||||
movb %al,(%edi)
|
||||
movb 0x12345678(%ecx),%cl
|
||||
LBPatch3:
|
||||
movb %cl,1(%edi)
|
||||
addl $0x2,%edi
|
||||
|
||||
movb (%esi),%al
|
||||
movb (%esi,%ebx,),%cl
|
||||
movb %dh,%ah
|
||||
addl %ebp,%edx
|
||||
movb %dh,%ch
|
||||
leal (%esi,%ebx,2),%esi
|
||||
movb 0x12345678(%eax),%al
|
||||
LBPatch4:
|
||||
addl %ebp,%edx
|
||||
movb %al,(%edi)
|
||||
movb 0x12345678(%ecx),%cl
|
||||
LBPatch5:
|
||||
movb %cl,1(%edi)
|
||||
addl $0x2,%edi
|
||||
|
||||
movb (%esi),%al
|
||||
movb (%esi,%ebx,),%cl
|
||||
movb %dh,%ah
|
||||
addl %ebp,%edx
|
||||
movb %dh,%ch
|
||||
leal (%esi,%ebx,2),%esi
|
||||
movb 0x12345678(%eax),%al
|
||||
LBPatch6:
|
||||
addl %ebp,%edx
|
||||
movb %al,(%edi)
|
||||
movb 0x12345678(%ecx),%cl
|
||||
LBPatch7:
|
||||
movb %cl,1(%edi)
|
||||
addl $0x2,%edi
|
||||
|
||||
LEnter8_8:
|
||||
movb (%esi),%al
|
||||
movb (%esi,%ebx,),%cl
|
||||
movb %dh,%ah
|
||||
addl %ebp,%edx
|
||||
movb %dh,%ch
|
||||
leal (%esi,%ebx,2),%esi
|
||||
movb 0x12345678(%eax),%al
|
||||
LBPatch8:
|
||||
addl %ebp,%edx
|
||||
movb %al,(%edi)
|
||||
movb 0x12345678(%ecx),%cl
|
||||
LBPatch9:
|
||||
movb %cl,1(%edi)
|
||||
addl $0x2,%edi
|
||||
|
||||
movb (%esi),%al
|
||||
movb (%esi,%ebx,),%cl
|
||||
movb %dh,%ah
|
||||
addl %ebp,%edx
|
||||
movb %dh,%ch
|
||||
leal (%esi,%ebx,2),%esi
|
||||
movb 0x12345678(%eax),%al
|
||||
LBPatch10:
|
||||
addl %ebp,%edx
|
||||
movb %al,(%edi)
|
||||
movb 0x12345678(%ecx),%cl
|
||||
LBPatch11:
|
||||
movb %cl,1(%edi)
|
||||
addl $0x2,%edi
|
||||
|
||||
LEnter4_8:
|
||||
movb (%esi),%al
|
||||
movb (%esi,%ebx,),%cl
|
||||
movb %dh,%ah
|
||||
addl %ebp,%edx
|
||||
movb %dh,%ch
|
||||
leal (%esi,%ebx,2),%esi
|
||||
movb 0x12345678(%eax),%al
|
||||
LBPatch12:
|
||||
addl %ebp,%edx
|
||||
movb %al,(%edi)
|
||||
movb 0x12345678(%ecx),%cl
|
||||
LBPatch13:
|
||||
movb %cl,1(%edi)
|
||||
addl $0x2,%edi
|
||||
|
||||
LEnter2_8:
|
||||
movb (%esi),%al
|
||||
movb (%esi,%ebx,),%cl
|
||||
movb %dh,%ah
|
||||
addl %ebp,%edx
|
||||
movb %dh,%ch
|
||||
leal (%esi,%ebx,2),%esi
|
||||
movb 0x12345678(%eax),%al
|
||||
LBPatch14:
|
||||
addl %ebp,%edx
|
||||
movb %al,(%edi)
|
||||
movb 0x12345678(%ecx),%cl
|
||||
LBPatch15:
|
||||
movb %cl,1(%edi)
|
||||
addl $0x2,%edi
|
||||
|
26
client/cdaudio.h
Normal file
26
client/cdaudio.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
int CDAudio_Init(void);
|
||||
void CDAudio_Shutdown(void);
|
||||
void CDAudio_Play(int track, qboolean looping);
|
||||
void CDAudio_Stop(void);
|
||||
void CDAudio_Update(void);
|
||||
void CDAudio_Activate (qboolean active);
|
650
client/cl_cin.c
Normal file
650
client/cl_cin.c
Normal file
@ -0,0 +1,650 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
#include "client.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte *data;
|
||||
int count;
|
||||
} cblock_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
qboolean restart_sound;
|
||||
int s_rate;
|
||||
int s_width;
|
||||
int s_channels;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
byte *pic;
|
||||
byte *pic_pending;
|
||||
|
||||
// order 1 huffman stuff
|
||||
int *hnodes1; // [256][256][2];
|
||||
int numhnodes1[256];
|
||||
|
||||
int h_used[512];
|
||||
int h_count[512];
|
||||
} cinematics_t;
|
||||
|
||||
cinematics_t cin;
|
||||
|
||||
/*
|
||||
=================================================================
|
||||
|
||||
PCX LOADING
|
||||
|
||||
=================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
SCR_LoadPCX
|
||||
==============
|
||||
*/
|
||||
void SCR_LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
|
||||
{
|
||||
byte *raw;
|
||||
pcx_t *pcx;
|
||||
int x, y;
|
||||
int len;
|
||||
int dataByte, runLength;
|
||||
byte *out, *pix;
|
||||
|
||||
*pic = NULL;
|
||||
|
||||
//
|
||||
// load the file
|
||||
//
|
||||
len = FS_LoadFile (filename, (void **)&raw);
|
||||
if (!raw)
|
||||
return; // Com_Printf ("Bad pcx file %s\n", filename);
|
||||
|
||||
//
|
||||
// parse the PCX file
|
||||
//
|
||||
pcx = (pcx_t *)raw;
|
||||
raw = &pcx->data;
|
||||
|
||||
if (pcx->manufacturer != 0x0a
|
||||
|| pcx->version != 5
|
||||
|| pcx->encoding != 1
|
||||
|| pcx->bits_per_pixel != 8
|
||||
|| pcx->xmax >= 640
|
||||
|| pcx->ymax >= 480)
|
||||
{
|
||||
Com_Printf ("Bad pcx file %s\n", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
out = Z_Malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
|
||||
|
||||
*pic = out;
|
||||
|
||||
pix = out;
|
||||
|
||||
if (palette)
|
||||
{
|
||||
*palette = Z_Malloc(768);
|
||||
memcpy (*palette, (byte *)pcx + len - 768, 768);
|
||||
}
|
||||
|
||||
if (width)
|
||||
*width = pcx->xmax+1;
|
||||
if (height)
|
||||
*height = pcx->ymax+1;
|
||||
|
||||
for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
|
||||
{
|
||||
for (x=0 ; x<=pcx->xmax ; )
|
||||
{
|
||||
dataByte = *raw++;
|
||||
|
||||
if((dataByte & 0xC0) == 0xC0)
|
||||
{
|
||||
runLength = dataByte & 0x3F;
|
||||
dataByte = *raw++;
|
||||
}
|
||||
else
|
||||
runLength = 1;
|
||||
|
||||
while(runLength-- > 0)
|
||||
pix[x++] = dataByte;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( raw - (byte *)pcx > len)
|
||||
{
|
||||
Com_Printf ("PCX file %s was malformed", filename);
|
||||
Z_Free (*pic);
|
||||
*pic = NULL;
|
||||
}
|
||||
|
||||
FS_FreeFile (pcx);
|
||||
}
|
||||
|
||||
//=============================================================
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_StopCinematic
|
||||
==================
|
||||
*/
|
||||
void SCR_StopCinematic (void)
|
||||
{
|
||||
cl.cinematictime = 0; // done
|
||||
if (cin.pic)
|
||||
{
|
||||
Z_Free (cin.pic);
|
||||
cin.pic = NULL;
|
||||
}
|
||||
if (cin.pic_pending)
|
||||
{
|
||||
Z_Free (cin.pic_pending);
|
||||
cin.pic_pending = NULL;
|
||||
}
|
||||
if (cl.cinematicpalette_active)
|
||||
{
|
||||
re.CinematicSetPalette(NULL);
|
||||
cl.cinematicpalette_active = false;
|
||||
}
|
||||
if (cl.cinematic_file)
|
||||
{
|
||||
fclose (cl.cinematic_file);
|
||||
cl.cinematic_file = NULL;
|
||||
}
|
||||
if (cin.hnodes1)
|
||||
{
|
||||
Z_Free (cin.hnodes1);
|
||||
cin.hnodes1 = NULL;
|
||||
}
|
||||
|
||||
// switch back down to 11 khz sound if necessary
|
||||
if (cin.restart_sound)
|
||||
{
|
||||
cin.restart_sound = false;
|
||||
CL_Snd_Restart_f ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
SCR_FinishCinematic
|
||||
|
||||
Called when either the cinematic completes, or it is aborted
|
||||
====================
|
||||
*/
|
||||
void SCR_FinishCinematic (void)
|
||||
{
|
||||
// tell the server to advance to the next map / cinematic
|
||||
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
|
||||
SZ_Print (&cls.netchan.message, va("nextserver %i\n", cl.servercount));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
||||
/*
|
||||
==================
|
||||
SmallestNode1
|
||||
==================
|
||||
*/
|
||||
int SmallestNode1 (int numhnodes)
|
||||
{
|
||||
int i;
|
||||
int best, bestnode;
|
||||
|
||||
best = 99999999;
|
||||
bestnode = -1;
|
||||
for (i=0 ; i<numhnodes ; i++)
|
||||
{
|
||||
if (cin.h_used[i])
|
||||
continue;
|
||||
if (!cin.h_count[i])
|
||||
continue;
|
||||
if (cin.h_count[i] < best)
|
||||
{
|
||||
best = cin.h_count[i];
|
||||
bestnode = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestnode == -1)
|
||||
return -1;
|
||||
|
||||
cin.h_used[bestnode] = true;
|
||||
return bestnode;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
Huff1TableInit
|
||||
|
||||
Reads the 64k counts table and initializes the node trees
|
||||
==================
|
||||
*/
|
||||
void Huff1TableInit (void)
|
||||
{
|
||||
int prev;
|
||||
int j;
|
||||
int *node, *nodebase;
|
||||
byte counts[256];
|
||||
int numhnodes;
|
||||
|
||||
cin.hnodes1 = Z_Malloc (256*256*2*4);
|
||||
memset (cin.hnodes1, 0, 256*256*2*4);
|
||||
|
||||
for (prev=0 ; prev<256 ; prev++)
|
||||
{
|
||||
memset (cin.h_count,0,sizeof(cin.h_count));
|
||||
memset (cin.h_used,0,sizeof(cin.h_used));
|
||||
|
||||
// read a row of counts
|
||||
FS_Read (counts, sizeof(counts), cl.cinematic_file);
|
||||
for (j=0 ; j<256 ; j++)
|
||||
cin.h_count[j] = counts[j];
|
||||
|
||||
// build the nodes
|
||||
numhnodes = 256;
|
||||
nodebase = cin.hnodes1 + prev*256*2;
|
||||
|
||||
while (numhnodes != 511)
|
||||
{
|
||||
node = nodebase + (numhnodes-256)*2;
|
||||
|
||||
// pick two lowest counts
|
||||
node[0] = SmallestNode1 (numhnodes);
|
||||
if (node[0] == -1)
|
||||
break; // no more
|
||||
|
||||
node[1] = SmallestNode1 (numhnodes);
|
||||
if (node[1] == -1)
|
||||
break;
|
||||
|
||||
cin.h_count[numhnodes] = cin.h_count[node[0]] + cin.h_count[node[1]];
|
||||
numhnodes++;
|
||||
}
|
||||
|
||||
cin.numhnodes1[prev] = numhnodes-1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
Huff1Decompress
|
||||
==================
|
||||
*/
|
||||
cblock_t Huff1Decompress (cblock_t in)
|
||||
{
|
||||
byte *input;
|
||||
byte *out_p;
|
||||
int nodenum;
|
||||
int count;
|
||||
cblock_t out;
|
||||
int inbyte;
|
||||
int *hnodes, *hnodesbase;
|
||||
//int i;
|
||||
|
||||
// get decompressed count
|
||||
count = in.data[0] + (in.data[1]<<8) + (in.data[2]<<16) + (in.data[3]<<24);
|
||||
input = in.data + 4;
|
||||
out_p = out.data = Z_Malloc (count);
|
||||
|
||||
// read bits
|
||||
|
||||
hnodesbase = cin.hnodes1 - 256*2; // nodes 0-255 aren't stored
|
||||
|
||||
hnodes = hnodesbase;
|
||||
nodenum = cin.numhnodes1[0];
|
||||
while (count)
|
||||
{
|
||||
inbyte = *input++;
|
||||
//-----------
|
||||
if (nodenum < 256)
|
||||
{
|
||||
hnodes = hnodesbase + (nodenum<<9);
|
||||
*out_p++ = nodenum;
|
||||
if (!--count)
|
||||
break;
|
||||
nodenum = cin.numhnodes1[nodenum];
|
||||
}
|
||||
nodenum = hnodes[nodenum*2 + (inbyte&1)];
|
||||
inbyte >>=1;
|
||||
//-----------
|
||||
if (nodenum < 256)
|
||||
{
|
||||
hnodes = hnodesbase + (nodenum<<9);
|
||||
*out_p++ = nodenum;
|
||||
if (!--count)
|
||||
break;
|
||||
nodenum = cin.numhnodes1[nodenum];
|
||||
}
|
||||
nodenum = hnodes[nodenum*2 + (inbyte&1)];
|
||||
inbyte >>=1;
|
||||
//-----------
|
||||
if (nodenum < 256)
|
||||
{
|
||||
hnodes = hnodesbase + (nodenum<<9);
|
||||
*out_p++ = nodenum;
|
||||
if (!--count)
|
||||
break;
|
||||
nodenum = cin.numhnodes1[nodenum];
|
||||
}
|
||||
nodenum = hnodes[nodenum*2 + (inbyte&1)];
|
||||
inbyte >>=1;
|
||||
//-----------
|
||||
if (nodenum < 256)
|
||||
{
|
||||
hnodes = hnodesbase + (nodenum<<9);
|
||||
*out_p++ = nodenum;
|
||||
if (!--count)
|
||||
break;
|
||||
nodenum = cin.numhnodes1[nodenum];
|
||||
}
|
||||
nodenum = hnodes[nodenum*2 + (inbyte&1)];
|
||||
inbyte >>=1;
|
||||
//-----------
|
||||
if (nodenum < 256)
|
||||
{
|
||||
hnodes = hnodesbase + (nodenum<<9);
|
||||
*out_p++ = nodenum;
|
||||
if (!--count)
|
||||
break;
|
||||
nodenum = cin.numhnodes1[nodenum];
|
||||
}
|
||||
nodenum = hnodes[nodenum*2 + (inbyte&1)];
|
||||
inbyte >>=1;
|
||||
//-----------
|
||||
if (nodenum < 256)
|
||||
{
|
||||
hnodes = hnodesbase + (nodenum<<9);
|
||||
*out_p++ = nodenum;
|
||||
if (!--count)
|
||||
break;
|
||||
nodenum = cin.numhnodes1[nodenum];
|
||||
}
|
||||
nodenum = hnodes[nodenum*2 + (inbyte&1)];
|
||||
inbyte >>=1;
|
||||
//-----------
|
||||
if (nodenum < 256)
|
||||
{
|
||||
hnodes = hnodesbase + (nodenum<<9);
|
||||
*out_p++ = nodenum;
|
||||
if (!--count)
|
||||
break;
|
||||
nodenum = cin.numhnodes1[nodenum];
|
||||
}
|
||||
nodenum = hnodes[nodenum*2 + (inbyte&1)];
|
||||
inbyte >>=1;
|
||||
//-----------
|
||||
if (nodenum < 256)
|
||||
{
|
||||
hnodes = hnodesbase + (nodenum<<9);
|
||||
*out_p++ = nodenum;
|
||||
if (!--count)
|
||||
break;
|
||||
nodenum = cin.numhnodes1[nodenum];
|
||||
}
|
||||
nodenum = hnodes[nodenum*2 + (inbyte&1)];
|
||||
inbyte >>=1;
|
||||
}
|
||||
|
||||
if (input - in.data != in.count && input - in.data != in.count+1)
|
||||
{
|
||||
Com_Printf ("Decompression overread by %i", (input - in.data) - in.count);
|
||||
}
|
||||
out.count = out_p - out.data;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_ReadNextFrame
|
||||
==================
|
||||
*/
|
||||
byte *SCR_ReadNextFrame (void)
|
||||
{
|
||||
int r;
|
||||
int command;
|
||||
byte samples[22050/14*4];
|
||||
byte compressed[0x20000];
|
||||
int size;
|
||||
byte *pic;
|
||||
cblock_t in, huf1;
|
||||
int start, end, count;
|
||||
|
||||
// read the next frame
|
||||
r = fread (&command, 4, 1, cl.cinematic_file);
|
||||
if (r == 0) // we'll give it one more chance
|
||||
r = fread (&command, 4, 1, cl.cinematic_file);
|
||||
|
||||
if (r != 1)
|
||||
return NULL;
|
||||
command = LittleLong(command);
|
||||
if (command == 2)
|
||||
return NULL; // last frame marker
|
||||
|
||||
if (command == 1)
|
||||
{ // read palette
|
||||
FS_Read (cl.cinematicpalette, sizeof(cl.cinematicpalette), cl.cinematic_file);
|
||||
cl.cinematicpalette_active=0; // dubious.... exposes an edge case
|
||||
}
|
||||
|
||||
// decompress the next frame
|
||||
FS_Read (&size, 4, cl.cinematic_file);
|
||||
size = LittleLong(size);
|
||||
if (size > sizeof(compressed) || size < 1)
|
||||
Com_Error (ERR_DROP, "Bad compressed frame size");
|
||||
FS_Read (compressed, size, cl.cinematic_file);
|
||||
|
||||
// read sound
|
||||
start = cl.cinematicframe*cin.s_rate/14;
|
||||
end = (cl.cinematicframe+1)*cin.s_rate/14;
|
||||
count = end - start;
|
||||
|
||||
FS_Read (samples, count*cin.s_width*cin.s_channels, cl.cinematic_file);
|
||||
|
||||
S_RawSamples (count, cin.s_rate, cin.s_width, cin.s_channels, samples);
|
||||
|
||||
in.data = compressed;
|
||||
in.count = size;
|
||||
|
||||
huf1 = Huff1Decompress (in);
|
||||
|
||||
pic = huf1.data;
|
||||
|
||||
cl.cinematicframe++;
|
||||
|
||||
return pic;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_RunCinematic
|
||||
|
||||
==================
|
||||
*/
|
||||
void SCR_RunCinematic (void)
|
||||
{
|
||||
int frame;
|
||||
|
||||
if (cl.cinematictime <= 0)
|
||||
{
|
||||
SCR_StopCinematic ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (cl.cinematicframe == -1)
|
||||
return; // static image
|
||||
|
||||
if (cls.key_dest != key_game)
|
||||
{ // pause if menu or console is up
|
||||
cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14;
|
||||
return;
|
||||
}
|
||||
|
||||
frame = (cls.realtime - cl.cinematictime)*14.0/1000;
|
||||
if (frame <= cl.cinematicframe)
|
||||
return;
|
||||
if (frame > cl.cinematicframe+1)
|
||||
{
|
||||
Com_Printf ("Dropped frame: %i > %i\n", frame, cl.cinematicframe+1);
|
||||
cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14;
|
||||
}
|
||||
if (cin.pic)
|
||||
Z_Free (cin.pic);
|
||||
cin.pic = cin.pic_pending;
|
||||
cin.pic_pending = NULL;
|
||||
cin.pic_pending = SCR_ReadNextFrame ();
|
||||
if (!cin.pic_pending)
|
||||
{
|
||||
SCR_StopCinematic ();
|
||||
SCR_FinishCinematic ();
|
||||
cl.cinematictime = 1; // hack to get the black screen behind loading
|
||||
SCR_BeginLoadingPlaque ();
|
||||
cl.cinematictime = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_DrawCinematic
|
||||
|
||||
Returns true if a cinematic is active, meaning the view rendering
|
||||
should be skipped
|
||||
==================
|
||||
*/
|
||||
qboolean SCR_DrawCinematic (void)
|
||||
{
|
||||
if (cl.cinematictime <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cls.key_dest == key_menu)
|
||||
{ // blank screen and pause if menu is up
|
||||
re.CinematicSetPalette(NULL);
|
||||
cl.cinematicpalette_active = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!cl.cinematicpalette_active)
|
||||
{
|
||||
re.CinematicSetPalette(cl.cinematicpalette);
|
||||
cl.cinematicpalette_active = true;
|
||||
}
|
||||
|
||||
if (!cin.pic)
|
||||
return true;
|
||||
|
||||
re.DrawStretchRaw (0, 0, viddef.width, viddef.height,
|
||||
cin.width, cin.height, cin.pic);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_PlayCinematic
|
||||
|
||||
==================
|
||||
*/
|
||||
void SCR_PlayCinematic (char *arg)
|
||||
{
|
||||
int width, height;
|
||||
byte *palette;
|
||||
char name[MAX_OSPATH], *dot;
|
||||
int old_khz;
|
||||
|
||||
// make sure CD isn't playing music
|
||||
CDAudio_Stop();
|
||||
|
||||
cl.cinematicframe = 0;
|
||||
dot = strstr (arg, ".");
|
||||
if (dot && !strcmp (dot, ".pcx"))
|
||||
{ // static pcx image
|
||||
Com_sprintf (name, sizeof(name), "pics/%s", arg);
|
||||
SCR_LoadPCX (name, &cin.pic, &palette, &cin.width, &cin.height);
|
||||
cl.cinematicframe = -1;
|
||||
cl.cinematictime = 1;
|
||||
SCR_EndLoadingPlaque ();
|
||||
cls.state = ca_active;
|
||||
if (!cin.pic)
|
||||
{
|
||||
Com_Printf ("%s not found.\n", name);
|
||||
cl.cinematictime = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy (cl.cinematicpalette, palette, sizeof(cl.cinematicpalette));
|
||||
Z_Free (palette);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Com_sprintf (name, sizeof(name), "video/%s", arg);
|
||||
FS_FOpenFile (name, &cl.cinematic_file);
|
||||
if (!cl.cinematic_file)
|
||||
{
|
||||
// Com_Error (ERR_DROP, "Cinematic %s not found.\n", name);
|
||||
SCR_FinishCinematic ();
|
||||
cl.cinematictime = 0; // done
|
||||
return;
|
||||
}
|
||||
|
||||
SCR_EndLoadingPlaque ();
|
||||
|
||||
cls.state = ca_active;
|
||||
|
||||
FS_Read (&width, 4, cl.cinematic_file);
|
||||
FS_Read (&height, 4, cl.cinematic_file);
|
||||
cin.width = LittleLong(width);
|
||||
cin.height = LittleLong(height);
|
||||
|
||||
FS_Read (&cin.s_rate, 4, cl.cinematic_file);
|
||||
cin.s_rate = LittleLong(cin.s_rate);
|
||||
FS_Read (&cin.s_width, 4, cl.cinematic_file);
|
||||
cin.s_width = LittleLong(cin.s_width);
|
||||
FS_Read (&cin.s_channels, 4, cl.cinematic_file);
|
||||
cin.s_channels = LittleLong(cin.s_channels);
|
||||
|
||||
Huff1TableInit ();
|
||||
|
||||
// switch up to 22 khz sound if necessary
|
||||
old_khz = Cvar_VariableValue ("s_khz");
|
||||
if (old_khz != cin.s_rate/1000)
|
||||
{
|
||||
cin.restart_sound = true;
|
||||
Cvar_SetValue ("s_khz", cin.s_rate/1000);
|
||||
CL_Snd_Restart_f ();
|
||||
Cvar_SetValue ("s_khz", old_khz);
|
||||
}
|
||||
|
||||
cl.cinematicframe = 0;
|
||||
cin.pic = SCR_ReadNextFrame ();
|
||||
cl.cinematictime = Sys_Milliseconds ();
|
||||
}
|
1500
client/cl_ents.c
Normal file
1500
client/cl_ents.c
Normal file
File diff suppressed because it is too large
Load Diff
2298
client/cl_fx.c
Normal file
2298
client/cl_fx.c
Normal file
File diff suppressed because it is too large
Load Diff
542
client/cl_input.c
Normal file
542
client/cl_input.c
Normal file
@ -0,0 +1,542 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// cl.input.c -- builds an intended movement command to send to the server
|
||||
|
||||
#include "client.h"
|
||||
|
||||
cvar_t *cl_nodelta;
|
||||
|
||||
extern unsigned sys_frame_time;
|
||||
unsigned frame_msec;
|
||||
unsigned old_sys_frame_time;
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
KEY BUTTONS
|
||||
|
||||
Continuous button event tracking is complicated by the fact that two different
|
||||
input sources (say, mouse button 1 and the control key) can both press the
|
||||
same button, but the button should only be released when both of the
|
||||
pressing key have been released.
|
||||
|
||||
When a key event issues a button command (+forward, +attack, etc), it appends
|
||||
its key number as a parameter to the command so it can be matched up with
|
||||
the release.
|
||||
|
||||
state bit 0 is the current state of the key
|
||||
state bit 1 is edge triggered on the up to down transition
|
||||
state bit 2 is edge triggered on the down to up transition
|
||||
|
||||
|
||||
Key_Event (int key, qboolean down, unsigned time);
|
||||
|
||||
+mlook src time
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
|
||||
kbutton_t in_klook;
|
||||
kbutton_t in_left, in_right, in_forward, in_back;
|
||||
kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright;
|
||||
kbutton_t in_strafe, in_speed, in_use, in_attack;
|
||||
kbutton_t in_up, in_down;
|
||||
|
||||
int in_impulse;
|
||||
|
||||
|
||||
void KeyDown (kbutton_t *b)
|
||||
{
|
||||
int k;
|
||||
char *c;
|
||||
|
||||
c = Cmd_Argv(1);
|
||||
if (c[0])
|
||||
k = atoi(c);
|
||||
else
|
||||
k = -1; // typed manually at the console for continuous down
|
||||
|
||||
if (k == b->down[0] || k == b->down[1])
|
||||
return; // repeating key
|
||||
|
||||
if (!b->down[0])
|
||||
b->down[0] = k;
|
||||
else if (!b->down[1])
|
||||
b->down[1] = k;
|
||||
else
|
||||
{
|
||||
Com_Printf ("Three keys down for a button!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (b->state & 1)
|
||||
return; // still down
|
||||
|
||||
// save timestamp
|
||||
c = Cmd_Argv(2);
|
||||
b->downtime = atoi(c);
|
||||
if (!b->downtime)
|
||||
b->downtime = sys_frame_time - 100;
|
||||
|
||||
b->state |= 1 + 2; // down + impulse down
|
||||
}
|
||||
|
||||
void KeyUp (kbutton_t *b)
|
||||
{
|
||||
int k;
|
||||
char *c;
|
||||
unsigned uptime;
|
||||
|
||||
c = Cmd_Argv(1);
|
||||
if (c[0])
|
||||
k = atoi(c);
|
||||
else
|
||||
{ // typed manually at the console, assume for unsticking, so clear all
|
||||
b->down[0] = b->down[1] = 0;
|
||||
b->state = 4; // impulse up
|
||||
return;
|
||||
}
|
||||
|
||||
if (b->down[0] == k)
|
||||
b->down[0] = 0;
|
||||
else if (b->down[1] == k)
|
||||
b->down[1] = 0;
|
||||
else
|
||||
return; // key up without coresponding down (menu pass through)
|
||||
if (b->down[0] || b->down[1])
|
||||
return; // some other key is still holding it down
|
||||
|
||||
if (!(b->state & 1))
|
||||
return; // still up (this should not happen)
|
||||
|
||||
// save timestamp
|
||||
c = Cmd_Argv(2);
|
||||
uptime = atoi(c);
|
||||
if (uptime)
|
||||
b->msec += uptime - b->downtime;
|
||||
else
|
||||
b->msec += 10;
|
||||
|
||||
b->state &= ~1; // now up
|
||||
b->state |= 4; // impulse up
|
||||
}
|
||||
|
||||
void IN_KLookDown (void) {KeyDown(&in_klook);}
|
||||
void IN_KLookUp (void) {KeyUp(&in_klook);}
|
||||
void IN_UpDown(void) {KeyDown(&in_up);}
|
||||
void IN_UpUp(void) {KeyUp(&in_up);}
|
||||
void IN_DownDown(void) {KeyDown(&in_down);}
|
||||
void IN_DownUp(void) {KeyUp(&in_down);}
|
||||
void IN_LeftDown(void) {KeyDown(&in_left);}
|
||||
void IN_LeftUp(void) {KeyUp(&in_left);}
|
||||
void IN_RightDown(void) {KeyDown(&in_right);}
|
||||
void IN_RightUp(void) {KeyUp(&in_right);}
|
||||
void IN_ForwardDown(void) {KeyDown(&in_forward);}
|
||||
void IN_ForwardUp(void) {KeyUp(&in_forward);}
|
||||
void IN_BackDown(void) {KeyDown(&in_back);}
|
||||
void IN_BackUp(void) {KeyUp(&in_back);}
|
||||
void IN_LookupDown(void) {KeyDown(&in_lookup);}
|
||||
void IN_LookupUp(void) {KeyUp(&in_lookup);}
|
||||
void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
|
||||
void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
|
||||
void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
|
||||
void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
|
||||
void IN_MoverightDown(void) {KeyDown(&in_moveright);}
|
||||
void IN_MoverightUp(void) {KeyUp(&in_moveright);}
|
||||
|
||||
void IN_SpeedDown(void) {KeyDown(&in_speed);}
|
||||
void IN_SpeedUp(void) {KeyUp(&in_speed);}
|
||||
void IN_StrafeDown(void) {KeyDown(&in_strafe);}
|
||||
void IN_StrafeUp(void) {KeyUp(&in_strafe);}
|
||||
|
||||
void IN_AttackDown(void) {KeyDown(&in_attack);}
|
||||
void IN_AttackUp(void) {KeyUp(&in_attack);}
|
||||
|
||||
void IN_UseDown (void) {KeyDown(&in_use);}
|
||||
void IN_UseUp (void) {KeyUp(&in_use);}
|
||||
|
||||
void IN_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));}
|
||||
|
||||
/*
|
||||
===============
|
||||
CL_KeyState
|
||||
|
||||
Returns the fraction of the frame that the key was down
|
||||
===============
|
||||
*/
|
||||
float CL_KeyState (kbutton_t *key)
|
||||
{
|
||||
float val;
|
||||
int msec;
|
||||
|
||||
key->state &= 1; // clear impulses
|
||||
|
||||
msec = key->msec;
|
||||
key->msec = 0;
|
||||
|
||||
if (key->state)
|
||||
{ // still down
|
||||
msec += sys_frame_time - key->downtime;
|
||||
key->downtime = sys_frame_time;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (msec)
|
||||
{
|
||||
Com_Printf ("%i ", msec);
|
||||
}
|
||||
#endif
|
||||
|
||||
val = (float)msec / frame_msec;
|
||||
if (val < 0)
|
||||
val = 0;
|
||||
if (val > 1)
|
||||
val = 1;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
|
||||
cvar_t *cl_upspeed;
|
||||
cvar_t *cl_forwardspeed;
|
||||
cvar_t *cl_sidespeed;
|
||||
|
||||
cvar_t *cl_yawspeed;
|
||||
cvar_t *cl_pitchspeed;
|
||||
|
||||
cvar_t *cl_run;
|
||||
|
||||
cvar_t *cl_anglespeedkey;
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CL_AdjustAngles
|
||||
|
||||
Moves the local angle positions
|
||||
================
|
||||
*/
|
||||
void CL_AdjustAngles (void)
|
||||
{
|
||||
float speed;
|
||||
float up, down;
|
||||
|
||||
if (in_speed.state & 1)
|
||||
speed = cls.frametime * cl_anglespeedkey->value;
|
||||
else
|
||||
speed = cls.frametime;
|
||||
|
||||
if (!(in_strafe.state & 1))
|
||||
{
|
||||
cl.viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right);
|
||||
cl.viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left);
|
||||
}
|
||||
if (in_klook.state & 1)
|
||||
{
|
||||
cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_forward);
|
||||
cl.viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_back);
|
||||
}
|
||||
|
||||
up = CL_KeyState (&in_lookup);
|
||||
down = CL_KeyState(&in_lookdown);
|
||||
|
||||
cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * up;
|
||||
cl.viewangles[PITCH] += speed*cl_pitchspeed->value * down;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CL_BaseMove
|
||||
|
||||
Send the intended movement message to the server
|
||||
================
|
||||
*/
|
||||
void CL_BaseMove (usercmd_t *cmd)
|
||||
{
|
||||
CL_AdjustAngles ();
|
||||
|
||||
memset (cmd, 0, sizeof(*cmd));
|
||||
|
||||
VectorCopy (cl.viewangles, cmd->angles);
|
||||
if (in_strafe.state & 1)
|
||||
{
|
||||
cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_right);
|
||||
cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_left);
|
||||
}
|
||||
|
||||
cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_moveright);
|
||||
cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_moveleft);
|
||||
|
||||
cmd->upmove += cl_upspeed->value * CL_KeyState (&in_up);
|
||||
cmd->upmove -= cl_upspeed->value * CL_KeyState (&in_down);
|
||||
|
||||
if (! (in_klook.state & 1) )
|
||||
{
|
||||
cmd->forwardmove += cl_forwardspeed->value * CL_KeyState (&in_forward);
|
||||
cmd->forwardmove -= cl_forwardspeed->value * CL_KeyState (&in_back);
|
||||
}
|
||||
|
||||
//
|
||||
// adjust for speed key / running
|
||||
//
|
||||
if ( (in_speed.state & 1) ^ (int)(cl_run->value) )
|
||||
{
|
||||
cmd->forwardmove *= 2;
|
||||
cmd->sidemove *= 2;
|
||||
cmd->upmove *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
void CL_ClampPitch (void)
|
||||
{
|
||||
float pitch;
|
||||
|
||||
pitch = SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]);
|
||||
if (pitch > 180)
|
||||
pitch -= 360;
|
||||
if (cl.viewangles[PITCH] + pitch > 89)
|
||||
cl.viewangles[PITCH] = 89 - pitch;
|
||||
if (cl.viewangles[PITCH] + pitch < -89)
|
||||
cl.viewangles[PITCH] = -89 - pitch;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
CL_FinishMove
|
||||
==============
|
||||
*/
|
||||
void CL_FinishMove (usercmd_t *cmd)
|
||||
{
|
||||
int ms;
|
||||
int i;
|
||||
|
||||
//
|
||||
// figure button bits
|
||||
//
|
||||
if ( in_attack.state & 3 )
|
||||
cmd->buttons |= BUTTON_ATTACK;
|
||||
in_attack.state &= ~2;
|
||||
|
||||
if (in_use.state & 3)
|
||||
cmd->buttons |= BUTTON_USE;
|
||||
in_use.state &= ~2;
|
||||
|
||||
if (anykeydown && cls.key_dest == key_game)
|
||||
cmd->buttons |= BUTTON_ANY;
|
||||
|
||||
// send milliseconds of time to apply the move
|
||||
ms = cls.frametime * 1000;
|
||||
if (ms > 250)
|
||||
ms = 100; // time was unreasonable
|
||||
cmd->msec = ms;
|
||||
|
||||
CL_ClampPitch ();
|
||||
for (i=0 ; i<3 ; i++)
|
||||
cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);
|
||||
|
||||
cmd->impulse = in_impulse;
|
||||
in_impulse = 0;
|
||||
|
||||
// send the ambient light level at the player's current position
|
||||
cmd->lightlevel = (byte)cl_lightlevel->value;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_CreateCmd
|
||||
=================
|
||||
*/
|
||||
usercmd_t CL_CreateCmd (void)
|
||||
{
|
||||
usercmd_t cmd;
|
||||
|
||||
frame_msec = sys_frame_time - old_sys_frame_time;
|
||||
if (frame_msec < 1)
|
||||
frame_msec = 1;
|
||||
if (frame_msec > 200)
|
||||
frame_msec = 200;
|
||||
|
||||
// get basic movement from keyboard
|
||||
CL_BaseMove (&cmd);
|
||||
|
||||
// allow mice or other external controllers to add to the move
|
||||
IN_Move (&cmd);
|
||||
|
||||
CL_FinishMove (&cmd);
|
||||
|
||||
old_sys_frame_time = sys_frame_time;
|
||||
|
||||
//cmd.impulse = cls.framecount;
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
|
||||
void IN_CenterView (void)
|
||||
{
|
||||
cl.viewangles[PITCH] = -SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
CL_InitInput
|
||||
============
|
||||
*/
|
||||
void CL_InitInput (void)
|
||||
{
|
||||
Cmd_AddCommand ("centerview",IN_CenterView);
|
||||
|
||||
Cmd_AddCommand ("+moveup",IN_UpDown);
|
||||
Cmd_AddCommand ("-moveup",IN_UpUp);
|
||||
Cmd_AddCommand ("+movedown",IN_DownDown);
|
||||
Cmd_AddCommand ("-movedown",IN_DownUp);
|
||||
Cmd_AddCommand ("+left",IN_LeftDown);
|
||||
Cmd_AddCommand ("-left",IN_LeftUp);
|
||||
Cmd_AddCommand ("+right",IN_RightDown);
|
||||
Cmd_AddCommand ("-right",IN_RightUp);
|
||||
Cmd_AddCommand ("+forward",IN_ForwardDown);
|
||||
Cmd_AddCommand ("-forward",IN_ForwardUp);
|
||||
Cmd_AddCommand ("+back",IN_BackDown);
|
||||
Cmd_AddCommand ("-back",IN_BackUp);
|
||||
Cmd_AddCommand ("+lookup", IN_LookupDown);
|
||||
Cmd_AddCommand ("-lookup", IN_LookupUp);
|
||||
Cmd_AddCommand ("+lookdown", IN_LookdownDown);
|
||||
Cmd_AddCommand ("-lookdown", IN_LookdownUp);
|
||||
Cmd_AddCommand ("+strafe", IN_StrafeDown);
|
||||
Cmd_AddCommand ("-strafe", IN_StrafeUp);
|
||||
Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
|
||||
Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
|
||||
Cmd_AddCommand ("+moveright", IN_MoverightDown);
|
||||
Cmd_AddCommand ("-moveright", IN_MoverightUp);
|
||||
Cmd_AddCommand ("+speed", IN_SpeedDown);
|
||||
Cmd_AddCommand ("-speed", IN_SpeedUp);
|
||||
Cmd_AddCommand ("+attack", IN_AttackDown);
|
||||
Cmd_AddCommand ("-attack", IN_AttackUp);
|
||||
Cmd_AddCommand ("+use", IN_UseDown);
|
||||
Cmd_AddCommand ("-use", IN_UseUp);
|
||||
Cmd_AddCommand ("impulse", IN_Impulse);
|
||||
Cmd_AddCommand ("+klook", IN_KLookDown);
|
||||
Cmd_AddCommand ("-klook", IN_KLookUp);
|
||||
|
||||
cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_SendCmd
|
||||
=================
|
||||
*/
|
||||
void CL_SendCmd (void)
|
||||
{
|
||||
sizebuf_t buf;
|
||||
byte data[128];
|
||||
int i;
|
||||
usercmd_t *cmd, *oldcmd;
|
||||
usercmd_t nullcmd;
|
||||
int checksumIndex;
|
||||
|
||||
// build a command even if not connected
|
||||
|
||||
// save this command off for prediction
|
||||
i = cls.netchan.outgoing_sequence & (CMD_BACKUP-1);
|
||||
cmd = &cl.cmds[i];
|
||||
cl.cmd_time[i] = cls.realtime; // for netgraph ping calculation
|
||||
|
||||
*cmd = CL_CreateCmd ();
|
||||
|
||||
cl.cmd = *cmd;
|
||||
|
||||
if (cls.state == ca_disconnected || cls.state == ca_connecting)
|
||||
return;
|
||||
|
||||
if ( cls.state == ca_connected)
|
||||
{
|
||||
if (cls.netchan.message.cursize || curtime - cls.netchan.last_sent > 1000 )
|
||||
Netchan_Transmit (&cls.netchan, 0, buf.data);
|
||||
return;
|
||||
}
|
||||
|
||||
// send a userinfo update if needed
|
||||
if (userinfo_modified)
|
||||
{
|
||||
CL_FixUpGender();
|
||||
userinfo_modified = false;
|
||||
MSG_WriteByte (&cls.netchan.message, clc_userinfo);
|
||||
MSG_WriteString (&cls.netchan.message, Cvar_Userinfo() );
|
||||
}
|
||||
|
||||
SZ_Init (&buf, data, sizeof(data));
|
||||
|
||||
if (cmd->buttons && cl.cinematictime > 0 && !cl.attractloop
|
||||
&& cls.realtime - cl.cinematictime > 1000)
|
||||
{ // skip the rest of the cinematic
|
||||
SCR_FinishCinematic ();
|
||||
}
|
||||
|
||||
// begin a client move command
|
||||
MSG_WriteByte (&buf, clc_move);
|
||||
|
||||
// save the position for a checksum byte
|
||||
checksumIndex = buf.cursize;
|
||||
MSG_WriteByte (&buf, 0);
|
||||
|
||||
// let the server know what the last frame we
|
||||
// got was, so the next message can be delta compressed
|
||||
if (cl_nodelta->value || !cl.frame.valid || cls.demowaiting)
|
||||
MSG_WriteLong (&buf, -1); // no compression
|
||||
else
|
||||
MSG_WriteLong (&buf, cl.frame.serverframe);
|
||||
|
||||
// send this and the previous cmds in the message, so
|
||||
// if the last packet was dropped, it can be recovered
|
||||
i = (cls.netchan.outgoing_sequence-2) & (CMD_BACKUP-1);
|
||||
cmd = &cl.cmds[i];
|
||||
memset (&nullcmd, 0, sizeof(nullcmd));
|
||||
MSG_WriteDeltaUsercmd (&buf, &nullcmd, cmd);
|
||||
oldcmd = cmd;
|
||||
|
||||
i = (cls.netchan.outgoing_sequence-1) & (CMD_BACKUP-1);
|
||||
cmd = &cl.cmds[i];
|
||||
MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
|
||||
oldcmd = cmd;
|
||||
|
||||
i = (cls.netchan.outgoing_sequence) & (CMD_BACKUP-1);
|
||||
cmd = &cl.cmds[i];
|
||||
MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd);
|
||||
|
||||
// calculate a checksum over the move commands
|
||||
buf.data[checksumIndex] = COM_BlockSequenceCRCByte(
|
||||
buf.data + checksumIndex + 1, buf.cursize - checksumIndex - 1,
|
||||
cls.netchan.outgoing_sequence);
|
||||
|
||||
//
|
||||
// deliver the message
|
||||
//
|
||||
Netchan_Transmit (&cls.netchan, buf.cursize, buf.data);
|
||||
}
|
||||
|
||||
|
142
client/cl_inv.c
Normal file
142
client/cl_inv.c
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// cl_inv.c -- client inventory screen
|
||||
|
||||
#include "client.h"
|
||||
|
||||
/*
|
||||
================
|
||||
CL_ParseInventory
|
||||
================
|
||||
*/
|
||||
void CL_ParseInventory (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<MAX_ITEMS ; i++)
|
||||
cl.inventory[i] = MSG_ReadShort (&net_message);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Inv_DrawString
|
||||
================
|
||||
*/
|
||||
void Inv_DrawString (int x, int y, char *string)
|
||||
{
|
||||
while (*string)
|
||||
{
|
||||
re.DrawChar (x, y, *string);
|
||||
x+=8;
|
||||
string++;
|
||||
}
|
||||
}
|
||||
|
||||
void SetStringHighBit (char *s)
|
||||
{
|
||||
while (*s)
|
||||
*s++ |= 128;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CL_DrawInventory
|
||||
================
|
||||
*/
|
||||
#define DISPLAY_ITEMS 17
|
||||
|
||||
void CL_DrawInventory (void)
|
||||
{
|
||||
int i, j;
|
||||
int num, selected_num, item;
|
||||
int index[MAX_ITEMS];
|
||||
char string[1024];
|
||||
int x, y;
|
||||
char binding[1024];
|
||||
char *bind;
|
||||
int selected;
|
||||
int top;
|
||||
|
||||
selected = cl.frame.playerstate.stats[STAT_SELECTED_ITEM];
|
||||
|
||||
num = 0;
|
||||
selected_num = 0;
|
||||
for (i=0 ; i<MAX_ITEMS ; i++)
|
||||
{
|
||||
if (i==selected)
|
||||
selected_num = num;
|
||||
if (cl.inventory[i])
|
||||
{
|
||||
index[num] = i;
|
||||
num++;
|
||||
}
|
||||
}
|
||||
|
||||
// determine scroll point
|
||||
top = selected_num - DISPLAY_ITEMS/2;
|
||||
if (num - top < DISPLAY_ITEMS)
|
||||
top = num - DISPLAY_ITEMS;
|
||||
if (top < 0)
|
||||
top = 0;
|
||||
|
||||
x = (viddef.width-256)/2;
|
||||
y = (viddef.height-240)/2;
|
||||
|
||||
// repaint everything next frame
|
||||
SCR_DirtyScreen ();
|
||||
|
||||
re.DrawPic (x, y+8, "inventory");
|
||||
|
||||
y += 24;
|
||||
x += 24;
|
||||
Inv_DrawString (x, y, "hotkey ### item");
|
||||
Inv_DrawString (x, y+8, "------ --- ----");
|
||||
y += 16;
|
||||
for (i=top ; i<num && i < top+DISPLAY_ITEMS ; i++)
|
||||
{
|
||||
item = index[i];
|
||||
// search for a binding
|
||||
Com_sprintf (binding, sizeof(binding), "use %s", cl.configstrings[CS_ITEMS+item]);
|
||||
bind = "";
|
||||
for (j=0 ; j<256 ; j++)
|
||||
if (keybindings[j] && !Q_stricmp (keybindings[j], binding))
|
||||
{
|
||||
bind = Key_KeynumToString(j);
|
||||
break;
|
||||
}
|
||||
|
||||
Com_sprintf (string, sizeof(string), "%6s %3i %s", bind, cl.inventory[item],
|
||||
cl.configstrings[CS_ITEMS+item] );
|
||||
if (item != selected)
|
||||
SetStringHighBit (string);
|
||||
else // draw a blinky cursor by the selected item
|
||||
{
|
||||
if ( (int)(cls.realtime*10) & 1)
|
||||
re.DrawChar (x-8, y, 15);
|
||||
}
|
||||
Inv_DrawString (x, y, string);
|
||||
y += 8;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
1844
client/cl_main.c
Normal file
1844
client/cl_main.c
Normal file
File diff suppressed because it is too large
Load Diff
1323
client/cl_newfx.c
Normal file
1323
client/cl_newfx.c
Normal file
File diff suppressed because it is too large
Load Diff
806
client/cl_parse.c
Normal file
806
client/cl_parse.c
Normal file
@ -0,0 +1,806 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// cl_parse.c -- parse a message received from the server
|
||||
|
||||
#include "client.h"
|
||||
|
||||
char *svc_strings[256] =
|
||||
{
|
||||
"svc_bad",
|
||||
|
||||
"svc_muzzleflash",
|
||||
"svc_muzzlflash2",
|
||||
"svc_temp_entity",
|
||||
"svc_layout",
|
||||
"svc_inventory",
|
||||
|
||||
"svc_nop",
|
||||
"svc_disconnect",
|
||||
"svc_reconnect",
|
||||
"svc_sound",
|
||||
"svc_print",
|
||||
"svc_stufftext",
|
||||
"svc_serverdata",
|
||||
"svc_configstring",
|
||||
"svc_spawnbaseline",
|
||||
"svc_centerprint",
|
||||
"svc_download",
|
||||
"svc_playerinfo",
|
||||
"svc_packetentities",
|
||||
"svc_deltapacketentities",
|
||||
"svc_frame"
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void CL_DownloadFileName(char *dest, int destlen, char *fn)
|
||||
{
|
||||
if (strncmp(fn, "players", 7) == 0)
|
||||
Com_sprintf (dest, destlen, "%s/%s", BASEDIRNAME, fn);
|
||||
else
|
||||
Com_sprintf (dest, destlen, "%s/%s", FS_Gamedir(), fn);
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
CL_CheckOrDownloadFile
|
||||
|
||||
Returns true if the file exists, otherwise it attempts
|
||||
to start a download from the server.
|
||||
===============
|
||||
*/
|
||||
qboolean CL_CheckOrDownloadFile (char *filename)
|
||||
{
|
||||
FILE *fp;
|
||||
char name[MAX_OSPATH];
|
||||
|
||||
if (strstr (filename, ".."))
|
||||
{
|
||||
Com_Printf ("Refusing to download a path with ..\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (FS_LoadFile (filename, NULL) != -1)
|
||||
{ // it exists, no need to download
|
||||
return true;
|
||||
}
|
||||
|
||||
strcpy (cls.downloadname, filename);
|
||||
|
||||
// download to a temp name, and only rename
|
||||
// to the real name when done, so if interrupted
|
||||
// a runt file wont be left
|
||||
COM_StripExtension (cls.downloadname, cls.downloadtempname);
|
||||
strcat (cls.downloadtempname, ".tmp");
|
||||
|
||||
//ZOID
|
||||
// check to see if we already have a tmp for this file, if so, try to resume
|
||||
// open the file if not opened yet
|
||||
CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
|
||||
|
||||
// FS_CreatePath (name);
|
||||
|
||||
fp = fopen (name, "r+b");
|
||||
if (fp) { // it exists
|
||||
int len;
|
||||
fseek(fp, 0, SEEK_END);
|
||||
len = ftell(fp);
|
||||
|
||||
cls.download = fp;
|
||||
|
||||
// give the server an offset to start the download
|
||||
Com_Printf ("Resuming %s\n", cls.downloadname);
|
||||
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
|
||||
MSG_WriteString (&cls.netchan.message,
|
||||
va("download %s %i", cls.downloadname, len));
|
||||
} else {
|
||||
Com_Printf ("Downloading %s\n", cls.downloadname);
|
||||
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
|
||||
MSG_WriteString (&cls.netchan.message,
|
||||
va("download %s", cls.downloadname));
|
||||
}
|
||||
|
||||
cls.downloadnumber++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
CL_Download_f
|
||||
|
||||
Request a download from the server
|
||||
===============
|
||||
*/
|
||||
void CL_Download_f (void)
|
||||
{
|
||||
char filename[MAX_OSPATH];
|
||||
|
||||
if (Cmd_Argc() != 2) {
|
||||
Com_Printf("Usage: download <filename>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Com_sprintf(filename, sizeof(filename), "%s", Cmd_Argv(1));
|
||||
|
||||
if (strstr (filename, ".."))
|
||||
{
|
||||
Com_Printf ("Refusing to download a path with ..\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (FS_LoadFile (filename, NULL) != -1)
|
||||
{ // it exists, no need to download
|
||||
Com_Printf("File already exists.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
strcpy (cls.downloadname, filename);
|
||||
Com_Printf ("Downloading %s\n", cls.downloadname);
|
||||
|
||||
// download to a temp name, and only rename
|
||||
// to the real name when done, so if interrupted
|
||||
// a runt file wont be left
|
||||
COM_StripExtension (cls.downloadname, cls.downloadtempname);
|
||||
strcat (cls.downloadtempname, ".tmp");
|
||||
|
||||
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
|
||||
MSG_WriteString (&cls.netchan.message,
|
||||
va("download %s", cls.downloadname));
|
||||
|
||||
cls.downloadnumber++;
|
||||
}
|
||||
|
||||
/*
|
||||
======================
|
||||
CL_RegisterSounds
|
||||
======================
|
||||
*/
|
||||
void CL_RegisterSounds (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
S_BeginRegistration ();
|
||||
CL_RegisterTEntSounds ();
|
||||
for (i=1 ; i<MAX_SOUNDS ; i++)
|
||||
{
|
||||
if (!cl.configstrings[CS_SOUNDS+i][0])
|
||||
break;
|
||||
cl.sound_precache[i] = S_RegisterSound (cl.configstrings[CS_SOUNDS+i]);
|
||||
Sys_SendKeyEvents (); // pump message loop
|
||||
}
|
||||
S_EndRegistration ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=====================
|
||||
CL_ParseDownload
|
||||
|
||||
A download message has been received from the server
|
||||
=====================
|
||||
*/
|
||||
void CL_ParseDownload (void)
|
||||
{
|
||||
int size, percent;
|
||||
char name[MAX_OSPATH];
|
||||
int r;
|
||||
|
||||
// read the data
|
||||
size = MSG_ReadShort (&net_message);
|
||||
percent = MSG_ReadByte (&net_message);
|
||||
if (size == -1)
|
||||
{
|
||||
Com_Printf ("Server does not have this file.\n");
|
||||
if (cls.download)
|
||||
{
|
||||
// if here, we tried to resume a file but the server said no
|
||||
fclose (cls.download);
|
||||
cls.download = NULL;
|
||||
}
|
||||
CL_RequestNextDownload ();
|
||||
return;
|
||||
}
|
||||
|
||||
// open the file if not opened yet
|
||||
if (!cls.download)
|
||||
{
|
||||
CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
|
||||
|
||||
FS_CreatePath (name);
|
||||
|
||||
cls.download = fopen (name, "wb");
|
||||
if (!cls.download)
|
||||
{
|
||||
net_message.readcount += size;
|
||||
Com_Printf ("Failed to open %s\n", cls.downloadtempname);
|
||||
CL_RequestNextDownload ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fwrite (net_message.data + net_message.readcount, 1, size, cls.download);
|
||||
net_message.readcount += size;
|
||||
|
||||
if (percent != 100)
|
||||
{
|
||||
// request next block
|
||||
// change display routines by zoid
|
||||
#if 0
|
||||
Com_Printf (".");
|
||||
if (10*(percent/10) != cls.downloadpercent)
|
||||
{
|
||||
cls.downloadpercent = 10*(percent/10);
|
||||
Com_Printf ("%i%%", cls.downloadpercent);
|
||||
}
|
||||
#endif
|
||||
cls.downloadpercent = percent;
|
||||
|
||||
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
|
||||
SZ_Print (&cls.netchan.message, "nextdl");
|
||||
}
|
||||
else
|
||||
{
|
||||
char oldn[MAX_OSPATH];
|
||||
char newn[MAX_OSPATH];
|
||||
|
||||
// Com_Printf ("100%%\n");
|
||||
|
||||
fclose (cls.download);
|
||||
|
||||
// rename the temp file to it's final name
|
||||
CL_DownloadFileName(oldn, sizeof(oldn), cls.downloadtempname);
|
||||
CL_DownloadFileName(newn, sizeof(newn), cls.downloadname);
|
||||
r = rename (oldn, newn);
|
||||
if (r)
|
||||
Com_Printf ("failed to rename.\n");
|
||||
|
||||
cls.download = NULL;
|
||||
cls.downloadpercent = 0;
|
||||
|
||||
// get another file if needed
|
||||
|
||||
CL_RequestNextDownload ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=====================================================================
|
||||
|
||||
SERVER CONNECTING MESSAGES
|
||||
|
||||
=====================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==================
|
||||
CL_ParseServerData
|
||||
==================
|
||||
*/
|
||||
void CL_ParseServerData (void)
|
||||
{
|
||||
extern cvar_t *fs_gamedirvar;
|
||||
char *str;
|
||||
int i;
|
||||
|
||||
Com_DPrintf ("Serverdata packet received.\n");
|
||||
//
|
||||
// wipe the client_state_t struct
|
||||
//
|
||||
CL_ClearState ();
|
||||
cls.state = ca_connected;
|
||||
|
||||
// parse protocol version number
|
||||
i = MSG_ReadLong (&net_message);
|
||||
cls.serverProtocol = i;
|
||||
|
||||
// BIG HACK to let demos from release work with the 3.0x patch!!!
|
||||
if (Com_ServerState() && PROTOCOL_VERSION == 34)
|
||||
{
|
||||
}
|
||||
else if (i != PROTOCOL_VERSION)
|
||||
Com_Error (ERR_DROP,"Server returned version %i, not %i", i, PROTOCOL_VERSION);
|
||||
|
||||
cl.servercount = MSG_ReadLong (&net_message);
|
||||
cl.attractloop = MSG_ReadByte (&net_message);
|
||||
|
||||
// game directory
|
||||
str = MSG_ReadString (&net_message);
|
||||
strncpy (cl.gamedir, str, sizeof(cl.gamedir)-1);
|
||||
|
||||
// set gamedir
|
||||
if ((*str && (!fs_gamedirvar->string || !*fs_gamedirvar->string || strcmp(fs_gamedirvar->string, str))) || (!*str && (fs_gamedirvar->string || *fs_gamedirvar->string)))
|
||||
Cvar_Set("game", str);
|
||||
|
||||
// parse player entity number
|
||||
cl.playernum = MSG_ReadShort (&net_message);
|
||||
|
||||
// get the full level name
|
||||
str = MSG_ReadString (&net_message);
|
||||
|
||||
if (cl.playernum == -1)
|
||||
{ // playing a cinematic or showing a pic, not a level
|
||||
SCR_PlayCinematic (str);
|
||||
}
|
||||
else
|
||||
{
|
||||
// seperate the printfs so the server message can have a color
|
||||
Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
|
||||
Com_Printf ("%c%s\n", 2, str);
|
||||
|
||||
// need to prep refresh at next oportunity
|
||||
cl.refresh_prepped = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
CL_ParseBaseline
|
||||
==================
|
||||
*/
|
||||
void CL_ParseBaseline (void)
|
||||
{
|
||||
entity_state_t *es;
|
||||
int bits;
|
||||
int newnum;
|
||||
entity_state_t nullstate;
|
||||
|
||||
memset (&nullstate, 0, sizeof(nullstate));
|
||||
|
||||
newnum = CL_ParseEntityBits (&bits);
|
||||
es = &cl_entities[newnum].baseline;
|
||||
CL_ParseDelta (&nullstate, es, newnum, bits);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CL_LoadClientinfo
|
||||
|
||||
================
|
||||
*/
|
||||
void CL_LoadClientinfo (clientinfo_t *ci, char *s)
|
||||
{
|
||||
int i;
|
||||
char *t;
|
||||
char model_name[MAX_QPATH];
|
||||
char skin_name[MAX_QPATH];
|
||||
char model_filename[MAX_QPATH];
|
||||
char skin_filename[MAX_QPATH];
|
||||
char weapon_filename[MAX_QPATH];
|
||||
|
||||
strncpy(ci->cinfo, s, sizeof(ci->cinfo));
|
||||
ci->cinfo[sizeof(ci->cinfo)-1] = 0;
|
||||
|
||||
// isolate the player's name
|
||||
strncpy(ci->name, s, sizeof(ci->name));
|
||||
ci->name[sizeof(ci->name)-1] = 0;
|
||||
t = strstr (s, "\\");
|
||||
if (t)
|
||||
{
|
||||
ci->name[t-s] = 0;
|
||||
s = t+1;
|
||||
}
|
||||
|
||||
if (cl_noskins->value || *s == 0)
|
||||
{
|
||||
Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
|
||||
Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/weapon.md2");
|
||||
Com_sprintf (skin_filename, sizeof(skin_filename), "players/male/grunt.pcx");
|
||||
Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/male/grunt_i.pcx");
|
||||
ci->model = re.RegisterModel (model_filename);
|
||||
memset(ci->weaponmodel, 0, sizeof(ci->weaponmodel));
|
||||
ci->weaponmodel[0] = re.RegisterModel (weapon_filename);
|
||||
ci->skin = re.RegisterSkin (skin_filename);
|
||||
ci->icon = re.RegisterPic (ci->iconname);
|
||||
}
|
||||
else
|
||||
{
|
||||
// isolate the model name
|
||||
strcpy (model_name, s);
|
||||
t = strstr(model_name, "/");
|
||||
if (!t)
|
||||
t = strstr(model_name, "\\");
|
||||
if (!t)
|
||||
t = model_name;
|
||||
*t = 0;
|
||||
|
||||
// isolate the skin name
|
||||
strcpy (skin_name, s + strlen(model_name) + 1);
|
||||
|
||||
// model file
|
||||
Com_sprintf (model_filename, sizeof(model_filename), "players/%s/tris.md2", model_name);
|
||||
ci->model = re.RegisterModel (model_filename);
|
||||
if (!ci->model)
|
||||
{
|
||||
strcpy(model_name, "male");
|
||||
Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
|
||||
ci->model = re.RegisterModel (model_filename);
|
||||
}
|
||||
|
||||
// skin file
|
||||
Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
|
||||
ci->skin = re.RegisterSkin (skin_filename);
|
||||
|
||||
// if we don't have the skin and the model wasn't male,
|
||||
// see if the male has it (this is for CTF's skins)
|
||||
if (!ci->skin && Q_stricmp(model_name, "male"))
|
||||
{
|
||||
// change model to male
|
||||
strcpy(model_name, "male");
|
||||
Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
|
||||
ci->model = re.RegisterModel (model_filename);
|
||||
|
||||
// see if the skin exists for the male model
|
||||
Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
|
||||
ci->skin = re.RegisterSkin (skin_filename);
|
||||
}
|
||||
|
||||
// if we still don't have a skin, it means that the male model didn't have
|
||||
// it, so default to grunt
|
||||
if (!ci->skin) {
|
||||
// see if the skin exists for the male model
|
||||
Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/grunt.pcx", model_name, skin_name);
|
||||
ci->skin = re.RegisterSkin (skin_filename);
|
||||
}
|
||||
|
||||
// weapon file
|
||||
for (i = 0; i < num_cl_weaponmodels; i++) {
|
||||
Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/%s/%s", model_name, cl_weaponmodels[i]);
|
||||
ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
|
||||
if (!ci->weaponmodel[i] && strcmp(model_name, "cyborg") == 0) {
|
||||
// try male
|
||||
Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/%s", cl_weaponmodels[i]);
|
||||
ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
|
||||
}
|
||||
if (!cl_vwep->value)
|
||||
break; // only one when vwep is off
|
||||
}
|
||||
|
||||
// icon file
|
||||
Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/%s/%s_i.pcx", model_name, skin_name);
|
||||
ci->icon = re.RegisterPic (ci->iconname);
|
||||
}
|
||||
|
||||
// must have loaded all data types to be valud
|
||||
if (!ci->skin || !ci->icon || !ci->model || !ci->weaponmodel[0])
|
||||
{
|
||||
ci->skin = NULL;
|
||||
ci->icon = NULL;
|
||||
ci->model = NULL;
|
||||
ci->weaponmodel[0] = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CL_ParseClientinfo
|
||||
|
||||
Load the skin, icon, and model for a client
|
||||
================
|
||||
*/
|
||||
void CL_ParseClientinfo (int player)
|
||||
{
|
||||
char *s;
|
||||
clientinfo_t *ci;
|
||||
|
||||
s = cl.configstrings[player+CS_PLAYERSKINS];
|
||||
|
||||
ci = &cl.clientinfo[player];
|
||||
|
||||
CL_LoadClientinfo (ci, s);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CL_ParseConfigString
|
||||
================
|
||||
*/
|
||||
void CL_ParseConfigString (void)
|
||||
{
|
||||
int i;
|
||||
char *s;
|
||||
|
||||
i = MSG_ReadShort (&net_message);
|
||||
if (i < 0 || i >= MAX_CONFIGSTRINGS)
|
||||
Com_Error (ERR_DROP, "configstring > MAX_CONFIGSTRINGS");
|
||||
s = MSG_ReadString(&net_message);
|
||||
strcpy (cl.configstrings[i], s);
|
||||
|
||||
// do something apropriate
|
||||
|
||||
if (i >= CS_LIGHTS && i < CS_LIGHTS+MAX_LIGHTSTYLES)
|
||||
CL_SetLightstyle (i - CS_LIGHTS);
|
||||
else if (i == CS_CDTRACK)
|
||||
{
|
||||
if (cl.refresh_prepped)
|
||||
CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
|
||||
}
|
||||
else if (i >= CS_MODELS && i < CS_MODELS+MAX_MODELS)
|
||||
{
|
||||
if (cl.refresh_prepped)
|
||||
{
|
||||
cl.model_draw[i-CS_MODELS] = re.RegisterModel (cl.configstrings[i]);
|
||||
if (cl.configstrings[i][0] == '*')
|
||||
cl.model_clip[i-CS_MODELS] = CM_InlineModel (cl.configstrings[i]);
|
||||
else
|
||||
cl.model_clip[i-CS_MODELS] = NULL;
|
||||
}
|
||||
}
|
||||
else if (i >= CS_SOUNDS && i < CS_SOUNDS+MAX_MODELS)
|
||||
{
|
||||
if (cl.refresh_prepped)
|
||||
cl.sound_precache[i-CS_SOUNDS] = S_RegisterSound (cl.configstrings[i]);
|
||||
}
|
||||
else if (i >= CS_IMAGES && i < CS_IMAGES+MAX_MODELS)
|
||||
{
|
||||
if (cl.refresh_prepped)
|
||||
cl.image_precache[i-CS_IMAGES] = re.RegisterPic (cl.configstrings[i]);
|
||||
}
|
||||
else if (i >= CS_PLAYERSKINS && i < CS_PLAYERSKINS+MAX_CLIENTS)
|
||||
{
|
||||
if (cl.refresh_prepped)
|
||||
CL_ParseClientinfo (i-CS_PLAYERSKINS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=====================================================================
|
||||
|
||||
ACTION MESSAGES
|
||||
|
||||
=====================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==================
|
||||
CL_ParseStartSoundPacket
|
||||
==================
|
||||
*/
|
||||
void CL_ParseStartSoundPacket(void)
|
||||
{
|
||||
vec3_t pos_v;
|
||||
float *pos;
|
||||
int channel, ent;
|
||||
int sound_num;
|
||||
float volume;
|
||||
float attenuation;
|
||||
int flags;
|
||||
float ofs;
|
||||
|
||||
flags = MSG_ReadByte (&net_message);
|
||||
sound_num = MSG_ReadByte (&net_message);
|
||||
|
||||
if (flags & SND_VOLUME)
|
||||
volume = MSG_ReadByte (&net_message) / 255.0;
|
||||
else
|
||||
volume = DEFAULT_SOUND_PACKET_VOLUME;
|
||||
|
||||
if (flags & SND_ATTENUATION)
|
||||
attenuation = MSG_ReadByte (&net_message) / 64.0;
|
||||
else
|
||||
attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
|
||||
|
||||
if (flags & SND_OFFSET)
|
||||
ofs = MSG_ReadByte (&net_message) / 1000.0;
|
||||
else
|
||||
ofs = 0;
|
||||
|
||||
if (flags & SND_ENT)
|
||||
{ // entity reletive
|
||||
channel = MSG_ReadShort(&net_message);
|
||||
ent = channel>>3;
|
||||
if (ent > MAX_EDICTS)
|
||||
Com_Error (ERR_DROP,"CL_ParseStartSoundPacket: ent = %i", ent);
|
||||
|
||||
channel &= 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
ent = 0;
|
||||
channel = 0;
|
||||
}
|
||||
|
||||
if (flags & SND_POS)
|
||||
{ // positioned in space
|
||||
MSG_ReadPos (&net_message, pos_v);
|
||||
|
||||
pos = pos_v;
|
||||
}
|
||||
else // use entity number
|
||||
pos = NULL;
|
||||
|
||||
if (!cl.sound_precache[sound_num])
|
||||
return;
|
||||
|
||||
S_StartSound (pos, ent, channel, cl.sound_precache[sound_num], volume, attenuation, ofs);
|
||||
}
|
||||
|
||||
|
||||
void SHOWNET(char *s)
|
||||
{
|
||||
if (cl_shownet->value>=2)
|
||||
Com_Printf ("%3i:%s\n", net_message.readcount-1, s);
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
CL_ParseServerMessage
|
||||
=====================
|
||||
*/
|
||||
void CL_ParseServerMessage (void)
|
||||
{
|
||||
int cmd;
|
||||
char *s;
|
||||
int i;
|
||||
|
||||
//
|
||||
// if recording demos, copy the message out
|
||||
//
|
||||
if (cl_shownet->value == 1)
|
||||
Com_Printf ("%i ",net_message.cursize);
|
||||
else if (cl_shownet->value >= 2)
|
||||
Com_Printf ("------------------\n");
|
||||
|
||||
|
||||
//
|
||||
// parse the message
|
||||
//
|
||||
while (1)
|
||||
{
|
||||
if (net_message.readcount > net_message.cursize)
|
||||
{
|
||||
Com_Error (ERR_DROP,"CL_ParseServerMessage: Bad server message");
|
||||
break;
|
||||
}
|
||||
|
||||
cmd = MSG_ReadByte (&net_message);
|
||||
|
||||
if (cmd == -1)
|
||||
{
|
||||
SHOWNET("END OF MESSAGE");
|
||||
break;
|
||||
}
|
||||
|
||||
if (cl_shownet->value>=2)
|
||||
{
|
||||
if (!svc_strings[cmd])
|
||||
Com_Printf ("%3i:BAD CMD %i\n", net_message.readcount-1,cmd);
|
||||
else
|
||||
SHOWNET(svc_strings[cmd]);
|
||||
}
|
||||
|
||||
// other commands
|
||||
switch (cmd)
|
||||
{
|
||||
default:
|
||||
Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
|
||||
break;
|
||||
|
||||
case svc_nop:
|
||||
// Com_Printf ("svc_nop\n");
|
||||
break;
|
||||
|
||||
case svc_disconnect:
|
||||
Com_Error (ERR_DISCONNECT,"Server disconnected\n");
|
||||
break;
|
||||
|
||||
case svc_reconnect:
|
||||
Com_Printf ("Server disconnected, reconnecting\n");
|
||||
if (cls.download) {
|
||||
//ZOID, close download
|
||||
fclose (cls.download);
|
||||
cls.download = NULL;
|
||||
}
|
||||
cls.state = ca_connecting;
|
||||
cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
|
||||
break;
|
||||
|
||||
case svc_print:
|
||||
i = MSG_ReadByte (&net_message);
|
||||
if (i == PRINT_CHAT)
|
||||
{
|
||||
S_StartLocalSound ("misc/talk.wav");
|
||||
con.ormask = 128;
|
||||
}
|
||||
Com_Printf ("%s", MSG_ReadString (&net_message));
|
||||
con.ormask = 0;
|
||||
break;
|
||||
|
||||
case svc_centerprint:
|
||||
SCR_CenterPrint (MSG_ReadString (&net_message));
|
||||
break;
|
||||
|
||||
case svc_stufftext:
|
||||
s = MSG_ReadString (&net_message);
|
||||
Com_DPrintf ("stufftext: %s\n", s);
|
||||
Cbuf_AddText (s);
|
||||
break;
|
||||
|
||||
case svc_serverdata:
|
||||
Cbuf_Execute (); // make sure any stuffed commands are done
|
||||
CL_ParseServerData ();
|
||||
break;
|
||||
|
||||
case svc_configstring:
|
||||
CL_ParseConfigString ();
|
||||
break;
|
||||
|
||||
case svc_sound:
|
||||
CL_ParseStartSoundPacket();
|
||||
break;
|
||||
|
||||
case svc_spawnbaseline:
|
||||
CL_ParseBaseline ();
|
||||
break;
|
||||
|
||||
case svc_temp_entity:
|
||||
CL_ParseTEnt ();
|
||||
break;
|
||||
|
||||
case svc_muzzleflash:
|
||||
CL_ParseMuzzleFlash ();
|
||||
break;
|
||||
|
||||
case svc_muzzleflash2:
|
||||
CL_ParseMuzzleFlash2 ();
|
||||
break;
|
||||
|
||||
case svc_download:
|
||||
CL_ParseDownload ();
|
||||
break;
|
||||
|
||||
case svc_frame:
|
||||
CL_ParseFrame ();
|
||||
break;
|
||||
|
||||
case svc_inventory:
|
||||
CL_ParseInventory ();
|
||||
break;
|
||||
|
||||
case svc_layout:
|
||||
s = MSG_ReadString (&net_message);
|
||||
strncpy (cl.layout, s, sizeof(cl.layout)-1);
|
||||
break;
|
||||
|
||||
case svc_playerinfo:
|
||||
case svc_packetentities:
|
||||
case svc_deltapacketentities:
|
||||
Com_Error (ERR_DROP, "Out of place frame data");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CL_AddNetgraph ();
|
||||
|
||||
//
|
||||
// we don't know if it is ok to save a demo message until
|
||||
// after we have parsed the frame
|
||||
//
|
||||
if (cls.demorecording && !cls.demowaiting)
|
||||
CL_WriteDemoMessage ();
|
||||
|
||||
}
|
||||
|
||||
|
278
client/cl_pred.c
Normal file
278
client/cl_pred.c
Normal file
@ -0,0 +1,278 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "client.h"
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
CL_CheckPredictionError
|
||||
===================
|
||||
*/
|
||||
void CL_CheckPredictionError (void)
|
||||
{
|
||||
int frame;
|
||||
int delta[3];
|
||||
int i;
|
||||
int len;
|
||||
|
||||
if (!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
|
||||
return;
|
||||
|
||||
// calculate the last usercmd_t we sent that the server has processed
|
||||
frame = cls.netchan.incoming_acknowledged;
|
||||
frame &= (CMD_BACKUP-1);
|
||||
|
||||
// compare what the server returned with what we had predicted it to be
|
||||
VectorSubtract (cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame], delta);
|
||||
|
||||
// save the prediction error for interpolation
|
||||
len = abs(delta[0]) + abs(delta[1]) + abs(delta[2]);
|
||||
if (len > 640) // 80 world units
|
||||
{ // a teleport or something
|
||||
VectorClear (cl.prediction_error);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cl_showmiss->value && (delta[0] || delta[1] || delta[2]) )
|
||||
Com_Printf ("prediction miss on %i: %i\n", cl.frame.serverframe,
|
||||
delta[0] + delta[1] + delta[2]);
|
||||
|
||||
VectorCopy (cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame]);
|
||||
|
||||
// save for error itnerpolation
|
||||
for (i=0 ; i<3 ; i++)
|
||||
cl.prediction_error[i] = delta[i]*0.125;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
CL_ClipMoveToEntities
|
||||
|
||||
====================
|
||||
*/
|
||||
void CL_ClipMoveToEntities ( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, trace_t *tr )
|
||||
{
|
||||
int i, x, zd, zu;
|
||||
trace_t trace;
|
||||
int headnode;
|
||||
float *angles;
|
||||
entity_state_t *ent;
|
||||
int num;
|
||||
cmodel_t *cmodel;
|
||||
vec3_t bmins, bmaxs;
|
||||
|
||||
for (i=0 ; i<cl.frame.num_entities ; i++)
|
||||
{
|
||||
num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
|
||||
ent = &cl_parse_entities[num];
|
||||
|
||||
if (!ent->solid)
|
||||
continue;
|
||||
|
||||
if (ent->number == cl.playernum+1)
|
||||
continue;
|
||||
|
||||
if (ent->solid == 31)
|
||||
{ // special value for bmodel
|
||||
cmodel = cl.model_clip[ent->modelindex];
|
||||
if (!cmodel)
|
||||
continue;
|
||||
headnode = cmodel->headnode;
|
||||
angles = ent->angles;
|
||||
}
|
||||
else
|
||||
{ // encoded bbox
|
||||
x = 8*(ent->solid & 31);
|
||||
zd = 8*((ent->solid>>5) & 31);
|
||||
zu = 8*((ent->solid>>10) & 63) - 32;
|
||||
|
||||
bmins[0] = bmins[1] = -x;
|
||||
bmaxs[0] = bmaxs[1] = x;
|
||||
bmins[2] = -zd;
|
||||
bmaxs[2] = zu;
|
||||
|
||||
headnode = CM_HeadnodeForBox (bmins, bmaxs);
|
||||
angles = vec3_origin; // boxes don't rotate
|
||||
}
|
||||
|
||||
if (tr->allsolid)
|
||||
return;
|
||||
|
||||
trace = CM_TransformedBoxTrace (start, end,
|
||||
mins, maxs, headnode, MASK_PLAYERSOLID,
|
||||
ent->origin, angles);
|
||||
|
||||
if (trace.allsolid || trace.startsolid ||
|
||||
trace.fraction < tr->fraction)
|
||||
{
|
||||
trace.ent = (struct edict_s *)ent;
|
||||
if (tr->startsolid)
|
||||
{
|
||||
*tr = trace;
|
||||
tr->startsolid = true;
|
||||
}
|
||||
else
|
||||
*tr = trace;
|
||||
}
|
||||
else if (trace.startsolid)
|
||||
tr->startsolid = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CL_PMTrace
|
||||
================
|
||||
*/
|
||||
trace_t CL_PMTrace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
|
||||
{
|
||||
trace_t t;
|
||||
|
||||
// check against world
|
||||
t = CM_BoxTrace (start, end, mins, maxs, 0, MASK_PLAYERSOLID);
|
||||
if (t.fraction < 1.0)
|
||||
t.ent = (struct edict_s *)1;
|
||||
|
||||
// check all other solid models
|
||||
CL_ClipMoveToEntities (start, mins, maxs, end, &t);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
int CL_PMpointcontents (vec3_t point)
|
||||
{
|
||||
int i;
|
||||
entity_state_t *ent;
|
||||
int num;
|
||||
cmodel_t *cmodel;
|
||||
int contents;
|
||||
|
||||
contents = CM_PointContents (point, 0);
|
||||
|
||||
for (i=0 ; i<cl.frame.num_entities ; i++)
|
||||
{
|
||||
num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
|
||||
ent = &cl_parse_entities[num];
|
||||
|
||||
if (ent->solid != 31) // special value for bmodel
|
||||
continue;
|
||||
|
||||
cmodel = cl.model_clip[ent->modelindex];
|
||||
if (!cmodel)
|
||||
continue;
|
||||
|
||||
contents |= CM_TransformedPointContents (point, cmodel->headnode, ent->origin, ent->angles);
|
||||
}
|
||||
|
||||
return contents;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_PredictMovement
|
||||
|
||||
Sets cl.predicted_origin and cl.predicted_angles
|
||||
=================
|
||||
*/
|
||||
void CL_PredictMovement (void)
|
||||
{
|
||||
int ack, current;
|
||||
int frame;
|
||||
int oldframe;
|
||||
usercmd_t *cmd;
|
||||
pmove_t pm;
|
||||
int i;
|
||||
int step;
|
||||
int oldz;
|
||||
|
||||
if (cls.state != ca_active)
|
||||
return;
|
||||
|
||||
if (cl_paused->value)
|
||||
return;
|
||||
|
||||
if (!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
|
||||
{ // just set angles
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
cl.predicted_angles[i] = cl.viewangles[i] + SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ack = cls.netchan.incoming_acknowledged;
|
||||
current = cls.netchan.outgoing_sequence;
|
||||
|
||||
// if we are too far out of date, just freeze
|
||||
if (current - ack >= CMD_BACKUP)
|
||||
{
|
||||
if (cl_showmiss->value)
|
||||
Com_Printf ("exceeded CMD_BACKUP\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// copy current state to pmove
|
||||
memset (&pm, 0, sizeof(pm));
|
||||
pm.trace = CL_PMTrace;
|
||||
pm.pointcontents = CL_PMpointcontents;
|
||||
|
||||
pm_airaccelerate = atof(cl.configstrings[CS_AIRACCEL]);
|
||||
|
||||
pm.s = cl.frame.playerstate.pmove;
|
||||
|
||||
// SCR_DebugGraph (current - ack - 1, 0);
|
||||
|
||||
frame = 0;
|
||||
|
||||
// run frames
|
||||
while (++ack < current)
|
||||
{
|
||||
frame = ack & (CMD_BACKUP-1);
|
||||
cmd = &cl.cmds[frame];
|
||||
|
||||
pm.cmd = *cmd;
|
||||
Pmove (&pm);
|
||||
|
||||
// save for debug checking
|
||||
VectorCopy (pm.s.origin, cl.predicted_origins[frame]);
|
||||
}
|
||||
|
||||
oldframe = (ack-2) & (CMD_BACKUP-1);
|
||||
oldz = cl.predicted_origins[oldframe][2];
|
||||
step = pm.s.origin[2] - oldz;
|
||||
if (step > 63 && step < 160 && (pm.s.pm_flags & PMF_ON_GROUND) )
|
||||
{
|
||||
cl.predicted_step = step * 0.125;
|
||||
cl.predicted_step_time = cls.realtime - cls.frametime * 500;
|
||||
}
|
||||
|
||||
|
||||
// copy results out for rendering
|
||||
cl.predicted_origin[0] = pm.s.origin[0]*0.125;
|
||||
cl.predicted_origin[1] = pm.s.origin[1]*0.125;
|
||||
cl.predicted_origin[2] = pm.s.origin[2]*0.125;
|
||||
|
||||
VectorCopy (pm.viewangles, cl.predicted_angles);
|
||||
}
|
1401
client/cl_scrn.c
Normal file
1401
client/cl_scrn.c
Normal file
File diff suppressed because it is too large
Load Diff
1745
client/cl_tent.c
Normal file
1745
client/cl_tent.c
Normal file
File diff suppressed because it is too large
Load Diff
584
client/cl_view.c
Normal file
584
client/cl_view.c
Normal file
@ -0,0 +1,584 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// cl_view.c -- player rendering positioning
|
||||
|
||||
#include "client.h"
|
||||
|
||||
//=============
|
||||
//
|
||||
// development tools for weapons
|
||||
//
|
||||
int gun_frame;
|
||||
struct model_s *gun_model;
|
||||
|
||||
//=============
|
||||
|
||||
cvar_t *crosshair;
|
||||
cvar_t *cl_testparticles;
|
||||
cvar_t *cl_testentities;
|
||||
cvar_t *cl_testlights;
|
||||
cvar_t *cl_testblend;
|
||||
|
||||
cvar_t *cl_stats;
|
||||
|
||||
|
||||
int r_numdlights;
|
||||
dlight_t r_dlights[MAX_DLIGHTS];
|
||||
|
||||
int r_numentities;
|
||||
entity_t r_entities[MAX_ENTITIES];
|
||||
|
||||
int r_numparticles;
|
||||
particle_t r_particles[MAX_PARTICLES];
|
||||
|
||||
lightstyle_t r_lightstyles[MAX_LIGHTSTYLES];
|
||||
|
||||
char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
|
||||
int num_cl_weaponmodels;
|
||||
|
||||
/*
|
||||
====================
|
||||
V_ClearScene
|
||||
|
||||
Specifies the model that will be used as the world
|
||||
====================
|
||||
*/
|
||||
void V_ClearScene (void)
|
||||
{
|
||||
r_numdlights = 0;
|
||||
r_numentities = 0;
|
||||
r_numparticles = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=====================
|
||||
V_AddEntity
|
||||
|
||||
=====================
|
||||
*/
|
||||
void V_AddEntity (entity_t *ent)
|
||||
{
|
||||
if (r_numentities >= MAX_ENTITIES)
|
||||
return;
|
||||
r_entities[r_numentities++] = *ent;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=====================
|
||||
V_AddParticle
|
||||
|
||||
=====================
|
||||
*/
|
||||
void V_AddParticle (vec3_t org, int color, float alpha)
|
||||
{
|
||||
particle_t *p;
|
||||
|
||||
if (r_numparticles >= MAX_PARTICLES)
|
||||
return;
|
||||
p = &r_particles[r_numparticles++];
|
||||
VectorCopy (org, p->origin);
|
||||
p->color = color;
|
||||
p->alpha = alpha;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
V_AddLight
|
||||
|
||||
=====================
|
||||
*/
|
||||
void V_AddLight (vec3_t org, float intensity, float r, float g, float b)
|
||||
{
|
||||
dlight_t *dl;
|
||||
|
||||
if (r_numdlights >= MAX_DLIGHTS)
|
||||
return;
|
||||
dl = &r_dlights[r_numdlights++];
|
||||
VectorCopy (org, dl->origin);
|
||||
dl->intensity = intensity;
|
||||
dl->color[0] = r;
|
||||
dl->color[1] = g;
|
||||
dl->color[2] = b;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=====================
|
||||
V_AddLightStyle
|
||||
|
||||
=====================
|
||||
*/
|
||||
void V_AddLightStyle (int style, float r, float g, float b)
|
||||
{
|
||||
lightstyle_t *ls;
|
||||
|
||||
if (style < 0 || style > MAX_LIGHTSTYLES)
|
||||
Com_Error (ERR_DROP, "Bad light style %i", style);
|
||||
ls = &r_lightstyles[style];
|
||||
|
||||
ls->white = r+g+b;
|
||||
ls->rgb[0] = r;
|
||||
ls->rgb[1] = g;
|
||||
ls->rgb[2] = b;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
V_TestParticles
|
||||
|
||||
If cl_testparticles is set, create 4096 particles in the view
|
||||
================
|
||||
*/
|
||||
void V_TestParticles (void)
|
||||
{
|
||||
particle_t *p;
|
||||
int i, j;
|
||||
float d, r, u;
|
||||
|
||||
r_numparticles = MAX_PARTICLES;
|
||||
for (i=0 ; i<r_numparticles ; i++)
|
||||
{
|
||||
d = i*0.25;
|
||||
r = 4*((i&7)-3.5);
|
||||
u = 4*(((i>>3)&7)-3.5);
|
||||
p = &r_particles[i];
|
||||
|
||||
for (j=0 ; j<3 ; j++)
|
||||
p->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*d +
|
||||
cl.v_right[j]*r + cl.v_up[j]*u;
|
||||
|
||||
p->color = 8;
|
||||
p->alpha = cl_testparticles->value;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
V_TestEntities
|
||||
|
||||
If cl_testentities is set, create 32 player models
|
||||
================
|
||||
*/
|
||||
void V_TestEntities (void)
|
||||
{
|
||||
int i, j;
|
||||
float f, r;
|
||||
entity_t *ent;
|
||||
|
||||
r_numentities = 32;
|
||||
memset (r_entities, 0, sizeof(r_entities));
|
||||
|
||||
for (i=0 ; i<r_numentities ; i++)
|
||||
{
|
||||
ent = &r_entities[i];
|
||||
|
||||
r = 64 * ( (i%4) - 1.5 );
|
||||
f = 64 * (i/4) + 128;
|
||||
|
||||
for (j=0 ; j<3 ; j++)
|
||||
ent->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
|
||||
cl.v_right[j]*r;
|
||||
|
||||
ent->model = cl.baseclientinfo.model;
|
||||
ent->skin = cl.baseclientinfo.skin;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
V_TestLights
|
||||
|
||||
If cl_testlights is set, create 32 lights models
|
||||
================
|
||||
*/
|
||||
void V_TestLights (void)
|
||||
{
|
||||
int i, j;
|
||||
float f, r;
|
||||
dlight_t *dl;
|
||||
|
||||
r_numdlights = 32;
|
||||
memset (r_dlights, 0, sizeof(r_dlights));
|
||||
|
||||
for (i=0 ; i<r_numdlights ; i++)
|
||||
{
|
||||
dl = &r_dlights[i];
|
||||
|
||||
r = 64 * ( (i%4) - 1.5 );
|
||||
f = 64 * (i/4) + 128;
|
||||
|
||||
for (j=0 ; j<3 ; j++)
|
||||
dl->origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
|
||||
cl.v_right[j]*r;
|
||||
dl->color[0] = ((i%6)+1) & 1;
|
||||
dl->color[1] = (((i%6)+1) & 2)>>1;
|
||||
dl->color[2] = (((i%6)+1) & 4)>>2;
|
||||
dl->intensity = 200;
|
||||
}
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_PrepRefresh
|
||||
|
||||
Call before entering a new level, or after changing dlls
|
||||
=================
|
||||
*/
|
||||
void CL_PrepRefresh (void)
|
||||
{
|
||||
char mapname[32];
|
||||
int i;
|
||||
char name[MAX_QPATH];
|
||||
float rotate;
|
||||
vec3_t axis;
|
||||
|
||||
if (!cl.configstrings[CS_MODELS+1][0])
|
||||
return; // no map loaded
|
||||
|
||||
SCR_AddDirtyPoint (0, 0);
|
||||
SCR_AddDirtyPoint (viddef.width-1, viddef.height-1);
|
||||
|
||||
// let the render dll load the map
|
||||
strcpy (mapname, cl.configstrings[CS_MODELS+1] + 5); // skip "maps/"
|
||||
mapname[strlen(mapname)-4] = 0; // cut off ".bsp"
|
||||
|
||||
// register models, pics, and skins
|
||||
Com_Printf ("Map: %s\r", mapname);
|
||||
SCR_UpdateScreen ();
|
||||
re.BeginRegistration (mapname);
|
||||
Com_Printf (" \r");
|
||||
|
||||
// precache status bar pics
|
||||
Com_Printf ("pics\r");
|
||||
SCR_UpdateScreen ();
|
||||
SCR_TouchPics ();
|
||||
Com_Printf (" \r");
|
||||
|
||||
CL_RegisterTEntModels ();
|
||||
|
||||
num_cl_weaponmodels = 1;
|
||||
strcpy(cl_weaponmodels[0], "weapon.md2");
|
||||
|
||||
for (i=1 ; i<MAX_MODELS && cl.configstrings[CS_MODELS+i][0] ; i++)
|
||||
{
|
||||
strcpy (name, cl.configstrings[CS_MODELS+i]);
|
||||
name[37] = 0; // never go beyond one line
|
||||
if (name[0] != '*')
|
||||
Com_Printf ("%s\r", name);
|
||||
SCR_UpdateScreen ();
|
||||
Sys_SendKeyEvents (); // pump message loop
|
||||
if (name[0] == '#')
|
||||
{
|
||||
// special player weapon model
|
||||
if (num_cl_weaponmodels < MAX_CLIENTWEAPONMODELS)
|
||||
{
|
||||
strncpy(cl_weaponmodels[num_cl_weaponmodels], cl.configstrings[CS_MODELS+i]+1,
|
||||
sizeof(cl_weaponmodels[num_cl_weaponmodels]) - 1);
|
||||
num_cl_weaponmodels++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cl.model_draw[i] = re.RegisterModel (cl.configstrings[CS_MODELS+i]);
|
||||
if (name[0] == '*')
|
||||
cl.model_clip[i] = CM_InlineModel (cl.configstrings[CS_MODELS+i]);
|
||||
else
|
||||
cl.model_clip[i] = NULL;
|
||||
}
|
||||
if (name[0] != '*')
|
||||
Com_Printf (" \r");
|
||||
}
|
||||
|
||||
Com_Printf ("images\r", i);
|
||||
SCR_UpdateScreen ();
|
||||
for (i=1 ; i<MAX_IMAGES && cl.configstrings[CS_IMAGES+i][0] ; i++)
|
||||
{
|
||||
cl.image_precache[i] = re.RegisterPic (cl.configstrings[CS_IMAGES+i]);
|
||||
Sys_SendKeyEvents (); // pump message loop
|
||||
}
|
||||
|
||||
Com_Printf (" \r");
|
||||
for (i=0 ; i<MAX_CLIENTS ; i++)
|
||||
{
|
||||
if (!cl.configstrings[CS_PLAYERSKINS+i][0])
|
||||
continue;
|
||||
Com_Printf ("client %i\r", i);
|
||||
SCR_UpdateScreen ();
|
||||
Sys_SendKeyEvents (); // pump message loop
|
||||
CL_ParseClientinfo (i);
|
||||
Com_Printf (" \r");
|
||||
}
|
||||
|
||||
CL_LoadClientinfo (&cl.baseclientinfo, "unnamed\\male/grunt");
|
||||
|
||||
// set sky textures and speed
|
||||
Com_Printf ("sky\r", i);
|
||||
SCR_UpdateScreen ();
|
||||
rotate = atof (cl.configstrings[CS_SKYROTATE]);
|
||||
sscanf (cl.configstrings[CS_SKYAXIS], "%f %f %f",
|
||||
&axis[0], &axis[1], &axis[2]);
|
||||
re.SetSky (cl.configstrings[CS_SKY], rotate, axis);
|
||||
Com_Printf (" \r");
|
||||
|
||||
// the renderer can now free unneeded stuff
|
||||
re.EndRegistration ();
|
||||
|
||||
// clear any lines of console text
|
||||
Con_ClearNotify ();
|
||||
|
||||
SCR_UpdateScreen ();
|
||||
cl.refresh_prepped = true;
|
||||
cl.force_refdef = true; // make sure we have a valid refdef
|
||||
|
||||
// start the cd track
|
||||
CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
CalcFov
|
||||
====================
|
||||
*/
|
||||
float CalcFov (float fov_x, float width, float height)
|
||||
{
|
||||
float a;
|
||||
float x;
|
||||
|
||||
if (fov_x < 1 || fov_x > 179)
|
||||
Com_Error (ERR_DROP, "Bad fov: %f", fov_x);
|
||||
|
||||
x = width/tan(fov_x/360*M_PI);
|
||||
|
||||
a = atan (height/x);
|
||||
|
||||
a = a*360/M_PI;
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
// gun frame debugging functions
|
||||
void V_Gun_Next_f (void)
|
||||
{
|
||||
gun_frame++;
|
||||
Com_Printf ("frame %i\n", gun_frame);
|
||||
}
|
||||
|
||||
void V_Gun_Prev_f (void)
|
||||
{
|
||||
gun_frame--;
|
||||
if (gun_frame < 0)
|
||||
gun_frame = 0;
|
||||
Com_Printf ("frame %i\n", gun_frame);
|
||||
}
|
||||
|
||||
void V_Gun_Model_f (void)
|
||||
{
|
||||
char name[MAX_QPATH];
|
||||
|
||||
if (Cmd_Argc() != 2)
|
||||
{
|
||||
gun_model = NULL;
|
||||
return;
|
||||
}
|
||||
Com_sprintf (name, sizeof(name), "models/%s/tris.md2", Cmd_Argv(1));
|
||||
gun_model = re.RegisterModel (name);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
SCR_DrawCrosshair
|
||||
=================
|
||||
*/
|
||||
void SCR_DrawCrosshair (void)
|
||||
{
|
||||
if (!crosshair->value)
|
||||
return;
|
||||
|
||||
if (crosshair->modified)
|
||||
{
|
||||
crosshair->modified = false;
|
||||
SCR_TouchPics ();
|
||||
}
|
||||
|
||||
if (!crosshair_pic[0])
|
||||
return;
|
||||
|
||||
re.DrawPic (scr_vrect.x + ((scr_vrect.width - crosshair_width)>>1)
|
||||
, scr_vrect.y + ((scr_vrect.height - crosshair_height)>>1), crosshair_pic);
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
V_RenderView
|
||||
|
||||
==================
|
||||
*/
|
||||
void V_RenderView( float stereo_separation )
|
||||
{
|
||||
extern int entitycmpfnc( const entity_t *, const entity_t * );
|
||||
|
||||
if (cls.state != ca_active)
|
||||
return;
|
||||
|
||||
if (!cl.refresh_prepped)
|
||||
return; // still loading
|
||||
|
||||
if (cl_timedemo->value)
|
||||
{
|
||||
if (!cl.timedemo_start)
|
||||
cl.timedemo_start = Sys_Milliseconds ();
|
||||
cl.timedemo_frames++;
|
||||
}
|
||||
|
||||
// an invalid frame will just use the exact previous refdef
|
||||
// we can't use the old frame if the video mode has changed, though...
|
||||
if ( cl.frame.valid && (cl.force_refdef || !cl_paused->value) )
|
||||
{
|
||||
cl.force_refdef = false;
|
||||
|
||||
V_ClearScene ();
|
||||
|
||||
// build a refresh entity list and calc cl.sim*
|
||||
// this also calls CL_CalcViewValues which loads
|
||||
// v_forward, etc.
|
||||
CL_AddEntities ();
|
||||
|
||||
if (cl_testparticles->value)
|
||||
V_TestParticles ();
|
||||
if (cl_testentities->value)
|
||||
V_TestEntities ();
|
||||
if (cl_testlights->value)
|
||||
V_TestLights ();
|
||||
if (cl_testblend->value)
|
||||
{
|
||||
cl.refdef.blend[0] = 1;
|
||||
cl.refdef.blend[1] = 0.5;
|
||||
cl.refdef.blend[2] = 0.25;
|
||||
cl.refdef.blend[3] = 0.5;
|
||||
}
|
||||
|
||||
// offset vieworg appropriately if we're doing stereo separation
|
||||
if ( stereo_separation != 0 )
|
||||
{
|
||||
vec3_t tmp;
|
||||
|
||||
VectorScale( cl.v_right, stereo_separation, tmp );
|
||||
VectorAdd( cl.refdef.vieworg, tmp, cl.refdef.vieworg );
|
||||
}
|
||||
|
||||
// never let it sit exactly on a node line, because a water plane can
|
||||
// dissapear when viewed with the eye exactly on it.
|
||||
// the server protocol only specifies to 1/8 pixel, so add 1/16 in each axis
|
||||
cl.refdef.vieworg[0] += 1.0/16;
|
||||
cl.refdef.vieworg[1] += 1.0/16;
|
||||
cl.refdef.vieworg[2] += 1.0/16;
|
||||
|
||||
cl.refdef.x = scr_vrect.x;
|
||||
cl.refdef.y = scr_vrect.y;
|
||||
cl.refdef.width = scr_vrect.width;
|
||||
cl.refdef.height = scr_vrect.height;
|
||||
cl.refdef.fov_y = CalcFov (cl.refdef.fov_x, cl.refdef.width, cl.refdef.height);
|
||||
cl.refdef.time = cl.time*0.001;
|
||||
|
||||
cl.refdef.areabits = cl.frame.areabits;
|
||||
|
||||
if (!cl_add_entities->value)
|
||||
r_numentities = 0;
|
||||
if (!cl_add_particles->value)
|
||||
r_numparticles = 0;
|
||||
if (!cl_add_lights->value)
|
||||
r_numdlights = 0;
|
||||
if (!cl_add_blend->value)
|
||||
{
|
||||
VectorClear (cl.refdef.blend);
|
||||
}
|
||||
|
||||
cl.refdef.num_entities = r_numentities;
|
||||
cl.refdef.entities = r_entities;
|
||||
cl.refdef.num_particles = r_numparticles;
|
||||
cl.refdef.particles = r_particles;
|
||||
cl.refdef.num_dlights = r_numdlights;
|
||||
cl.refdef.dlights = r_dlights;
|
||||
cl.refdef.lightstyles = r_lightstyles;
|
||||
|
||||
cl.refdef.rdflags = cl.frame.playerstate.rdflags;
|
||||
|
||||
// sort entities for better cache locality
|
||||
qsort( cl.refdef.entities, cl.refdef.num_entities, sizeof( cl.refdef.entities[0] ), (int (*)(const void *, const void *))entitycmpfnc );
|
||||
}
|
||||
|
||||
re.RenderFrame (&cl.refdef);
|
||||
if (cl_stats->value)
|
||||
Com_Printf ("ent:%i lt:%i part:%i\n", r_numentities, r_numdlights, r_numparticles);
|
||||
if ( log_stats->value && ( log_stats_file != 0 ) )
|
||||
fprintf( log_stats_file, "%i,%i,%i,",r_numentities, r_numdlights, r_numparticles);
|
||||
|
||||
|
||||
SCR_AddDirtyPoint (scr_vrect.x, scr_vrect.y);
|
||||
SCR_AddDirtyPoint (scr_vrect.x+scr_vrect.width-1,
|
||||
scr_vrect.y+scr_vrect.height-1);
|
||||
|
||||
SCR_DrawCrosshair ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
V_Viewpos_f
|
||||
=============
|
||||
*/
|
||||
void V_Viewpos_f (void)
|
||||
{
|
||||
Com_Printf ("(%i %i %i) : %i\n", (int)cl.refdef.vieworg[0],
|
||||
(int)cl.refdef.vieworg[1], (int)cl.refdef.vieworg[2],
|
||||
(int)cl.refdef.viewangles[YAW]);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
V_Init
|
||||
=============
|
||||
*/
|
||||
void V_Init (void)
|
||||
{
|
||||
Cmd_AddCommand ("gun_next", V_Gun_Next_f);
|
||||
Cmd_AddCommand ("gun_prev", V_Gun_Prev_f);
|
||||
Cmd_AddCommand ("gun_model", V_Gun_Model_f);
|
||||
|
||||
Cmd_AddCommand ("viewpos", V_Viewpos_f);
|
||||
|
||||
crosshair = Cvar_Get ("crosshair", "0", CVAR_ARCHIVE);
|
||||
|
||||
cl_testblend = Cvar_Get ("cl_testblend", "0", 0);
|
||||
cl_testparticles = Cvar_Get ("cl_testparticles", "0", 0);
|
||||
cl_testentities = Cvar_Get ("cl_testentities", "0", 0);
|
||||
cl_testlights = Cvar_Get ("cl_testlights", "0", 0);
|
||||
|
||||
cl_stats = Cvar_Get ("cl_stats", "0", 0);
|
||||
}
|
584
client/client.h
Normal file
584
client/client.h
Normal file
@ -0,0 +1,584 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// client.h -- primary header for client
|
||||
|
||||
//define PARANOID // speed sapping error checking
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ref.h"
|
||||
|
||||
#include "vid.h"
|
||||
#include "screen.h"
|
||||
#include "sound.h"
|
||||
#include "input.h"
|
||||
#include "keys.h"
|
||||
#include "console.h"
|
||||
#include "cdaudio.h"
|
||||
|
||||
//=============================================================================
|
||||
|
||||
typedef struct
|
||||
{
|
||||
qboolean valid; // cleared if delta parsing was invalid
|
||||
int serverframe;
|
||||
int servertime; // server time the message is valid for (in msec)
|
||||
int deltaframe;
|
||||
byte areabits[MAX_MAP_AREAS/8]; // portalarea visibility bits
|
||||
player_state_t playerstate;
|
||||
int num_entities;
|
||||
int parse_entities; // non-masked index into cl_parse_entities array
|
||||
} frame_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
entity_state_t baseline; // delta from this if not from a previous frame
|
||||
entity_state_t current;
|
||||
entity_state_t prev; // will always be valid, but might just be a copy of current
|
||||
|
||||
int serverframe; // if not current, this ent isn't in the frame
|
||||
|
||||
int trailcount; // for diminishing grenade trails
|
||||
vec3_t lerp_origin; // for trails (variable hz)
|
||||
|
||||
int fly_stoptime;
|
||||
} centity_t;
|
||||
|
||||
#define MAX_CLIENTWEAPONMODELS 20 // PGM -- upped from 16 to fit the chainfist vwep
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[MAX_QPATH];
|
||||
char cinfo[MAX_QPATH];
|
||||
struct image_s *skin;
|
||||
struct image_s *icon;
|
||||
char iconname[MAX_QPATH];
|
||||
struct model_s *model;
|
||||
struct model_s *weaponmodel[MAX_CLIENTWEAPONMODELS];
|
||||
} clientinfo_t;
|
||||
|
||||
extern char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
|
||||
extern int num_cl_weaponmodels;
|
||||
|
||||
#define CMD_BACKUP 64 // allow a lot of command backups for very fast systems
|
||||
|
||||
//
|
||||
// the client_state_t structure is wiped completely at every
|
||||
// server map change
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
int timeoutcount;
|
||||
|
||||
int timedemo_frames;
|
||||
int timedemo_start;
|
||||
|
||||
qboolean refresh_prepped; // false if on new level or new ref dll
|
||||
qboolean sound_prepped; // ambient sounds can start
|
||||
qboolean force_refdef; // vid has changed, so we can't use a paused refdef
|
||||
|
||||
int parse_entities; // index (not anded off) into cl_parse_entities[]
|
||||
|
||||
usercmd_t cmd;
|
||||
usercmd_t cmds[CMD_BACKUP]; // each mesage will send several old cmds
|
||||
int cmd_time[CMD_BACKUP]; // time sent, for calculating pings
|
||||
short predicted_origins[CMD_BACKUP][3]; // for debug comparing against server
|
||||
|
||||
float predicted_step; // for stair up smoothing
|
||||
unsigned predicted_step_time;
|
||||
|
||||
vec3_t predicted_origin; // generated by CL_PredictMovement
|
||||
vec3_t predicted_angles;
|
||||
vec3_t prediction_error;
|
||||
|
||||
frame_t frame; // received from server
|
||||
int surpressCount; // number of messages rate supressed
|
||||
frame_t frames[UPDATE_BACKUP];
|
||||
|
||||
// the client maintains its own idea of view angles, which are
|
||||
// sent to the server each frame. It is cleared to 0 upon entering each level.
|
||||
// the server sends a delta each frame which is added to the locally
|
||||
// tracked view angles to account for standing on rotating objects,
|
||||
// and teleport direction changes
|
||||
vec3_t viewangles;
|
||||
|
||||
int time; // this is the time value that the client
|
||||
// is rendering at. always <= cls.realtime
|
||||
float lerpfrac; // between oldframe and frame
|
||||
|
||||
refdef_t refdef;
|
||||
|
||||
vec3_t v_forward, v_right, v_up; // set when refdef.angles is set
|
||||
|
||||
//
|
||||
// transient data from server
|
||||
//
|
||||
char layout[1024]; // general 2D overlay
|
||||
int inventory[MAX_ITEMS];
|
||||
|
||||
//
|
||||
// non-gameserver infornamtion
|
||||
// FIXME: move this cinematic stuff into the cin_t structure
|
||||
FILE *cinematic_file;
|
||||
int cinematictime; // cls.realtime for first cinematic frame
|
||||
int cinematicframe;
|
||||
char cinematicpalette[768];
|
||||
qboolean cinematicpalette_active;
|
||||
|
||||
//
|
||||
// server state information
|
||||
//
|
||||
qboolean attractloop; // running the attract loop, any key will menu
|
||||
int servercount; // server identification for prespawns
|
||||
char gamedir[MAX_QPATH];
|
||||
int playernum;
|
||||
|
||||
char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH];
|
||||
|
||||
//
|
||||
// locally derived information from server state
|
||||
//
|
||||
struct model_s *model_draw[MAX_MODELS];
|
||||
struct cmodel_s *model_clip[MAX_MODELS];
|
||||
|
||||
struct sfx_s *sound_precache[MAX_SOUNDS];
|
||||
struct image_s *image_precache[MAX_IMAGES];
|
||||
|
||||
clientinfo_t clientinfo[MAX_CLIENTS];
|
||||
clientinfo_t baseclientinfo;
|
||||
} client_state_t;
|
||||
|
||||
extern client_state_t cl;
|
||||
|
||||
/*
|
||||
==================================================================
|
||||
|
||||
the client_static_t structure is persistant through an arbitrary number
|
||||
of server connections
|
||||
|
||||
==================================================================
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
ca_uninitialized,
|
||||
ca_disconnected, // not talking to a server
|
||||
ca_connecting, // sending request packets to the server
|
||||
ca_connected, // netchan_t established, waiting for svc_serverdata
|
||||
ca_active // game views should be displayed
|
||||
} connstate_t;
|
||||
|
||||
typedef enum {
|
||||
dl_none,
|
||||
dl_model,
|
||||
dl_sound,
|
||||
dl_skin,
|
||||
dl_single
|
||||
} dltype_t; // download type
|
||||
|
||||
typedef enum {key_game, key_console, key_message, key_menu} keydest_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
connstate_t state;
|
||||
keydest_t key_dest;
|
||||
|
||||
int framecount;
|
||||
int realtime; // always increasing, no clamping, etc
|
||||
float frametime; // seconds since last frame
|
||||
|
||||
// screen rendering information
|
||||
float disable_screen; // showing loading plaque between levels
|
||||
// or changing rendering dlls
|
||||
// if time gets > 30 seconds ahead, break it
|
||||
int disable_servercount; // when we receive a frame and cl.servercount
|
||||
// > cls.disable_servercount, clear disable_screen
|
||||
|
||||
// connection information
|
||||
char servername[MAX_OSPATH]; // name of server from original connect
|
||||
float connect_time; // for connection retransmits
|
||||
|
||||
int quakePort; // a 16 bit value that allows quake servers
|
||||
// to work around address translating routers
|
||||
netchan_t netchan;
|
||||
int serverProtocol; // in case we are doing some kind of version hack
|
||||
|
||||
int challenge; // from the server to use for connecting
|
||||
|
||||
FILE *download; // file transfer from server
|
||||
char downloadtempname[MAX_OSPATH];
|
||||
char downloadname[MAX_OSPATH];
|
||||
int downloadnumber;
|
||||
dltype_t downloadtype;
|
||||
int downloadpercent;
|
||||
|
||||
// demo recording info must be here, so it isn't cleared on level change
|
||||
qboolean demorecording;
|
||||
qboolean demowaiting; // don't record until a non-delta message is received
|
||||
FILE *demofile;
|
||||
} client_static_t;
|
||||
|
||||
extern client_static_t cls;
|
||||
|
||||
//=============================================================================
|
||||
|
||||
//
|
||||
// cvars
|
||||
//
|
||||
extern cvar_t *cl_stereo_separation;
|
||||
extern cvar_t *cl_stereo;
|
||||
|
||||
extern cvar_t *cl_gun;
|
||||
extern cvar_t *cl_add_blend;
|
||||
extern cvar_t *cl_add_lights;
|
||||
extern cvar_t *cl_add_particles;
|
||||
extern cvar_t *cl_add_entities;
|
||||
extern cvar_t *cl_predict;
|
||||
extern cvar_t *cl_footsteps;
|
||||
extern cvar_t *cl_noskins;
|
||||
extern cvar_t *cl_autoskins;
|
||||
|
||||
extern cvar_t *cl_upspeed;
|
||||
extern cvar_t *cl_forwardspeed;
|
||||
extern cvar_t *cl_sidespeed;
|
||||
|
||||
extern cvar_t *cl_yawspeed;
|
||||
extern cvar_t *cl_pitchspeed;
|
||||
|
||||
extern cvar_t *cl_run;
|
||||
|
||||
extern cvar_t *cl_anglespeedkey;
|
||||
|
||||
extern cvar_t *cl_shownet;
|
||||
extern cvar_t *cl_showmiss;
|
||||
extern cvar_t *cl_showclamp;
|
||||
|
||||
extern cvar_t *lookspring;
|
||||
extern cvar_t *lookstrafe;
|
||||
extern cvar_t *sensitivity;
|
||||
|
||||
extern cvar_t *m_pitch;
|
||||
extern cvar_t *m_yaw;
|
||||
extern cvar_t *m_forward;
|
||||
extern cvar_t *m_side;
|
||||
|
||||
extern cvar_t *freelook;
|
||||
|
||||
extern cvar_t *cl_lightlevel; // FIXME HACK
|
||||
|
||||
extern cvar_t *cl_paused;
|
||||
extern cvar_t *cl_timedemo;
|
||||
|
||||
extern cvar_t *cl_vwep;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int key; // so entities can reuse same entry
|
||||
vec3_t color;
|
||||
vec3_t origin;
|
||||
float radius;
|
||||
float die; // stop lighting after this time
|
||||
float decay; // drop this each second
|
||||
float minlight; // don't add when contributing less
|
||||
} cdlight_t;
|
||||
|
||||
extern centity_t cl_entities[MAX_EDICTS];
|
||||
extern cdlight_t cl_dlights[MAX_DLIGHTS];
|
||||
|
||||
// the cl_parse_entities must be large enough to hold UPDATE_BACKUP frames of
|
||||
// entities, so that when a delta compressed message arives from the server
|
||||
// it can be un-deltad from the original
|
||||
#define MAX_PARSE_ENTITIES 1024
|
||||
extern entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES];
|
||||
|
||||
//=============================================================================
|
||||
|
||||
extern netadr_t net_from;
|
||||
extern sizebuf_t net_message;
|
||||
|
||||
void DrawString (int x, int y, char *s);
|
||||
void DrawAltString (int x, int y, char *s); // toggle high bit
|
||||
qboolean CL_CheckOrDownloadFile (char *filename);
|
||||
|
||||
void CL_AddNetgraph (void);
|
||||
|
||||
//ROGUE
|
||||
typedef struct cl_sustain
|
||||
{
|
||||
int id;
|
||||
int type;
|
||||
int endtime;
|
||||
int nextthink;
|
||||
int thinkinterval;
|
||||
vec3_t org;
|
||||
vec3_t dir;
|
||||
int color;
|
||||
int count;
|
||||
int magnitude;
|
||||
void (*think)(struct cl_sustain *self);
|
||||
} cl_sustain_t;
|
||||
|
||||
#define MAX_SUSTAINS 32
|
||||
void CL_ParticleSteamEffect2(cl_sustain_t *self);
|
||||
|
||||
void CL_TeleporterParticles (entity_state_t *ent);
|
||||
void CL_ParticleEffect (vec3_t org, vec3_t dir, int color, int count);
|
||||
void CL_ParticleEffect2 (vec3_t org, vec3_t dir, int color, int count);
|
||||
|
||||
// RAFAEL
|
||||
void CL_ParticleEffect3 (vec3_t org, vec3_t dir, int color, int count);
|
||||
|
||||
|
||||
//=================================================
|
||||
|
||||
// ========
|
||||
// PGM
|
||||
typedef struct particle_s
|
||||
{
|
||||
struct particle_s *next;
|
||||
|
||||
float time;
|
||||
|
||||
vec3_t org;
|
||||
vec3_t vel;
|
||||
vec3_t accel;
|
||||
float color;
|
||||
float colorvel;
|
||||
float alpha;
|
||||
float alphavel;
|
||||
} cparticle_t;
|
||||
|
||||
|
||||
#define PARTICLE_GRAVITY 40
|
||||
#define BLASTER_PARTICLE_COLOR 0xe0
|
||||
// PMM
|
||||
#define INSTANT_PARTICLE -10000.0
|
||||
// PGM
|
||||
// ========
|
||||
|
||||
void CL_ClearEffects (void);
|
||||
void CL_ClearTEnts (void);
|
||||
void CL_BlasterTrail (vec3_t start, vec3_t end);
|
||||
void CL_QuadTrail (vec3_t start, vec3_t end);
|
||||
void CL_RailTrail (vec3_t start, vec3_t end);
|
||||
void CL_BubbleTrail (vec3_t start, vec3_t end);
|
||||
void CL_FlagTrail (vec3_t start, vec3_t end, float color);
|
||||
|
||||
// RAFAEL
|
||||
void CL_IonripperTrail (vec3_t start, vec3_t end);
|
||||
|
||||
// ========
|
||||
// PGM
|
||||
void CL_BlasterParticles2 (vec3_t org, vec3_t dir, unsigned int color);
|
||||
void CL_BlasterTrail2 (vec3_t start, vec3_t end);
|
||||
void CL_DebugTrail (vec3_t start, vec3_t end);
|
||||
void CL_SmokeTrail (vec3_t start, vec3_t end, int colorStart, int colorRun, int spacing);
|
||||
void CL_Flashlight (int ent, vec3_t pos);
|
||||
void CL_ForceWall (vec3_t start, vec3_t end, int color);
|
||||
void CL_FlameEffects (centity_t *ent, vec3_t origin);
|
||||
void CL_GenericParticleEffect (vec3_t org, vec3_t dir, int color, int count, int numcolors, int dirspread, float alphavel);
|
||||
void CL_BubbleTrail2 (vec3_t start, vec3_t end, int dist);
|
||||
void CL_Heatbeam (vec3_t start, vec3_t end);
|
||||
void CL_ParticleSteamEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude);
|
||||
void CL_TrackerTrail (vec3_t start, vec3_t end, int particleColor);
|
||||
void CL_Tracker_Explode(vec3_t origin);
|
||||
void CL_TagTrail (vec3_t start, vec3_t end, float color);
|
||||
void CL_ColorFlash (vec3_t pos, int ent, int intensity, float r, float g, float b);
|
||||
void CL_Tracker_Shell(vec3_t origin);
|
||||
void CL_MonsterPlasma_Shell(vec3_t origin);
|
||||
void CL_ColorExplosionParticles (vec3_t org, int color, int run);
|
||||
void CL_ParticleSmokeEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude);
|
||||
void CL_Widowbeamout (cl_sustain_t *self);
|
||||
void CL_Nukeblast (cl_sustain_t *self);
|
||||
void CL_WidowSplash (vec3_t org);
|
||||
// PGM
|
||||
// ========
|
||||
|
||||
int CL_ParseEntityBits (unsigned *bits);
|
||||
void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int number, int bits);
|
||||
void CL_ParseFrame (void);
|
||||
|
||||
void CL_ParseTEnt (void);
|
||||
void CL_ParseConfigString (void);
|
||||
void CL_ParseMuzzleFlash (void);
|
||||
void CL_ParseMuzzleFlash2 (void);
|
||||
void SmokeAndFlash(vec3_t origin);
|
||||
|
||||
void CL_SetLightstyle (int i);
|
||||
|
||||
void CL_RunParticles (void);
|
||||
void CL_RunDLights (void);
|
||||
void CL_RunLightStyles (void);
|
||||
|
||||
void CL_AddEntities (void);
|
||||
void CL_AddDLights (void);
|
||||
void CL_AddTEnts (void);
|
||||
void CL_AddLightStyles (void);
|
||||
|
||||
//=================================================
|
||||
|
||||
void CL_PrepRefresh (void);
|
||||
void CL_RegisterSounds (void);
|
||||
|
||||
void CL_Quit_f (void);
|
||||
|
||||
void IN_Accumulate (void);
|
||||
|
||||
void CL_ParseLayout (void);
|
||||
|
||||
|
||||
//
|
||||
// cl_main
|
||||
//
|
||||
extern refexport_t re; // interface to refresh .dll
|
||||
|
||||
void CL_Init (void);
|
||||
|
||||
void CL_FixUpGender(void);
|
||||
void CL_Disconnect (void);
|
||||
void CL_Disconnect_f (void);
|
||||
void CL_GetChallengePacket (void);
|
||||
void CL_PingServers_f (void);
|
||||
void CL_Snd_Restart_f (void);
|
||||
void CL_RequestNextDownload (void);
|
||||
|
||||
//
|
||||
// cl_input
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
int down[2]; // key nums holding it down
|
||||
unsigned downtime; // msec timestamp
|
||||
unsigned msec; // msec down this frame
|
||||
int state;
|
||||
} kbutton_t;
|
||||
|
||||
extern kbutton_t in_mlook, in_klook;
|
||||
extern kbutton_t in_strafe;
|
||||
extern kbutton_t in_speed;
|
||||
|
||||
void CL_InitInput (void);
|
||||
void CL_SendCmd (void);
|
||||
void CL_SendMove (usercmd_t *cmd);
|
||||
|
||||
void CL_ClearState (void);
|
||||
|
||||
void CL_ReadPackets (void);
|
||||
|
||||
int CL_ReadFromServer (void);
|
||||
void CL_WriteToServer (usercmd_t *cmd);
|
||||
void CL_BaseMove (usercmd_t *cmd);
|
||||
|
||||
void IN_CenterView (void);
|
||||
|
||||
float CL_KeyState (kbutton_t *key);
|
||||
char *Key_KeynumToString (int keynum);
|
||||
|
||||
//
|
||||
// cl_demo.c
|
||||
//
|
||||
void CL_WriteDemoMessage (void);
|
||||
void CL_Stop_f (void);
|
||||
void CL_Record_f (void);
|
||||
|
||||
//
|
||||
// cl_parse.c
|
||||
//
|
||||
extern char *svc_strings[256];
|
||||
|
||||
void CL_ParseServerMessage (void);
|
||||
void CL_LoadClientinfo (clientinfo_t *ci, char *s);
|
||||
void SHOWNET(char *s);
|
||||
void CL_ParseClientinfo (int player);
|
||||
void CL_Download_f (void);
|
||||
|
||||
//
|
||||
// cl_view.c
|
||||
//
|
||||
extern int gun_frame;
|
||||
extern struct model_s *gun_model;
|
||||
|
||||
void V_Init (void);
|
||||
void V_RenderView( float stereo_separation );
|
||||
void V_AddEntity (entity_t *ent);
|
||||
void V_AddParticle (vec3_t org, int color, float alpha);
|
||||
void V_AddLight (vec3_t org, float intensity, float r, float g, float b);
|
||||
void V_AddLightStyle (int style, float r, float g, float b);
|
||||
|
||||
//
|
||||
// cl_tent.c
|
||||
//
|
||||
void CL_RegisterTEntSounds (void);
|
||||
void CL_RegisterTEntModels (void);
|
||||
void CL_SmokeAndFlash(vec3_t origin);
|
||||
|
||||
|
||||
//
|
||||
// cl_pred.c
|
||||
//
|
||||
void CL_InitPrediction (void);
|
||||
void CL_PredictMove (void);
|
||||
void CL_CheckPredictionError (void);
|
||||
|
||||
//
|
||||
// cl_fx.c
|
||||
//
|
||||
cdlight_t *CL_AllocDlight (int key);
|
||||
void CL_BigTeleportParticles (vec3_t org);
|
||||
void CL_RocketTrail (vec3_t start, vec3_t end, centity_t *old);
|
||||
void CL_DiminishingTrail (vec3_t start, vec3_t end, centity_t *old, int flags);
|
||||
void CL_FlyEffect (centity_t *ent, vec3_t origin);
|
||||
void CL_BfgParticles (entity_t *ent);
|
||||
void CL_AddParticles (void);
|
||||
void CL_EntityEvent (entity_state_t *ent);
|
||||
// RAFAEL
|
||||
void CL_TrapParticles (entity_t *ent);
|
||||
|
||||
//
|
||||
// menus
|
||||
//
|
||||
void M_Init (void);
|
||||
void M_Keydown (int key);
|
||||
void M_Draw (void);
|
||||
void M_Menu_Main_f (void);
|
||||
void M_ForceMenuOff (void);
|
||||
void M_AddToServerList (netadr_t adr, char *info);
|
||||
|
||||
//
|
||||
// cl_inv.c
|
||||
//
|
||||
void CL_ParseInventory (void);
|
||||
void CL_KeyInventory (int key);
|
||||
void CL_DrawInventory (void);
|
||||
|
||||
//
|
||||
// cl_pred.c
|
||||
//
|
||||
void CL_PredictMovement (void);
|
||||
|
||||
#if id386
|
||||
void x86_TimerStart( void );
|
||||
void x86_TimerStop( void );
|
||||
void x86_TimerInit( unsigned long smallest, unsigned longest );
|
||||
unsigned long *x86_TimerGetHistogram( void );
|
||||
#endif
|
682
client/console.c
Normal file
682
client/console.c
Normal file
@ -0,0 +1,682 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// console.c
|
||||
|
||||
#include "client.h"
|
||||
|
||||
console_t con;
|
||||
|
||||
cvar_t *con_notifytime;
|
||||
|
||||
|
||||
#define MAXCMDLINE 256
|
||||
extern char key_lines[32][MAXCMDLINE];
|
||||
extern int edit_line;
|
||||
extern int key_linepos;
|
||||
|
||||
|
||||
void DrawString (int x, int y, char *s)
|
||||
{
|
||||
while (*s)
|
||||
{
|
||||
re.DrawChar (x, y, *s);
|
||||
x+=8;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawAltString (int x, int y, char *s)
|
||||
{
|
||||
while (*s)
|
||||
{
|
||||
re.DrawChar (x, y, *s ^ 0x80);
|
||||
x+=8;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Key_ClearTyping (void)
|
||||
{
|
||||
key_lines[edit_line][1] = 0; // clear any typing
|
||||
key_linepos = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_ToggleConsole_f
|
||||
================
|
||||
*/
|
||||
void Con_ToggleConsole_f (void)
|
||||
{
|
||||
SCR_EndLoadingPlaque (); // get rid of loading plaque
|
||||
|
||||
if (cl.attractloop)
|
||||
{
|
||||
Cbuf_AddText ("killserver\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cls.state == ca_disconnected)
|
||||
{ // start the demo loop again
|
||||
Cbuf_AddText ("d1\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Key_ClearTyping ();
|
||||
Con_ClearNotify ();
|
||||
|
||||
if (cls.key_dest == key_console)
|
||||
{
|
||||
M_ForceMenuOff ();
|
||||
Cvar_Set ("paused", "0");
|
||||
}
|
||||
else
|
||||
{
|
||||
M_ForceMenuOff ();
|
||||
cls.key_dest = key_console;
|
||||
|
||||
if (Cvar_VariableValue ("maxclients") == 1
|
||||
&& Com_ServerState ())
|
||||
Cvar_Set ("paused", "1");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_ToggleChat_f
|
||||
================
|
||||
*/
|
||||
void Con_ToggleChat_f (void)
|
||||
{
|
||||
Key_ClearTyping ();
|
||||
|
||||
if (cls.key_dest == key_console)
|
||||
{
|
||||
if (cls.state == ca_active)
|
||||
{
|
||||
M_ForceMenuOff ();
|
||||
cls.key_dest = key_game;
|
||||
}
|
||||
}
|
||||
else
|
||||
cls.key_dest = key_console;
|
||||
|
||||
Con_ClearNotify ();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_Clear_f
|
||||
================
|
||||
*/
|
||||
void Con_Clear_f (void)
|
||||
{
|
||||
memset (con.text, ' ', CON_TEXTSIZE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Con_Dump_f
|
||||
|
||||
Save the console contents out to a file
|
||||
================
|
||||
*/
|
||||
void Con_Dump_f (void)
|
||||
{
|
||||
int l, x;
|
||||
char *line;
|
||||
FILE *f;
|
||||
char buffer[1024];
|
||||
char name[MAX_OSPATH];
|
||||
|
||||
if (Cmd_Argc() != 2)
|
||||
{
|
||||
Com_Printf ("usage: condump <filename>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Com_sprintf (name, sizeof(name), "%s/%s.txt", FS_Gamedir(), Cmd_Argv(1));
|
||||
|
||||
Com_Printf ("Dumped console text to %s.\n", name);
|
||||
FS_CreatePath (name);
|
||||
f = fopen (name, "w");
|
||||
if (!f)
|
||||
{
|
||||
Com_Printf ("ERROR: couldn't open.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// skip empty lines
|
||||
for (l = con.current - con.totallines + 1 ; l <= con.current ; l++)
|
||||
{
|
||||
line = con.text + (l%con.totallines)*con.linewidth;
|
||||
for (x=0 ; x<con.linewidth ; x++)
|
||||
if (line[x] != ' ')
|
||||
break;
|
||||
if (x != con.linewidth)
|
||||
break;
|
||||
}
|
||||
|
||||
// write the remaining lines
|
||||
buffer[con.linewidth] = 0;
|
||||
for ( ; l <= con.current ; l++)
|
||||
{
|
||||
line = con.text + (l%con.totallines)*con.linewidth;
|
||||
strncpy (buffer, line, con.linewidth);
|
||||
for (x=con.linewidth-1 ; x>=0 ; x--)
|
||||
{
|
||||
if (buffer[x] == ' ')
|
||||
buffer[x] = 0;
|
||||
else
|
||||
break;
|
||||
}
|
||||
for (x=0; buffer[x]; x++)
|
||||
buffer[x] &= 0x7f;
|
||||
|
||||
fprintf (f, "%s\n", buffer);
|
||||
}
|
||||
|
||||
fclose (f);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Con_ClearNotify
|
||||
================
|
||||
*/
|
||||
void Con_ClearNotify (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<NUM_CON_TIMES ; i++)
|
||||
con.times[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Con_MessageMode_f
|
||||
================
|
||||
*/
|
||||
void Con_MessageMode_f (void)
|
||||
{
|
||||
chat_team = false;
|
||||
cls.key_dest = key_message;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_MessageMode2_f
|
||||
================
|
||||
*/
|
||||
void Con_MessageMode2_f (void)
|
||||
{
|
||||
chat_team = true;
|
||||
cls.key_dest = key_message;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_CheckResize
|
||||
|
||||
If the line width has changed, reformat the buffer.
|
||||
================
|
||||
*/
|
||||
void Con_CheckResize (void)
|
||||
{
|
||||
int i, j, width, oldwidth, oldtotallines, numlines, numchars;
|
||||
char tbuf[CON_TEXTSIZE];
|
||||
|
||||
width = (viddef.width >> 3) - 2;
|
||||
|
||||
if (width == con.linewidth)
|
||||
return;
|
||||
|
||||
if (width < 1) // video hasn't been initialized yet
|
||||
{
|
||||
width = 38;
|
||||
con.linewidth = width;
|
||||
con.totallines = CON_TEXTSIZE / con.linewidth;
|
||||
memset (con.text, ' ', CON_TEXTSIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
oldwidth = con.linewidth;
|
||||
con.linewidth = width;
|
||||
oldtotallines = con.totallines;
|
||||
con.totallines = CON_TEXTSIZE / con.linewidth;
|
||||
numlines = oldtotallines;
|
||||
|
||||
if (con.totallines < numlines)
|
||||
numlines = con.totallines;
|
||||
|
||||
numchars = oldwidth;
|
||||
|
||||
if (con.linewidth < numchars)
|
||||
numchars = con.linewidth;
|
||||
|
||||
memcpy (tbuf, con.text, CON_TEXTSIZE);
|
||||
memset (con.text, ' ', CON_TEXTSIZE);
|
||||
|
||||
for (i=0 ; i<numlines ; i++)
|
||||
{
|
||||
for (j=0 ; j<numchars ; j++)
|
||||
{
|
||||
con.text[(con.totallines - 1 - i) * con.linewidth + j] =
|
||||
tbuf[((con.current - i + oldtotallines) %
|
||||
oldtotallines) * oldwidth + j];
|
||||
}
|
||||
}
|
||||
|
||||
Con_ClearNotify ();
|
||||
}
|
||||
|
||||
con.current = con.totallines - 1;
|
||||
con.display = con.current;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Con_Init
|
||||
================
|
||||
*/
|
||||
void Con_Init (void)
|
||||
{
|
||||
con.linewidth = -1;
|
||||
|
||||
Con_CheckResize ();
|
||||
|
||||
Com_Printf ("Console initialized.\n");
|
||||
|
||||
//
|
||||
// register our commands
|
||||
//
|
||||
con_notifytime = Cvar_Get ("con_notifytime", "3", 0);
|
||||
|
||||
Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
|
||||
Cmd_AddCommand ("togglechat", Con_ToggleChat_f);
|
||||
Cmd_AddCommand ("messagemode", Con_MessageMode_f);
|
||||
Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
|
||||
Cmd_AddCommand ("clear", Con_Clear_f);
|
||||
Cmd_AddCommand ("condump", Con_Dump_f);
|
||||
con.initialized = true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
Con_Linefeed
|
||||
===============
|
||||
*/
|
||||
void Con_Linefeed (void)
|
||||
{
|
||||
con.x = 0;
|
||||
if (con.display == con.current)
|
||||
con.display++;
|
||||
con.current++;
|
||||
memset (&con.text[(con.current%con.totallines)*con.linewidth]
|
||||
, ' ', con.linewidth);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_Print
|
||||
|
||||
Handles cursor positioning, line wrapping, etc
|
||||
All console printing must go through this in order to be logged to disk
|
||||
If no console is visible, the text will appear at the top of the game window
|
||||
================
|
||||
*/
|
||||
void Con_Print (char *txt)
|
||||
{
|
||||
int y;
|
||||
int c, l;
|
||||
static int cr;
|
||||
int mask;
|
||||
|
||||
if (!con.initialized)
|
||||
return;
|
||||
|
||||
if (txt[0] == 1 || txt[0] == 2)
|
||||
{
|
||||
mask = 128; // go to colored text
|
||||
txt++;
|
||||
}
|
||||
else
|
||||
mask = 0;
|
||||
|
||||
|
||||
while ( (c = *txt) )
|
||||
{
|
||||
// count word length
|
||||
for (l=0 ; l< con.linewidth ; l++)
|
||||
if ( txt[l] <= ' ')
|
||||
break;
|
||||
|
||||
// word wrap
|
||||
if (l != con.linewidth && (con.x + l > con.linewidth) )
|
||||
con.x = 0;
|
||||
|
||||
txt++;
|
||||
|
||||
if (cr)
|
||||
{
|
||||
con.current--;
|
||||
cr = false;
|
||||
}
|
||||
|
||||
|
||||
if (!con.x)
|
||||
{
|
||||
Con_Linefeed ();
|
||||
// mark time for transparent overlay
|
||||
if (con.current >= 0)
|
||||
con.times[con.current % NUM_CON_TIMES] = cls.realtime;
|
||||
}
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\n':
|
||||
con.x = 0;
|
||||
break;
|
||||
|
||||
case '\r':
|
||||
con.x = 0;
|
||||
cr = 1;
|
||||
break;
|
||||
|
||||
default: // display character and advance
|
||||
y = con.current % con.totallines;
|
||||
con.text[y*con.linewidth+con.x] = c | mask | con.ormask;
|
||||
con.x++;
|
||||
if (con.x >= con.linewidth)
|
||||
con.x = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
Con_CenteredPrint
|
||||
==============
|
||||
*/
|
||||
void Con_CenteredPrint (char *text)
|
||||
{
|
||||
int l;
|
||||
char buffer[1024];
|
||||
|
||||
l = strlen(text);
|
||||
l = (con.linewidth-l)/2;
|
||||
if (l < 0)
|
||||
l = 0;
|
||||
memset (buffer, ' ', l);
|
||||
strcpy (buffer+l, text);
|
||||
strcat (buffer, "\n");
|
||||
Con_Print (buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
DRAWING
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Con_DrawInput
|
||||
|
||||
The input line scrolls horizontally if typing goes beyond the right edge
|
||||
================
|
||||
*/
|
||||
void Con_DrawInput (void)
|
||||
{
|
||||
int y;
|
||||
int i;
|
||||
char *text;
|
||||
|
||||
if (cls.key_dest == key_menu)
|
||||
return;
|
||||
if (cls.key_dest != key_console && cls.state == ca_active)
|
||||
return; // don't draw anything (always draw if not active)
|
||||
|
||||
text = key_lines[edit_line];
|
||||
|
||||
// add the cursor frame
|
||||
text[key_linepos] = 10+((int)(cls.realtime>>8)&1);
|
||||
|
||||
// fill out remainder with spaces
|
||||
for (i=key_linepos+1 ; i< con.linewidth ; i++)
|
||||
text[i] = ' ';
|
||||
|
||||
// prestep if horizontally scrolling
|
||||
if (key_linepos >= con.linewidth)
|
||||
text += 1 + key_linepos - con.linewidth;
|
||||
|
||||
// draw it
|
||||
y = con.vislines-16;
|
||||
|
||||
for (i=0 ; i<con.linewidth ; i++)
|
||||
re.DrawChar ( (i+1)<<3, con.vislines - 22, text[i]);
|
||||
|
||||
// remove cursor
|
||||
key_lines[edit_line][key_linepos] = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Con_DrawNotify
|
||||
|
||||
Draws the last few lines of output transparently over the game top
|
||||
================
|
||||
*/
|
||||
void Con_DrawNotify (void)
|
||||
{
|
||||
int x, v;
|
||||
char *text;
|
||||
int i;
|
||||
int time;
|
||||
char *s;
|
||||
int skip;
|
||||
|
||||
v = 0;
|
||||
for (i= con.current-NUM_CON_TIMES+1 ; i<=con.current ; i++)
|
||||
{
|
||||
if (i < 0)
|
||||
continue;
|
||||
time = con.times[i % NUM_CON_TIMES];
|
||||
if (time == 0)
|
||||
continue;
|
||||
time = cls.realtime - time;
|
||||
if (time > con_notifytime->value*1000)
|
||||
continue;
|
||||
text = con.text + (i % con.totallines)*con.linewidth;
|
||||
|
||||
for (x = 0 ; x < con.linewidth ; x++)
|
||||
re.DrawChar ( (x+1)<<3, v, text[x]);
|
||||
|
||||
v += 8;
|
||||
}
|
||||
|
||||
|
||||
if (cls.key_dest == key_message)
|
||||
{
|
||||
if (chat_team)
|
||||
{
|
||||
DrawString (8, v, "say_team:");
|
||||
skip = 11;
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawString (8, v, "say:");
|
||||
skip = 5;
|
||||
}
|
||||
|
||||
s = chat_buffer;
|
||||
if (chat_bufferlen > (viddef.width>>3)-(skip+1))
|
||||
s += chat_bufferlen - ((viddef.width>>3)-(skip+1));
|
||||
x = 0;
|
||||
while(s[x])
|
||||
{
|
||||
re.DrawChar ( (x+skip)<<3, v, s[x]);
|
||||
x++;
|
||||
}
|
||||
re.DrawChar ( (x+skip)<<3, v, 10+((cls.realtime>>8)&1));
|
||||
v += 8;
|
||||
}
|
||||
|
||||
if (v)
|
||||
{
|
||||
SCR_AddDirtyPoint (0,0);
|
||||
SCR_AddDirtyPoint (viddef.width-1, v);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_DrawConsole
|
||||
|
||||
Draws the console with the solid background
|
||||
================
|
||||
*/
|
||||
void Con_DrawConsole (float frac)
|
||||
{
|
||||
int i, j, x, y, n;
|
||||
int rows;
|
||||
char *text;
|
||||
int row;
|
||||
int lines;
|
||||
char version[64];
|
||||
char dlbar[1024];
|
||||
|
||||
lines = viddef.height * frac;
|
||||
if (lines <= 0)
|
||||
return;
|
||||
|
||||
if (lines > viddef.height)
|
||||
lines = viddef.height;
|
||||
|
||||
// draw the background
|
||||
re.DrawStretchPic (0, -viddef.height+lines, viddef.width, viddef.height, "conback");
|
||||
SCR_AddDirtyPoint (0,0);
|
||||
SCR_AddDirtyPoint (viddef.width-1,lines-1);
|
||||
|
||||
Com_sprintf (version, sizeof(version), "v%4.2f", VERSION);
|
||||
for (x=0 ; x<5 ; x++)
|
||||
re.DrawChar (viddef.width-44+x*8, lines-12, 128 + version[x] );
|
||||
|
||||
// draw the text
|
||||
con.vislines = lines;
|
||||
|
||||
#if 0
|
||||
rows = (lines-8)>>3; // rows of text to draw
|
||||
|
||||
y = lines - 24;
|
||||
#else
|
||||
rows = (lines-22)>>3; // rows of text to draw
|
||||
|
||||
y = lines - 30;
|
||||
#endif
|
||||
|
||||
// draw from the bottom up
|
||||
if (con.display != con.current)
|
||||
{
|
||||
// draw arrows to show the buffer is backscrolled
|
||||
for (x=0 ; x<con.linewidth ; x+=4)
|
||||
re.DrawChar ( (x+1)<<3, y, '^');
|
||||
|
||||
y -= 8;
|
||||
rows--;
|
||||
}
|
||||
|
||||
row = con.display;
|
||||
for (i=0 ; i<rows ; i++, y-=8, row--)
|
||||
{
|
||||
if (row < 0)
|
||||
break;
|
||||
if (con.current - row >= con.totallines)
|
||||
break; // past scrollback wrap point
|
||||
|
||||
text = con.text + (row % con.totallines)*con.linewidth;
|
||||
|
||||
for (x=0 ; x<con.linewidth ; x++)
|
||||
re.DrawChar ( (x+1)<<3, y, text[x]);
|
||||
}
|
||||
|
||||
//ZOID
|
||||
// draw the download bar
|
||||
// figure out width
|
||||
if (cls.download) {
|
||||
if ((text = strrchr(cls.downloadname, '/')) != NULL)
|
||||
text++;
|
||||
else
|
||||
text = cls.downloadname;
|
||||
|
||||
x = con.linewidth - ((con.linewidth * 7) / 40);
|
||||
y = x - strlen(text) - 8;
|
||||
i = con.linewidth/3;
|
||||
if (strlen(text) > i) {
|
||||
y = x - i - 11;
|
||||
strncpy(dlbar, text, i);
|
||||
dlbar[i] = 0;
|
||||
strcat(dlbar, "...");
|
||||
} else
|
||||
strcpy(dlbar, text);
|
||||
strcat(dlbar, ": ");
|
||||
i = strlen(dlbar);
|
||||
dlbar[i++] = '\x80';
|
||||
// where's the dot go?
|
||||
if (cls.downloadpercent == 0)
|
||||
n = 0;
|
||||
else
|
||||
n = y * cls.downloadpercent / 100;
|
||||
|
||||
for (j = 0; j < y; j++)
|
||||
if (j == n)
|
||||
dlbar[i++] = '\x83';
|
||||
else
|
||||
dlbar[i++] = '\x81';
|
||||
dlbar[i++] = '\x82';
|
||||
dlbar[i] = 0;
|
||||
|
||||
sprintf(dlbar + strlen(dlbar), " %02d%%", cls.downloadpercent);
|
||||
|
||||
// draw it
|
||||
y = con.vislines-12;
|
||||
for (i = 0; i < strlen(dlbar); i++)
|
||||
re.DrawChar ( (i+1)<<3, y, dlbar[i]);
|
||||
}
|
||||
//ZOID
|
||||
|
||||
// draw the input prompt, user text, and cursor if desired
|
||||
Con_DrawInput ();
|
||||
}
|
||||
|
||||
|
62
client/console.h
Normal file
62
client/console.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
//
|
||||
// console
|
||||
//
|
||||
|
||||
#define NUM_CON_TIMES 4
|
||||
|
||||
#define CON_TEXTSIZE 32768
|
||||
typedef struct
|
||||
{
|
||||
qboolean initialized;
|
||||
|
||||
char text[CON_TEXTSIZE];
|
||||
int current; // line where next message will be printed
|
||||
int x; // offset in current line for next print
|
||||
int display; // bottom of console displays this line
|
||||
|
||||
int ormask; // high bit mask for colored characters
|
||||
|
||||
int linewidth; // characters across screen
|
||||
int totallines; // total lines in console scrollback
|
||||
|
||||
float cursorspeed;
|
||||
|
||||
int vislines;
|
||||
|
||||
float times[NUM_CON_TIMES]; // cls.realtime time the line was generated
|
||||
// for transparent notify lines
|
||||
} console_t;
|
||||
|
||||
extern console_t con;
|
||||
|
||||
void Con_DrawCharacter (int cx, int line, int num);
|
||||
|
||||
void Con_CheckResize (void);
|
||||
void Con_Init (void);
|
||||
void Con_DrawConsole (float frac);
|
||||
void Con_Print (char *txt);
|
||||
void Con_CenteredPrint (char *text);
|
||||
void Con_Clear_f (void);
|
||||
void Con_DrawNotify (void);
|
||||
void Con_ClearNotify (void);
|
||||
void Con_ToggleConsole_f (void);
|
34
client/input.h
Normal file
34
client/input.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// input.h -- external (non-keyboard) input devices
|
||||
|
||||
void IN_Init (void);
|
||||
|
||||
void IN_Shutdown (void);
|
||||
|
||||
void IN_Commands (void);
|
||||
// oportunity for devices to stick commands on the script buffer
|
||||
|
||||
void IN_Frame (void);
|
||||
|
||||
void IN_Move (usercmd_t *cmd);
|
||||
// add additional movement on top of the keyboard move cmd
|
||||
|
||||
void IN_Activate (qboolean active);
|
943
client/keys.c
Normal file
943
client/keys.c
Normal file
@ -0,0 +1,943 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
#include "client.h"
|
||||
|
||||
/*
|
||||
|
||||
key up events are sent even if in console mode
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#define MAXCMDLINE 256
|
||||
char key_lines[32][MAXCMDLINE];
|
||||
int key_linepos;
|
||||
int shift_down=false;
|
||||
int anykeydown;
|
||||
|
||||
int edit_line=0;
|
||||
int history_line=0;
|
||||
|
||||
int key_waiting;
|
||||
char *keybindings[256];
|
||||
qboolean consolekeys[256]; // if true, can't be rebound while in console
|
||||
qboolean menubound[256]; // if true, can't be rebound while in menu
|
||||
int keyshift[256]; // key to map to if shift held down in console
|
||||
int key_repeats[256]; // if > 1, it is autorepeating
|
||||
qboolean keydown[256];
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
int keynum;
|
||||
} keyname_t;
|
||||
|
||||
keyname_t keynames[] =
|
||||
{
|
||||
{"TAB", K_TAB},
|
||||
{"ENTER", K_ENTER},
|
||||
{"ESCAPE", K_ESCAPE},
|
||||
{"SPACE", K_SPACE},
|
||||
{"BACKSPACE", K_BACKSPACE},
|
||||
{"UPARROW", K_UPARROW},
|
||||
{"DOWNARROW", K_DOWNARROW},
|
||||
{"LEFTARROW", K_LEFTARROW},
|
||||
{"RIGHTARROW", K_RIGHTARROW},
|
||||
|
||||
{"ALT", K_ALT},
|
||||
{"CTRL", K_CTRL},
|
||||
{"SHIFT", K_SHIFT},
|
||||
|
||||
{"F1", K_F1},
|
||||
{"F2", K_F2},
|
||||
{"F3", K_F3},
|
||||
{"F4", K_F4},
|
||||
{"F5", K_F5},
|
||||
{"F6", K_F6},
|
||||
{"F7", K_F7},
|
||||
{"F8", K_F8},
|
||||
{"F9", K_F9},
|
||||
{"F10", K_F10},
|
||||
{"F11", K_F11},
|
||||
{"F12", K_F12},
|
||||
|
||||
{"INS", K_INS},
|
||||
{"DEL", K_DEL},
|
||||
{"PGDN", K_PGDN},
|
||||
{"PGUP", K_PGUP},
|
||||
{"HOME", K_HOME},
|
||||
{"END", K_END},
|
||||
|
||||
{"MOUSE1", K_MOUSE1},
|
||||
{"MOUSE2", K_MOUSE2},
|
||||
{"MOUSE3", K_MOUSE3},
|
||||
|
||||
{"JOY1", K_JOY1},
|
||||
{"JOY2", K_JOY2},
|
||||
{"JOY3", K_JOY3},
|
||||
{"JOY4", K_JOY4},
|
||||
|
||||
{"AUX1", K_AUX1},
|
||||
{"AUX2", K_AUX2},
|
||||
{"AUX3", K_AUX3},
|
||||
{"AUX4", K_AUX4},
|
||||
{"AUX5", K_AUX5},
|
||||
{"AUX6", K_AUX6},
|
||||
{"AUX7", K_AUX7},
|
||||
{"AUX8", K_AUX8},
|
||||
{"AUX9", K_AUX9},
|
||||
{"AUX10", K_AUX10},
|
||||
{"AUX11", K_AUX11},
|
||||
{"AUX12", K_AUX12},
|
||||
{"AUX13", K_AUX13},
|
||||
{"AUX14", K_AUX14},
|
||||
{"AUX15", K_AUX15},
|
||||
{"AUX16", K_AUX16},
|
||||
{"AUX17", K_AUX17},
|
||||
{"AUX18", K_AUX18},
|
||||
{"AUX19", K_AUX19},
|
||||
{"AUX20", K_AUX20},
|
||||
{"AUX21", K_AUX21},
|
||||
{"AUX22", K_AUX22},
|
||||
{"AUX23", K_AUX23},
|
||||
{"AUX24", K_AUX24},
|
||||
{"AUX25", K_AUX25},
|
||||
{"AUX26", K_AUX26},
|
||||
{"AUX27", K_AUX27},
|
||||
{"AUX28", K_AUX28},
|
||||
{"AUX29", K_AUX29},
|
||||
{"AUX30", K_AUX30},
|
||||
{"AUX31", K_AUX31},
|
||||
{"AUX32", K_AUX32},
|
||||
|
||||
{"KP_HOME", K_KP_HOME },
|
||||
{"KP_UPARROW", K_KP_UPARROW },
|
||||
{"KP_PGUP", K_KP_PGUP },
|
||||
{"KP_LEFTARROW", K_KP_LEFTARROW },
|
||||
{"KP_5", K_KP_5 },
|
||||
{"KP_RIGHTARROW", K_KP_RIGHTARROW },
|
||||
{"KP_END", K_KP_END },
|
||||
{"KP_DOWNARROW", K_KP_DOWNARROW },
|
||||
{"KP_PGDN", K_KP_PGDN },
|
||||
{"KP_ENTER", K_KP_ENTER },
|
||||
{"KP_INS", K_KP_INS },
|
||||
{"KP_DEL", K_KP_DEL },
|
||||
{"KP_SLASH", K_KP_SLASH },
|
||||
{"KP_MINUS", K_KP_MINUS },
|
||||
{"KP_PLUS", K_KP_PLUS },
|
||||
|
||||
{"MWHEELUP", K_MWHEELUP },
|
||||
{"MWHEELDOWN", K_MWHEELDOWN },
|
||||
|
||||
{"PAUSE", K_PAUSE},
|
||||
|
||||
{"SEMICOLON", ';'}, // because a raw semicolon seperates commands
|
||||
|
||||
{NULL,0}
|
||||
};
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
LINE TYPING INTO THE CONSOLE
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
void CompleteCommand (void)
|
||||
{
|
||||
char *cmd, *s;
|
||||
|
||||
s = key_lines[edit_line]+1;
|
||||
if (*s == '\\' || *s == '/')
|
||||
s++;
|
||||
|
||||
cmd = Cmd_CompleteCommand (s);
|
||||
if (!cmd)
|
||||
cmd = Cvar_CompleteVariable (s);
|
||||
if (cmd)
|
||||
{
|
||||
key_lines[edit_line][1] = '/';
|
||||
strcpy (key_lines[edit_line]+2, cmd);
|
||||
key_linepos = strlen(cmd)+2;
|
||||
key_lines[edit_line][key_linepos] = ' ';
|
||||
key_linepos++;
|
||||
key_lines[edit_line][key_linepos] = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
Key_Console
|
||||
|
||||
Interactive line editing and console scrollback
|
||||
====================
|
||||
*/
|
||||
void Key_Console (int key)
|
||||
{
|
||||
|
||||
switch ( key )
|
||||
{
|
||||
case K_KP_SLASH:
|
||||
key = '/';
|
||||
break;
|
||||
case K_KP_MINUS:
|
||||
key = '-';
|
||||
break;
|
||||
case K_KP_PLUS:
|
||||
key = '+';
|
||||
break;
|
||||
case K_KP_HOME:
|
||||
key = '7';
|
||||
break;
|
||||
case K_KP_UPARROW:
|
||||
key = '8';
|
||||
break;
|
||||
case K_KP_PGUP:
|
||||
key = '9';
|
||||
break;
|
||||
case K_KP_LEFTARROW:
|
||||
key = '4';
|
||||
break;
|
||||
case K_KP_5:
|
||||
key = '5';
|
||||
break;
|
||||
case K_KP_RIGHTARROW:
|
||||
key = '6';
|
||||
break;
|
||||
case K_KP_END:
|
||||
key = '1';
|
||||
break;
|
||||
case K_KP_DOWNARROW:
|
||||
key = '2';
|
||||
break;
|
||||
case K_KP_PGDN:
|
||||
key = '3';
|
||||
break;
|
||||
case K_KP_INS:
|
||||
key = '0';
|
||||
break;
|
||||
case K_KP_DEL:
|
||||
key = '.';
|
||||
break;
|
||||
}
|
||||
|
||||
if ( ( toupper( key ) == 'V' && keydown[K_CTRL] ) ||
|
||||
( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keydown[K_SHIFT] ) )
|
||||
{
|
||||
char *cbd;
|
||||
|
||||
if ( ( cbd = Sys_GetClipboardData() ) != 0 )
|
||||
{
|
||||
int i;
|
||||
|
||||
strtok( cbd, "\n\r\b" );
|
||||
|
||||
i = strlen( cbd );
|
||||
if ( i + key_linepos >= MAXCMDLINE)
|
||||
i= MAXCMDLINE - key_linepos;
|
||||
|
||||
if ( i > 0 )
|
||||
{
|
||||
cbd[i]=0;
|
||||
strcat( key_lines[edit_line], cbd );
|
||||
key_linepos += i;
|
||||
}
|
||||
free( cbd );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( key == 'l' )
|
||||
{
|
||||
if ( keydown[K_CTRL] )
|
||||
{
|
||||
Cbuf_AddText ("clear\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( key == K_ENTER || key == K_KP_ENTER )
|
||||
{ // backslash text are commands, else chat
|
||||
if (key_lines[edit_line][1] == '\\' || key_lines[edit_line][1] == '/')
|
||||
Cbuf_AddText (key_lines[edit_line]+2); // skip the >
|
||||
else
|
||||
Cbuf_AddText (key_lines[edit_line]+1); // valid command
|
||||
|
||||
Cbuf_AddText ("\n");
|
||||
Com_Printf ("%s\n",key_lines[edit_line]);
|
||||
edit_line = (edit_line + 1) & 31;
|
||||
history_line = edit_line;
|
||||
key_lines[edit_line][0] = ']';
|
||||
key_linepos = 1;
|
||||
if (cls.state == ca_disconnected)
|
||||
SCR_UpdateScreen (); // force an update, because the command
|
||||
// may take some time
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == K_TAB)
|
||||
{ // command completion
|
||||
CompleteCommand ();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ( key == K_BACKSPACE ) || ( key == K_LEFTARROW ) || ( key == K_KP_LEFTARROW ) || ( ( key == 'h' ) && ( keydown[K_CTRL] ) ) )
|
||||
{
|
||||
if (key_linepos > 1)
|
||||
key_linepos--;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
|
||||
( ( key == 'p' ) && keydown[K_CTRL] ) )
|
||||
{
|
||||
do
|
||||
{
|
||||
history_line = (history_line - 1) & 31;
|
||||
} while (history_line != edit_line
|
||||
&& !key_lines[history_line][1]);
|
||||
if (history_line == edit_line)
|
||||
history_line = (edit_line+1)&31;
|
||||
strcpy(key_lines[edit_line], key_lines[history_line]);
|
||||
key_linepos = strlen(key_lines[edit_line]);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ||
|
||||
( ( key == 'n' ) && keydown[K_CTRL] ) )
|
||||
{
|
||||
if (history_line == edit_line) return;
|
||||
do
|
||||
{
|
||||
history_line = (history_line + 1) & 31;
|
||||
}
|
||||
while (history_line != edit_line
|
||||
&& !key_lines[history_line][1]);
|
||||
if (history_line == edit_line)
|
||||
{
|
||||
key_lines[edit_line][0] = ']';
|
||||
key_linepos = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(key_lines[edit_line], key_lines[history_line]);
|
||||
key_linepos = strlen(key_lines[edit_line]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == K_PGUP || key == K_KP_PGUP )
|
||||
{
|
||||
con.display -= 2;
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == K_PGDN || key == K_KP_PGDN )
|
||||
{
|
||||
con.display += 2;
|
||||
if (con.display > con.current)
|
||||
con.display = con.current;
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == K_HOME || key == K_KP_HOME )
|
||||
{
|
||||
con.display = con.current - con.totallines + 10;
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == K_END || key == K_KP_END )
|
||||
{
|
||||
con.display = con.current;
|
||||
return;
|
||||
}
|
||||
|
||||
if (key < 32 || key > 127)
|
||||
return; // non printable
|
||||
|
||||
if (key_linepos < MAXCMDLINE-1)
|
||||
{
|
||||
key_lines[edit_line][key_linepos] = key;
|
||||
key_linepos++;
|
||||
key_lines[edit_line][key_linepos] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
qboolean chat_team;
|
||||
char chat_buffer[MAXCMDLINE];
|
||||
int chat_bufferlen = 0;
|
||||
|
||||
void Key_Message (int key)
|
||||
{
|
||||
|
||||
if ( key == K_ENTER || key == K_KP_ENTER )
|
||||
{
|
||||
if (chat_team)
|
||||
Cbuf_AddText ("say_team \"");
|
||||
else
|
||||
Cbuf_AddText ("say \"");
|
||||
Cbuf_AddText(chat_buffer);
|
||||
Cbuf_AddText("\"\n");
|
||||
|
||||
cls.key_dest = key_game;
|
||||
chat_bufferlen = 0;
|
||||
chat_buffer[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == K_ESCAPE)
|
||||
{
|
||||
cls.key_dest = key_game;
|
||||
chat_bufferlen = 0;
|
||||
chat_buffer[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (key < 32 || key > 127)
|
||||
return; // non printable
|
||||
|
||||
if (key == K_BACKSPACE)
|
||||
{
|
||||
if (chat_bufferlen)
|
||||
{
|
||||
chat_bufferlen--;
|
||||
chat_buffer[chat_bufferlen] = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (chat_bufferlen == sizeof(chat_buffer)-1)
|
||||
return; // all full
|
||||
|
||||
chat_buffer[chat_bufferlen++] = key;
|
||||
chat_buffer[chat_bufferlen] = 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
Key_StringToKeynum
|
||||
|
||||
Returns a key number to be used to index keybindings[] by looking at
|
||||
the given string. Single ascii characters return themselves, while
|
||||
the K_* names are matched up.
|
||||
===================
|
||||
*/
|
||||
int Key_StringToKeynum (char *str)
|
||||
{
|
||||
keyname_t *kn;
|
||||
|
||||
if (!str || !str[0])
|
||||
return -1;
|
||||
if (!str[1])
|
||||
return str[0];
|
||||
|
||||
for (kn=keynames ; kn->name ; kn++)
|
||||
{
|
||||
if (!Q_strcasecmp(str,kn->name))
|
||||
return kn->keynum;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
Key_KeynumToString
|
||||
|
||||
Returns a string (either a single ascii char, or a K_* name) for the
|
||||
given keynum.
|
||||
FIXME: handle quote special (general escape sequence?)
|
||||
===================
|
||||
*/
|
||||
char *Key_KeynumToString (int keynum)
|
||||
{
|
||||
keyname_t *kn;
|
||||
static char tinystr[2];
|
||||
|
||||
if (keynum == -1)
|
||||
return "<KEY NOT FOUND>";
|
||||
if (keynum > 32 && keynum < 127)
|
||||
{ // printable ascii
|
||||
tinystr[0] = keynum;
|
||||
tinystr[1] = 0;
|
||||
return tinystr;
|
||||
}
|
||||
|
||||
for (kn=keynames ; kn->name ; kn++)
|
||||
if (keynum == kn->keynum)
|
||||
return kn->name;
|
||||
|
||||
return "<UNKNOWN KEYNUM>";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
Key_SetBinding
|
||||
===================
|
||||
*/
|
||||
void Key_SetBinding (int keynum, char *binding)
|
||||
{
|
||||
char *new;
|
||||
int l;
|
||||
|
||||
if (keynum == -1)
|
||||
return;
|
||||
|
||||
// free old bindings
|
||||
if (keybindings[keynum])
|
||||
{
|
||||
Z_Free (keybindings[keynum]);
|
||||
keybindings[keynum] = NULL;
|
||||
}
|
||||
|
||||
// allocate memory for new binding
|
||||
l = strlen (binding);
|
||||
new = Z_Malloc (l+1);
|
||||
strcpy (new, binding);
|
||||
new[l] = 0;
|
||||
keybindings[keynum] = new;
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
Key_Unbind_f
|
||||
===================
|
||||
*/
|
||||
void Key_Unbind_f (void)
|
||||
{
|
||||
int b;
|
||||
|
||||
if (Cmd_Argc() != 2)
|
||||
{
|
||||
Com_Printf ("unbind <key> : remove commands from a key\n");
|
||||
return;
|
||||
}
|
||||
|
||||
b = Key_StringToKeynum (Cmd_Argv(1));
|
||||
if (b==-1)
|
||||
{
|
||||
Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
|
||||
return;
|
||||
}
|
||||
|
||||
Key_SetBinding (b, "");
|
||||
}
|
||||
|
||||
void Key_Unbindall_f (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<256 ; i++)
|
||||
if (keybindings[i])
|
||||
Key_SetBinding (i, "");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
Key_Bind_f
|
||||
===================
|
||||
*/
|
||||
void Key_Bind_f (void)
|
||||
{
|
||||
int i, c, b;
|
||||
char cmd[1024];
|
||||
|
||||
c = Cmd_Argc();
|
||||
|
||||
if (c < 2)
|
||||
{
|
||||
Com_Printf ("bind <key> [command] : attach a command to a key\n");
|
||||
return;
|
||||
}
|
||||
b = Key_StringToKeynum (Cmd_Argv(1));
|
||||
if (b==-1)
|
||||
{
|
||||
Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
|
||||
return;
|
||||
}
|
||||
|
||||
if (c == 2)
|
||||
{
|
||||
if (keybindings[b])
|
||||
Com_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] );
|
||||
else
|
||||
Com_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );
|
||||
return;
|
||||
}
|
||||
|
||||
// copy the rest of the command line
|
||||
cmd[0] = 0; // start out with a null string
|
||||
for (i=2 ; i< c ; i++)
|
||||
{
|
||||
strcat (cmd, Cmd_Argv(i));
|
||||
if (i != (c-1))
|
||||
strcat (cmd, " ");
|
||||
}
|
||||
|
||||
Key_SetBinding (b, cmd);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Key_WriteBindings
|
||||
|
||||
Writes lines containing "bind key value"
|
||||
============
|
||||
*/
|
||||
void Key_WriteBindings (FILE *f)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<256 ; i++)
|
||||
if (keybindings[i] && keybindings[i][0])
|
||||
fprintf (f, "bind %s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Key_Bindlist_f
|
||||
|
||||
============
|
||||
*/
|
||||
void Key_Bindlist_f (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<256 ; i++)
|
||||
if (keybindings[i] && keybindings[i][0])
|
||||
Com_Printf ("%s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
Key_Init
|
||||
===================
|
||||
*/
|
||||
void Key_Init (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<32 ; i++)
|
||||
{
|
||||
key_lines[i][0] = ']';
|
||||
key_lines[i][1] = 0;
|
||||
}
|
||||
key_linepos = 1;
|
||||
|
||||
//
|
||||
// init ascii characters in console mode
|
||||
//
|
||||
for (i=32 ; i<128 ; i++)
|
||||
consolekeys[i] = true;
|
||||
consolekeys[K_ENTER] = true;
|
||||
consolekeys[K_KP_ENTER] = true;
|
||||
consolekeys[K_TAB] = true;
|
||||
consolekeys[K_LEFTARROW] = true;
|
||||
consolekeys[K_KP_LEFTARROW] = true;
|
||||
consolekeys[K_RIGHTARROW] = true;
|
||||
consolekeys[K_KP_RIGHTARROW] = true;
|
||||
consolekeys[K_UPARROW] = true;
|
||||
consolekeys[K_KP_UPARROW] = true;
|
||||
consolekeys[K_DOWNARROW] = true;
|
||||
consolekeys[K_KP_DOWNARROW] = true;
|
||||
consolekeys[K_BACKSPACE] = true;
|
||||
consolekeys[K_HOME] = true;
|
||||
consolekeys[K_KP_HOME] = true;
|
||||
consolekeys[K_END] = true;
|
||||
consolekeys[K_KP_END] = true;
|
||||
consolekeys[K_PGUP] = true;
|
||||
consolekeys[K_KP_PGUP] = true;
|
||||
consolekeys[K_PGDN] = true;
|
||||
consolekeys[K_KP_PGDN] = true;
|
||||
consolekeys[K_SHIFT] = true;
|
||||
consolekeys[K_INS] = true;
|
||||
consolekeys[K_KP_INS] = true;
|
||||
consolekeys[K_KP_DEL] = true;
|
||||
consolekeys[K_KP_SLASH] = true;
|
||||
consolekeys[K_KP_PLUS] = true;
|
||||
consolekeys[K_KP_MINUS] = true;
|
||||
consolekeys[K_KP_5] = true;
|
||||
|
||||
consolekeys['`'] = false;
|
||||
consolekeys['~'] = false;
|
||||
|
||||
for (i=0 ; i<256 ; i++)
|
||||
keyshift[i] = i;
|
||||
for (i='a' ; i<='z' ; i++)
|
||||
keyshift[i] = i - 'a' + 'A';
|
||||
keyshift['1'] = '!';
|
||||
keyshift['2'] = '@';
|
||||
keyshift['3'] = '#';
|
||||
keyshift['4'] = '$';
|
||||
keyshift['5'] = '%';
|
||||
keyshift['6'] = '^';
|
||||
keyshift['7'] = '&';
|
||||
keyshift['8'] = '*';
|
||||
keyshift['9'] = '(';
|
||||
keyshift['0'] = ')';
|
||||
keyshift['-'] = '_';
|
||||
keyshift['='] = '+';
|
||||
keyshift[','] = '<';
|
||||
keyshift['.'] = '>';
|
||||
keyshift['/'] = '?';
|
||||
keyshift[';'] = ':';
|
||||
keyshift['\''] = '"';
|
||||
keyshift['['] = '{';
|
||||
keyshift[']'] = '}';
|
||||
keyshift['`'] = '~';
|
||||
keyshift['\\'] = '|';
|
||||
|
||||
menubound[K_ESCAPE] = true;
|
||||
for (i=0 ; i<12 ; i++)
|
||||
menubound[K_F1+i] = true;
|
||||
|
||||
//
|
||||
// register our functions
|
||||
//
|
||||
Cmd_AddCommand ("bind",Key_Bind_f);
|
||||
Cmd_AddCommand ("unbind",Key_Unbind_f);
|
||||
Cmd_AddCommand ("unbindall",Key_Unbindall_f);
|
||||
Cmd_AddCommand ("bindlist",Key_Bindlist_f);
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
Key_Event
|
||||
|
||||
Called by the system between frames for both key up and key down events
|
||||
Should NOT be called during an interrupt!
|
||||
===================
|
||||
*/
|
||||
void Key_Event (int key, qboolean down, unsigned time)
|
||||
{
|
||||
char *kb;
|
||||
char cmd[1024];
|
||||
|
||||
// hack for modal presses
|
||||
if (key_waiting == -1)
|
||||
{
|
||||
if (down)
|
||||
key_waiting = key;
|
||||
return;
|
||||
}
|
||||
|
||||
// update auto-repeat status
|
||||
if (down)
|
||||
{
|
||||
key_repeats[key]++;
|
||||
if (key != K_BACKSPACE
|
||||
&& key != K_PAUSE
|
||||
&& key != K_PGUP
|
||||
&& key != K_KP_PGUP
|
||||
&& key != K_PGDN
|
||||
&& key != K_KP_PGDN
|
||||
&& key_repeats[key] > 1)
|
||||
return; // ignore most autorepeats
|
||||
|
||||
if (key >= 200 && !keybindings[key])
|
||||
Com_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) );
|
||||
}
|
||||
else
|
||||
{
|
||||
key_repeats[key] = 0;
|
||||
}
|
||||
|
||||
if (key == K_SHIFT)
|
||||
shift_down = down;
|
||||
|
||||
// console key is hardcoded, so the user can never unbind it
|
||||
if (key == '`' || key == '~')
|
||||
{
|
||||
if (!down)
|
||||
return;
|
||||
Con_ToggleConsole_f ();
|
||||
return;
|
||||
}
|
||||
|
||||
// any key during the attract mode will bring up the menu
|
||||
if (cl.attractloop && cls.key_dest != key_menu)
|
||||
key = K_ESCAPE;
|
||||
|
||||
// menu key is hardcoded, so the user can never unbind it
|
||||
if (key == K_ESCAPE)
|
||||
{
|
||||
if (!down)
|
||||
return;
|
||||
|
||||
if (cl.frame.playerstate.stats[STAT_LAYOUTS] && cls.key_dest == key_game)
|
||||
{ // put away help computer / inventory
|
||||
Cbuf_AddText ("cmd putaway\n");
|
||||
return;
|
||||
}
|
||||
switch (cls.key_dest)
|
||||
{
|
||||
case key_message:
|
||||
Key_Message (key);
|
||||
break;
|
||||
case key_menu:
|
||||
M_Keydown (key);
|
||||
break;
|
||||
case key_game:
|
||||
case key_console:
|
||||
M_Menu_Main_f ();
|
||||
break;
|
||||
default:
|
||||
Com_Error (ERR_FATAL, "Bad cls.key_dest");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// track if any key is down for BUTTON_ANY
|
||||
keydown[key] = down;
|
||||
if (down)
|
||||
{
|
||||
if (key_repeats[key] == 1)
|
||||
anykeydown++;
|
||||
}
|
||||
else
|
||||
{
|
||||
anykeydown--;
|
||||
if (anykeydown < 0)
|
||||
anykeydown = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// key up events only generate commands if the game key binding is
|
||||
// a button command (leading + sign). These will occur even in console mode,
|
||||
// to keep the character from continuing an action started before a console
|
||||
// switch. Button commands include the kenum as a parameter, so multiple
|
||||
// downs can be matched with ups
|
||||
//
|
||||
if (!down)
|
||||
{
|
||||
kb = keybindings[key];
|
||||
if (kb && kb[0] == '+')
|
||||
{
|
||||
Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
|
||||
Cbuf_AddText (cmd);
|
||||
}
|
||||
if (keyshift[key] != key)
|
||||
{
|
||||
kb = keybindings[keyshift[key]];
|
||||
if (kb && kb[0] == '+')
|
||||
{
|
||||
Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
|
||||
Cbuf_AddText (cmd);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// if not a consolekey, send to the interpreter no matter what mode is
|
||||
//
|
||||
if ( (cls.key_dest == key_menu && menubound[key])
|
||||
|| (cls.key_dest == key_console && !consolekeys[key])
|
||||
|| (cls.key_dest == key_game && ( cls.state == ca_active || !consolekeys[key] ) ) )
|
||||
{
|
||||
kb = keybindings[key];
|
||||
if (kb)
|
||||
{
|
||||
if (kb[0] == '+')
|
||||
{ // button commands add keynum and time as a parm
|
||||
Com_sprintf (cmd, sizeof(cmd), "%s %i %i\n", kb, key, time);
|
||||
Cbuf_AddText (cmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
Cbuf_AddText (kb);
|
||||
Cbuf_AddText ("\n");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!down)
|
||||
return; // other systems only care about key down events
|
||||
|
||||
if (shift_down)
|
||||
key = keyshift[key];
|
||||
|
||||
switch (cls.key_dest)
|
||||
{
|
||||
case key_message:
|
||||
Key_Message (key);
|
||||
break;
|
||||
case key_menu:
|
||||
M_Keydown (key);
|
||||
break;
|
||||
|
||||
case key_game:
|
||||
case key_console:
|
||||
Key_Console (key);
|
||||
break;
|
||||
default:
|
||||
Com_Error (ERR_FATAL, "Bad cls.key_dest");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
Key_ClearStates
|
||||
===================
|
||||
*/
|
||||
void Key_ClearStates (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
anykeydown = false;
|
||||
|
||||
for (i=0 ; i<256 ; i++)
|
||||
{
|
||||
if ( keydown[i] || key_repeats[i] )
|
||||
Key_Event( i, false, 0 );
|
||||
keydown[i] = 0;
|
||||
key_repeats[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
Key_GetKey
|
||||
===================
|
||||
*/
|
||||
int Key_GetKey (void)
|
||||
{
|
||||
key_waiting = -1;
|
||||
|
||||
while (key_waiting == -1)
|
||||
Sys_SendKeyEvents ();
|
||||
|
||||
return key_waiting;
|
||||
}
|
||||
|
146
client/keys.h
Normal file
146
client/keys.h
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
//
|
||||
// these are the key numbers that should be passed to Key_Event
|
||||
//
|
||||
#define K_TAB 9
|
||||
#define K_ENTER 13
|
||||
#define K_ESCAPE 27
|
||||
#define K_SPACE 32
|
||||
|
||||
// normal keys should be passed as lowercased ascii
|
||||
|
||||
#define K_BACKSPACE 127
|
||||
#define K_UPARROW 128
|
||||
#define K_DOWNARROW 129
|
||||
#define K_LEFTARROW 130
|
||||
#define K_RIGHTARROW 131
|
||||
|
||||
#define K_ALT 132
|
||||
#define K_CTRL 133
|
||||
#define K_SHIFT 134
|
||||
#define K_F1 135
|
||||
#define K_F2 136
|
||||
#define K_F3 137
|
||||
#define K_F4 138
|
||||
#define K_F5 139
|
||||
#define K_F6 140
|
||||
#define K_F7 141
|
||||
#define K_F8 142
|
||||
#define K_F9 143
|
||||
#define K_F10 144
|
||||
#define K_F11 145
|
||||
#define K_F12 146
|
||||
#define K_INS 147
|
||||
#define K_DEL 148
|
||||
#define K_PGDN 149
|
||||
#define K_PGUP 150
|
||||
#define K_HOME 151
|
||||
#define K_END 152
|
||||
|
||||
#define K_KP_HOME 160
|
||||
#define K_KP_UPARROW 161
|
||||
#define K_KP_PGUP 162
|
||||
#define K_KP_LEFTARROW 163
|
||||
#define K_KP_5 164
|
||||
#define K_KP_RIGHTARROW 165
|
||||
#define K_KP_END 166
|
||||
#define K_KP_DOWNARROW 167
|
||||
#define K_KP_PGDN 168
|
||||
#define K_KP_ENTER 169
|
||||
#define K_KP_INS 170
|
||||
#define K_KP_DEL 171
|
||||
#define K_KP_SLASH 172
|
||||
#define K_KP_MINUS 173
|
||||
#define K_KP_PLUS 174
|
||||
|
||||
#define K_PAUSE 255
|
||||
|
||||
//
|
||||
// mouse buttons generate virtual keys
|
||||
//
|
||||
#define K_MOUSE1 200
|
||||
#define K_MOUSE2 201
|
||||
#define K_MOUSE3 202
|
||||
|
||||
//
|
||||
// joystick buttons
|
||||
//
|
||||
#define K_JOY1 203
|
||||
#define K_JOY2 204
|
||||
#define K_JOY3 205
|
||||
#define K_JOY4 206
|
||||
|
||||
//
|
||||
// aux keys are for multi-buttoned joysticks to generate so they can use
|
||||
// the normal binding process
|
||||
//
|
||||
#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_MWHEELDOWN 239
|
||||
#define K_MWHEELUP 240
|
||||
|
||||
extern char *keybindings[256];
|
||||
extern int key_repeats[256];
|
||||
|
||||
extern int anykeydown;
|
||||
extern char chat_buffer[];
|
||||
extern int chat_bufferlen;
|
||||
extern qboolean chat_team;
|
||||
|
||||
void Key_Event (int key, qboolean down, unsigned time);
|
||||
void Key_Init (void);
|
||||
void Key_WriteBindings (FILE *f);
|
||||
void Key_SetBinding (int keynum, char *binding);
|
||||
void Key_ClearStates (void);
|
||||
int Key_GetKey (void);
|
||||
|
4016
client/menu.c
Normal file
4016
client/menu.c
Normal file
File diff suppressed because it is too large
Load Diff
674
client/qmenu.c
Normal file
674
client/qmenu.c
Normal file
@ -0,0 +1,674 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "client.h"
|
||||
#include "qmenu.h"
|
||||
|
||||
static void Action_DoEnter( menuaction_s *a );
|
||||
static void Action_Draw( menuaction_s *a );
|
||||
static void Menu_DrawStatusBar( const char *string );
|
||||
static void Menulist_DoEnter( menulist_s *l );
|
||||
static void MenuList_Draw( menulist_s *l );
|
||||
static void Separator_Draw( menuseparator_s *s );
|
||||
static void Slider_DoSlide( menuslider_s *s, int dir );
|
||||
static void Slider_Draw( menuslider_s *s );
|
||||
static void SpinControl_DoEnter( menulist_s *s );
|
||||
static void SpinControl_Draw( menulist_s *s );
|
||||
static void SpinControl_DoSlide( menulist_s *s, int dir );
|
||||
|
||||
#define RCOLUMN_OFFSET 16
|
||||
#define LCOLUMN_OFFSET -16
|
||||
|
||||
extern refexport_t re;
|
||||
extern viddef_t viddef;
|
||||
|
||||
#define VID_WIDTH viddef.width
|
||||
#define VID_HEIGHT viddef.height
|
||||
|
||||
#define Draw_Char re.DrawChar
|
||||
#define Draw_Fill re.DrawFill
|
||||
|
||||
void Action_DoEnter( menuaction_s *a )
|
||||
{
|
||||
if ( a->generic.callback )
|
||||
a->generic.callback( a );
|
||||
}
|
||||
|
||||
void Action_Draw( menuaction_s *a )
|
||||
{
|
||||
if ( a->generic.flags & QMF_LEFT_JUSTIFY )
|
||||
{
|
||||
if ( a->generic.flags & QMF_GRAYED )
|
||||
Menu_DrawStringDark( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
|
||||
else
|
||||
Menu_DrawString( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( a->generic.flags & QMF_GRAYED )
|
||||
Menu_DrawStringR2LDark( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
|
||||
else
|
||||
Menu_DrawStringR2L( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name );
|
||||
}
|
||||
if ( a->generic.ownerdraw )
|
||||
a->generic.ownerdraw( a );
|
||||
}
|
||||
|
||||
qboolean Field_DoEnter( menufield_s *f )
|
||||
{
|
||||
if ( f->generic.callback )
|
||||
{
|
||||
f->generic.callback( f );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Field_Draw( menufield_s *f )
|
||||
{
|
||||
int i;
|
||||
char tempbuffer[128]="";
|
||||
|
||||
if ( f->generic.name )
|
||||
Menu_DrawStringR2LDark( f->generic.x + f->generic.parent->x + LCOLUMN_OFFSET, f->generic.y + f->generic.parent->y, f->generic.name );
|
||||
|
||||
strncpy( tempbuffer, f->buffer + f->visible_offset, f->visible_length );
|
||||
|
||||
Draw_Char( f->generic.x + f->generic.parent->x + 16, f->generic.y + f->generic.parent->y - 4, 18 );
|
||||
Draw_Char( f->generic.x + f->generic.parent->x + 16, f->generic.y + f->generic.parent->y + 4, 24 );
|
||||
|
||||
Draw_Char( f->generic.x + f->generic.parent->x + 24 + f->visible_length * 8, f->generic.y + f->generic.parent->y - 4, 20 );
|
||||
Draw_Char( f->generic.x + f->generic.parent->x + 24 + f->visible_length * 8, f->generic.y + f->generic.parent->y + 4, 26 );
|
||||
|
||||
for ( i = 0; i < f->visible_length; i++ )
|
||||
{
|
||||
Draw_Char( f->generic.x + f->generic.parent->x + 24 + i * 8, f->generic.y + f->generic.parent->y - 4, 19 );
|
||||
Draw_Char( f->generic.x + f->generic.parent->x + 24 + i * 8, f->generic.y + f->generic.parent->y + 4, 25 );
|
||||
}
|
||||
|
||||
Menu_DrawString( f->generic.x + f->generic.parent->x + 24, f->generic.y + f->generic.parent->y, tempbuffer );
|
||||
|
||||
if ( Menu_ItemAtCursor( f->generic.parent ) == f )
|
||||
{
|
||||
int offset;
|
||||
|
||||
if ( f->visible_offset )
|
||||
offset = f->visible_length;
|
||||
else
|
||||
offset = f->cursor;
|
||||
|
||||
if ( ( ( int ) ( Sys_Milliseconds() / 250 ) ) & 1 )
|
||||
{
|
||||
Draw_Char( f->generic.x + f->generic.parent->x + ( offset + 2 ) * 8 + 8,
|
||||
f->generic.y + f->generic.parent->y,
|
||||
11 );
|
||||
}
|
||||
else
|
||||
{
|
||||
Draw_Char( f->generic.x + f->generic.parent->x + ( offset + 2 ) * 8 + 8,
|
||||
f->generic.y + f->generic.parent->y,
|
||||
' ' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qboolean Field_Key( menufield_s *f, int key )
|
||||
{
|
||||
extern int keydown[];
|
||||
|
||||
switch ( key )
|
||||
{
|
||||
case K_KP_SLASH:
|
||||
key = '/';
|
||||
break;
|
||||
case K_KP_MINUS:
|
||||
key = '-';
|
||||
break;
|
||||
case K_KP_PLUS:
|
||||
key = '+';
|
||||
break;
|
||||
case K_KP_HOME:
|
||||
key = '7';
|
||||
break;
|
||||
case K_KP_UPARROW:
|
||||
key = '8';
|
||||
break;
|
||||
case K_KP_PGUP:
|
||||
key = '9';
|
||||
break;
|
||||
case K_KP_LEFTARROW:
|
||||
key = '4';
|
||||
break;
|
||||
case K_KP_5:
|
||||
key = '5';
|
||||
break;
|
||||
case K_KP_RIGHTARROW:
|
||||
key = '6';
|
||||
break;
|
||||
case K_KP_END:
|
||||
key = '1';
|
||||
break;
|
||||
case K_KP_DOWNARROW:
|
||||
key = '2';
|
||||
break;
|
||||
case K_KP_PGDN:
|
||||
key = '3';
|
||||
break;
|
||||
case K_KP_INS:
|
||||
key = '0';
|
||||
break;
|
||||
case K_KP_DEL:
|
||||
key = '.';
|
||||
break;
|
||||
}
|
||||
|
||||
if ( key > 127 )
|
||||
{
|
||||
switch ( key )
|
||||
{
|
||||
case K_DEL:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** support pasting from the clipboard
|
||||
*/
|
||||
if ( ( toupper( key ) == 'V' && keydown[K_CTRL] ) ||
|
||||
( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keydown[K_SHIFT] ) )
|
||||
{
|
||||
char *cbd;
|
||||
|
||||
if ( ( cbd = Sys_GetClipboardData() ) != 0 )
|
||||
{
|
||||
strtok( cbd, "\n\r\b" );
|
||||
|
||||
strncpy( f->buffer, cbd, f->length - 1 );
|
||||
f->cursor = strlen( f->buffer );
|
||||
f->visible_offset = f->cursor - f->visible_length;
|
||||
if ( f->visible_offset < 0 )
|
||||
f->visible_offset = 0;
|
||||
|
||||
free( cbd );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
switch ( key )
|
||||
{
|
||||
case K_KP_LEFTARROW:
|
||||
case K_LEFTARROW:
|
||||
case K_BACKSPACE:
|
||||
if ( f->cursor > 0 )
|
||||
{
|
||||
memmove( &f->buffer[f->cursor-1], &f->buffer[f->cursor], strlen( &f->buffer[f->cursor] ) + 1 );
|
||||
f->cursor--;
|
||||
|
||||
if ( f->visible_offset )
|
||||
{
|
||||
f->visible_offset--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case K_KP_DEL:
|
||||
case K_DEL:
|
||||
memmove( &f->buffer[f->cursor], &f->buffer[f->cursor+1], strlen( &f->buffer[f->cursor+1] ) + 1 );
|
||||
break;
|
||||
|
||||
case K_KP_ENTER:
|
||||
case K_ENTER:
|
||||
case K_ESCAPE:
|
||||
case K_TAB:
|
||||
return false;
|
||||
|
||||
case K_SPACE:
|
||||
default:
|
||||
if ( !isdigit( key ) && ( f->generic.flags & QMF_NUMBERSONLY ) )
|
||||
return false;
|
||||
|
||||
if ( f->cursor < f->length )
|
||||
{
|
||||
f->buffer[f->cursor++] = key;
|
||||
f->buffer[f->cursor] = 0;
|
||||
|
||||
if ( f->cursor > f->visible_length )
|
||||
{
|
||||
f->visible_offset++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Menu_AddItem( menuframework_s *menu, void *item )
|
||||
{
|
||||
if ( menu->nitems == 0 )
|
||||
menu->nslots = 0;
|
||||
|
||||
if ( menu->nitems < MAXMENUITEMS )
|
||||
{
|
||||
menu->items[menu->nitems] = item;
|
||||
( ( menucommon_s * ) menu->items[menu->nitems] )->parent = menu;
|
||||
menu->nitems++;
|
||||
}
|
||||
|
||||
menu->nslots = Menu_TallySlots( menu );
|
||||
}
|
||||
|
||||
/*
|
||||
** Menu_AdjustCursor
|
||||
**
|
||||
** This function takes the given menu, the direction, and attempts
|
||||
** to adjust the menu's cursor so that it's at the next available
|
||||
** slot.
|
||||
*/
|
||||
void Menu_AdjustCursor( menuframework_s *m, int dir )
|
||||
{
|
||||
menucommon_s *citem;
|
||||
|
||||
/*
|
||||
** see if it's in a valid spot
|
||||
*/
|
||||
if ( m->cursor >= 0 && m->cursor < m->nitems )
|
||||
{
|
||||
if ( ( citem = Menu_ItemAtCursor( m ) ) != 0 )
|
||||
{
|
||||
if ( citem->type != MTYPE_SEPARATOR )
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** it's not in a valid spot, so crawl in the direction indicated until we
|
||||
** find a valid spot
|
||||
*/
|
||||
if ( dir == 1 )
|
||||
{
|
||||
while ( 1 )
|
||||
{
|
||||
citem = Menu_ItemAtCursor( m );
|
||||
if ( citem )
|
||||
if ( citem->type != MTYPE_SEPARATOR )
|
||||
break;
|
||||
m->cursor += dir;
|
||||
if ( m->cursor >= m->nitems )
|
||||
m->cursor = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while ( 1 )
|
||||
{
|
||||
citem = Menu_ItemAtCursor( m );
|
||||
if ( citem )
|
||||
if ( citem->type != MTYPE_SEPARATOR )
|
||||
break;
|
||||
m->cursor += dir;
|
||||
if ( m->cursor < 0 )
|
||||
m->cursor = m->nitems - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Menu_Center( menuframework_s *menu )
|
||||
{
|
||||
int height;
|
||||
|
||||
height = ( ( menucommon_s * ) menu->items[menu->nitems-1])->y;
|
||||
height += 10;
|
||||
|
||||
menu->y = ( VID_HEIGHT - height ) / 2;
|
||||
}
|
||||
|
||||
void Menu_Draw( menuframework_s *menu )
|
||||
{
|
||||
int i;
|
||||
menucommon_s *item;
|
||||
|
||||
/*
|
||||
** draw contents
|
||||
*/
|
||||
for ( i = 0; i < menu->nitems; i++ )
|
||||
{
|
||||
switch ( ( ( menucommon_s * ) menu->items[i] )->type )
|
||||
{
|
||||
case MTYPE_FIELD:
|
||||
Field_Draw( ( menufield_s * ) menu->items[i] );
|
||||
break;
|
||||
case MTYPE_SLIDER:
|
||||
Slider_Draw( ( menuslider_s * ) menu->items[i] );
|
||||
break;
|
||||
case MTYPE_LIST:
|
||||
MenuList_Draw( ( menulist_s * ) menu->items[i] );
|
||||
break;
|
||||
case MTYPE_SPINCONTROL:
|
||||
SpinControl_Draw( ( menulist_s * ) menu->items[i] );
|
||||
break;
|
||||
case MTYPE_ACTION:
|
||||
Action_Draw( ( menuaction_s * ) menu->items[i] );
|
||||
break;
|
||||
case MTYPE_SEPARATOR:
|
||||
Separator_Draw( ( menuseparator_s * ) menu->items[i] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
item = Menu_ItemAtCursor( menu );
|
||||
|
||||
if ( item && item->cursordraw )
|
||||
{
|
||||
item->cursordraw( item );
|
||||
}
|
||||
else if ( menu->cursordraw )
|
||||
{
|
||||
menu->cursordraw( menu );
|
||||
}
|
||||
else if ( item && item->type != MTYPE_FIELD )
|
||||
{
|
||||
if ( item->flags & QMF_LEFT_JUSTIFY )
|
||||
{
|
||||
Draw_Char( menu->x + item->x - 24 + item->cursor_offset, menu->y + item->y, 12 + ( ( int ) ( Sys_Milliseconds()/250 ) & 1 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
Draw_Char( menu->x + item->cursor_offset, menu->y + item->y, 12 + ( ( int ) ( Sys_Milliseconds()/250 ) & 1 ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( item )
|
||||
{
|
||||
if ( item->statusbarfunc )
|
||||
item->statusbarfunc( ( void * ) item );
|
||||
else if ( item->statusbar )
|
||||
Menu_DrawStatusBar( item->statusbar );
|
||||
else
|
||||
Menu_DrawStatusBar( menu->statusbar );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Menu_DrawStatusBar( menu->statusbar );
|
||||
}
|
||||
}
|
||||
|
||||
void Menu_DrawStatusBar( const char *string )
|
||||
{
|
||||
if ( string )
|
||||
{
|
||||
int l = strlen( string );
|
||||
int maxrow = VID_HEIGHT / 8;
|
||||
int maxcol = VID_WIDTH / 8;
|
||||
int col = maxcol / 2 - l / 2;
|
||||
|
||||
Draw_Fill( 0, VID_HEIGHT-8, VID_WIDTH, 8, 4 );
|
||||
Menu_DrawString( col*8, VID_HEIGHT - 8, string );
|
||||
}
|
||||
else
|
||||
{
|
||||
Draw_Fill( 0, VID_HEIGHT-8, VID_WIDTH, 8, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
void Menu_DrawString( int x, int y, const char *string )
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for ( i = 0; i < strlen( string ); i++ )
|
||||
{
|
||||
Draw_Char( ( x + i*8 ), y, string[i] );
|
||||
}
|
||||
}
|
||||
|
||||
void Menu_DrawStringDark( int x, int y, const char *string )
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for ( i = 0; i < strlen( string ); i++ )
|
||||
{
|
||||
Draw_Char( ( x + i*8 ), y, string[i] + 128 );
|
||||
}
|
||||
}
|
||||
|
||||
void Menu_DrawStringR2L( int x, int y, const char *string )
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for ( i = 0; i < strlen( string ); i++ )
|
||||
{
|
||||
Draw_Char( ( x - i*8 ), y, string[strlen(string)-i-1] );
|
||||
}
|
||||
}
|
||||
|
||||
void Menu_DrawStringR2LDark( int x, int y, const char *string )
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for ( i = 0; i < strlen( string ); i++ )
|
||||
{
|
||||
Draw_Char( ( x - i*8 ), y, string[strlen(string)-i-1]+128 );
|
||||
}
|
||||
}
|
||||
|
||||
void *Menu_ItemAtCursor( menuframework_s *m )
|
||||
{
|
||||
if ( m->cursor < 0 || m->cursor >= m->nitems )
|
||||
return 0;
|
||||
|
||||
return m->items[m->cursor];
|
||||
}
|
||||
|
||||
qboolean Menu_SelectItem( menuframework_s *s )
|
||||
{
|
||||
menucommon_s *item = ( menucommon_s * ) Menu_ItemAtCursor( s );
|
||||
|
||||
if ( item )
|
||||
{
|
||||
switch ( item->type )
|
||||
{
|
||||
case MTYPE_FIELD:
|
||||
return Field_DoEnter( ( menufield_s * ) item ) ;
|
||||
case MTYPE_ACTION:
|
||||
Action_DoEnter( ( menuaction_s * ) item );
|
||||
return true;
|
||||
case MTYPE_LIST:
|
||||
// Menulist_DoEnter( ( menulist_s * ) item );
|
||||
return false;
|
||||
case MTYPE_SPINCONTROL:
|
||||
// SpinControl_DoEnter( ( menulist_s * ) item );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Menu_SetStatusBar( menuframework_s *m, const char *string )
|
||||
{
|
||||
m->statusbar = string;
|
||||
}
|
||||
|
||||
void Menu_SlideItem( menuframework_s *s, int dir )
|
||||
{
|
||||
menucommon_s *item = ( menucommon_s * ) Menu_ItemAtCursor( s );
|
||||
|
||||
if ( item )
|
||||
{
|
||||
switch ( item->type )
|
||||
{
|
||||
case MTYPE_SLIDER:
|
||||
Slider_DoSlide( ( menuslider_s * ) item, dir );
|
||||
break;
|
||||
case MTYPE_SPINCONTROL:
|
||||
SpinControl_DoSlide( ( menulist_s * ) item, dir );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Menu_TallySlots( menuframework_s *menu )
|
||||
{
|
||||
int i;
|
||||
int total = 0;
|
||||
|
||||
for ( i = 0; i < menu->nitems; i++ )
|
||||
{
|
||||
if ( ( ( menucommon_s * ) menu->items[i] )->type == MTYPE_LIST )
|
||||
{
|
||||
int nitems = 0;
|
||||
const char **n = ( ( menulist_s * ) menu->items[i] )->itemnames;
|
||||
|
||||
while (*n)
|
||||
nitems++, n++;
|
||||
|
||||
total += nitems;
|
||||
}
|
||||
else
|
||||
{
|
||||
total++;
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
void Menulist_DoEnter( menulist_s *l )
|
||||
{
|
||||
int start;
|
||||
|
||||
start = l->generic.y / 10 + 1;
|
||||
|
||||
l->curvalue = l->generic.parent->cursor - start;
|
||||
|
||||
if ( l->generic.callback )
|
||||
l->generic.callback( l );
|
||||
}
|
||||
|
||||
void MenuList_Draw( menulist_s *l )
|
||||
{
|
||||
const char **n;
|
||||
int y = 0;
|
||||
|
||||
Menu_DrawStringR2LDark( l->generic.x + l->generic.parent->x + LCOLUMN_OFFSET, l->generic.y + l->generic.parent->y, l->generic.name );
|
||||
|
||||
n = l->itemnames;
|
||||
|
||||
Draw_Fill( l->generic.x - 112 + l->generic.parent->x, l->generic.parent->y + l->generic.y + l->curvalue*10 + 10, 128, 10, 16 );
|
||||
while ( *n )
|
||||
{
|
||||
Menu_DrawStringR2LDark( l->generic.x + l->generic.parent->x + LCOLUMN_OFFSET, l->generic.y + l->generic.parent->y + y + 10, *n );
|
||||
|
||||
n++;
|
||||
y += 10;
|
||||
}
|
||||
}
|
||||
|
||||
void Separator_Draw( menuseparator_s *s )
|
||||
{
|
||||
if ( s->generic.name )
|
||||
Menu_DrawStringR2LDark( s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y, s->generic.name );
|
||||
}
|
||||
|
||||
void Slider_DoSlide( menuslider_s *s, int dir )
|
||||
{
|
||||
s->curvalue += dir;
|
||||
|
||||
if ( s->curvalue > s->maxvalue )
|
||||
s->curvalue = s->maxvalue;
|
||||
else if ( s->curvalue < s->minvalue )
|
||||
s->curvalue = s->minvalue;
|
||||
|
||||
if ( s->generic.callback )
|
||||
s->generic.callback( s );
|
||||
}
|
||||
|
||||
#define SLIDER_RANGE 10
|
||||
|
||||
void Slider_Draw( menuslider_s *s )
|
||||
{
|
||||
int i;
|
||||
|
||||
Menu_DrawStringR2LDark( s->generic.x + s->generic.parent->x + LCOLUMN_OFFSET,
|
||||
s->generic.y + s->generic.parent->y,
|
||||
s->generic.name );
|
||||
|
||||
s->range = ( s->curvalue - s->minvalue ) / ( float ) ( s->maxvalue - s->minvalue );
|
||||
|
||||
if ( s->range < 0)
|
||||
s->range = 0;
|
||||
if ( s->range > 1)
|
||||
s->range = 1;
|
||||
Draw_Char( s->generic.x + s->generic.parent->x + RCOLUMN_OFFSET, s->generic.y + s->generic.parent->y, 128);
|
||||
for ( i = 0; i < SLIDER_RANGE; i++ )
|
||||
Draw_Char( RCOLUMN_OFFSET + s->generic.x + i*8 + s->generic.parent->x + 8, s->generic.y + s->generic.parent->y, 129);
|
||||
Draw_Char( RCOLUMN_OFFSET + s->generic.x + i*8 + s->generic.parent->x + 8, s->generic.y + s->generic.parent->y, 130);
|
||||
Draw_Char( ( int ) ( 8 + RCOLUMN_OFFSET + s->generic.parent->x + s->generic.x + (SLIDER_RANGE-1)*8 * s->range ), s->generic.y + s->generic.parent->y, 131);
|
||||
}
|
||||
|
||||
void SpinControl_DoEnter( menulist_s *s )
|
||||
{
|
||||
s->curvalue++;
|
||||
if ( s->itemnames[s->curvalue] == 0 )
|
||||
s->curvalue = 0;
|
||||
|
||||
if ( s->generic.callback )
|
||||
s->generic.callback( s );
|
||||
}
|
||||
|
||||
void SpinControl_DoSlide( menulist_s *s, int dir )
|
||||
{
|
||||
s->curvalue += dir;
|
||||
|
||||
if ( s->curvalue < 0 )
|
||||
s->curvalue = 0;
|
||||
else if ( s->itemnames[s->curvalue] == 0 )
|
||||
s->curvalue--;
|
||||
|
||||
if ( s->generic.callback )
|
||||
s->generic.callback( s );
|
||||
}
|
||||
|
||||
void SpinControl_Draw( menulist_s *s )
|
||||
{
|
||||
char buffer[100];
|
||||
|
||||
if ( s->generic.name )
|
||||
{
|
||||
Menu_DrawStringR2LDark( s->generic.x + s->generic.parent->x + LCOLUMN_OFFSET,
|
||||
s->generic.y + s->generic.parent->y,
|
||||
s->generic.name );
|
||||
}
|
||||
if ( !strchr( s->itemnames[s->curvalue], '\n' ) )
|
||||
{
|
||||
Menu_DrawString( RCOLUMN_OFFSET + s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y, s->itemnames[s->curvalue] );
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy( buffer, s->itemnames[s->curvalue] );
|
||||
*strchr( buffer, '\n' ) = 0;
|
||||
Menu_DrawString( RCOLUMN_OFFSET + s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y, buffer );
|
||||
strcpy( buffer, strchr( s->itemnames[s->curvalue], '\n' ) + 1 );
|
||||
Menu_DrawString( RCOLUMN_OFFSET + s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y + 10, buffer );
|
||||
}
|
||||
}
|
||||
|
140
client/qmenu.h
Normal file
140
client/qmenu.h
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
#ifndef __QMENU_H__
|
||||
#define __QMENU_H__
|
||||
|
||||
#define MAXMENUITEMS 64
|
||||
|
||||
#define MTYPE_SLIDER 0
|
||||
#define MTYPE_LIST 1
|
||||
#define MTYPE_ACTION 2
|
||||
#define MTYPE_SPINCONTROL 3
|
||||
#define MTYPE_SEPARATOR 4
|
||||
#define MTYPE_FIELD 5
|
||||
|
||||
#define K_TAB 9
|
||||
#define K_ENTER 13
|
||||
#define K_ESCAPE 27
|
||||
#define K_SPACE 32
|
||||
|
||||
// normal keys should be passed as lowercased ascii
|
||||
|
||||
#define K_BACKSPACE 127
|
||||
#define K_UPARROW 128
|
||||
#define K_DOWNARROW 129
|
||||
#define K_LEFTARROW 130
|
||||
#define K_RIGHTARROW 131
|
||||
|
||||
#define QMF_LEFT_JUSTIFY 0x00000001
|
||||
#define QMF_GRAYED 0x00000002
|
||||
#define QMF_NUMBERSONLY 0x00000004
|
||||
|
||||
typedef struct _tag_menuframework
|
||||
{
|
||||
int x, y;
|
||||
int cursor;
|
||||
|
||||
int nitems;
|
||||
int nslots;
|
||||
void *items[64];
|
||||
|
||||
const char *statusbar;
|
||||
|
||||
void (*cursordraw)( struct _tag_menuframework *m );
|
||||
|
||||
} menuframework_s;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int type;
|
||||
const char *name;
|
||||
int x, y;
|
||||
menuframework_s *parent;
|
||||
int cursor_offset;
|
||||
int localdata[4];
|
||||
unsigned flags;
|
||||
|
||||
const char *statusbar;
|
||||
|
||||
void (*callback)( void *self );
|
||||
void (*statusbarfunc)( void *self );
|
||||
void (*ownerdraw)( void *self );
|
||||
void (*cursordraw)( void *self );
|
||||
} menucommon_s;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
menucommon_s generic;
|
||||
|
||||
char buffer[80];
|
||||
int cursor;
|
||||
int length;
|
||||
int visible_length;
|
||||
int visible_offset;
|
||||
} menufield_s;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
menucommon_s generic;
|
||||
|
||||
float minvalue;
|
||||
float maxvalue;
|
||||
float curvalue;
|
||||
|
||||
float range;
|
||||
} menuslider_s;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
menucommon_s generic;
|
||||
|
||||
int curvalue;
|
||||
|
||||
const char **itemnames;
|
||||
} menulist_s;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
menucommon_s generic;
|
||||
} menuaction_s;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
menucommon_s generic;
|
||||
} menuseparator_s;
|
||||
|
||||
qboolean Field_Key( menufield_s *field, int key );
|
||||
|
||||
void Menu_AddItem( menuframework_s *menu, void *item );
|
||||
void Menu_AdjustCursor( menuframework_s *menu, int dir );
|
||||
void Menu_Center( menuframework_s *menu );
|
||||
void Menu_Draw( menuframework_s *menu );
|
||||
void *Menu_ItemAtCursor( menuframework_s *m );
|
||||
qboolean Menu_SelectItem( menuframework_s *s );
|
||||
void Menu_SetStatusBar( menuframework_s *s, const char *string );
|
||||
void Menu_SlideItem( menuframework_s *s, int dir );
|
||||
int Menu_TallySlots( menuframework_s *menu );
|
||||
|
||||
void Menu_DrawString( int, int, const char * );
|
||||
void Menu_DrawStringDark( int, int, const char * );
|
||||
void Menu_DrawStringR2L( int, int, const char * );
|
||||
void Menu_DrawStringR2LDark( int, int, const char * );
|
||||
|
||||
#endif
|
224
client/ref.h
Normal file
224
client/ref.h
Normal file
@ -0,0 +1,224 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "../qcommon/qcommon.h"
|
||||
|
||||
#define MAX_DLIGHTS 32
|
||||
#define MAX_ENTITIES 128
|
||||
#define MAX_PARTICLES 4096
|
||||
#define MAX_LIGHTSTYLES 256
|
||||
|
||||
#define POWERSUIT_SCALE 4.0F
|
||||
|
||||
#define SHELL_RED_COLOR 0xF2
|
||||
#define SHELL_GREEN_COLOR 0xD0
|
||||
#define SHELL_BLUE_COLOR 0xF3
|
||||
|
||||
#define SHELL_RG_COLOR 0xDC
|
||||
//#define SHELL_RB_COLOR 0x86
|
||||
#define SHELL_RB_COLOR 0x68
|
||||
#define SHELL_BG_COLOR 0x78
|
||||
|
||||
//ROGUE
|
||||
#define SHELL_DOUBLE_COLOR 0xDF // 223
|
||||
#define SHELL_HALF_DAM_COLOR 0x90
|
||||
#define SHELL_CYAN_COLOR 0x72
|
||||
//ROGUE
|
||||
|
||||
#define SHELL_WHITE_COLOR 0xD7
|
||||
|
||||
typedef struct entity_s
|
||||
{
|
||||
struct model_s *model; // opaque type outside refresh
|
||||
float angles[3];
|
||||
|
||||
/*
|
||||
** most recent data
|
||||
*/
|
||||
float origin[3]; // also used as RF_BEAM's "from"
|
||||
int frame; // also used as RF_BEAM's diameter
|
||||
|
||||
/*
|
||||
** previous data for lerping
|
||||
*/
|
||||
float oldorigin[3]; // also used as RF_BEAM's "to"
|
||||
int oldframe;
|
||||
|
||||
/*
|
||||
** misc
|
||||
*/
|
||||
float backlerp; // 0.0 = current, 1.0 = old
|
||||
int skinnum; // also used as RF_BEAM's palette index
|
||||
|
||||
int lightstyle; // for flashing entities
|
||||
float alpha; // ignore if RF_TRANSLUCENT isn't set
|
||||
|
||||
struct image_s *skin; // NULL for inline skin
|
||||
int flags;
|
||||
|
||||
} entity_t;
|
||||
|
||||
#define ENTITY_FLAGS 68
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec3_t origin;
|
||||
vec3_t color;
|
||||
float intensity;
|
||||
} dlight_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec3_t origin;
|
||||
int color;
|
||||
float alpha;
|
||||
} particle_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float rgb[3]; // 0.0 - 2.0
|
||||
float white; // highest of rgb
|
||||
} lightstyle_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int x, y, width, height;// in virtual screen coordinates
|
||||
float fov_x, fov_y;
|
||||
float vieworg[3];
|
||||
float viewangles[3];
|
||||
float blend[4]; // rgba 0-1 full screen blend
|
||||
float time; // time is uesed to auto animate
|
||||
int rdflags; // RDF_UNDERWATER, etc
|
||||
|
||||
byte *areabits; // if not NULL, only areas with set bits will be drawn
|
||||
|
||||
lightstyle_t *lightstyles; // [MAX_LIGHTSTYLES]
|
||||
|
||||
int num_entities;
|
||||
entity_t *entities;
|
||||
|
||||
int num_dlights;
|
||||
dlight_t *dlights;
|
||||
|
||||
int num_particles;
|
||||
particle_t *particles;
|
||||
} refdef_t;
|
||||
|
||||
|
||||
|
||||
#define API_VERSION 3
|
||||
|
||||
//
|
||||
// these are the functions exported by the refresh module
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
// if api_version is different, the dll cannot be used
|
||||
int api_version;
|
||||
|
||||
// called when the library is loaded
|
||||
qboolean (*Init) ( void *hinstance, void *wndproc );
|
||||
|
||||
// called before the library is unloaded
|
||||
void (*Shutdown) (void);
|
||||
|
||||
// All data that will be used in a level should be
|
||||
// registered before rendering any frames to prevent disk hits,
|
||||
// but they can still be registered at a later time
|
||||
// if necessary.
|
||||
//
|
||||
// EndRegistration will free any remaining data that wasn't registered.
|
||||
// Any model_s or skin_s pointers from before the BeginRegistration
|
||||
// are no longer valid after EndRegistration.
|
||||
//
|
||||
// Skins and images need to be differentiated, because skins
|
||||
// are flood filled to eliminate mip map edge errors, and pics have
|
||||
// an implicit "pics/" prepended to the name. (a pic name that starts with a
|
||||
// slash will not use the "pics/" prefix or the ".pcx" postfix)
|
||||
void (*BeginRegistration) (char *map);
|
||||
struct model_s *(*RegisterModel) (char *name);
|
||||
struct image_s *(*RegisterSkin) (char *name);
|
||||
struct image_s *(*RegisterPic) (char *name);
|
||||
void (*SetSky) (char *name, float rotate, vec3_t axis);
|
||||
void (*EndRegistration) (void);
|
||||
|
||||
void (*RenderFrame) (refdef_t *fd);
|
||||
|
||||
void (*DrawGetPicSize) (int *w, int *h, char *name); // will return 0 0 if not found
|
||||
void (*DrawPic) (int x, int y, char *name);
|
||||
void (*DrawStretchPic) (int x, int y, int w, int h, char *name);
|
||||
void (*DrawChar) (int x, int y, int c);
|
||||
void (*DrawTileClear) (int x, int y, int w, int h, char *name);
|
||||
void (*DrawFill) (int x, int y, int w, int h, int c);
|
||||
void (*DrawFadeScreen) (void);
|
||||
|
||||
// Draw images for cinematic rendering (which can have a different palette). Note that calls
|
||||
void (*DrawStretchRaw) (int x, int y, int w, int h, int cols, int rows, byte *data);
|
||||
|
||||
/*
|
||||
** video mode and refresh state management entry points
|
||||
*/
|
||||
void (*CinematicSetPalette)( const unsigned char *palette); // NULL = game palette
|
||||
void (*BeginFrame)( float camera_separation );
|
||||
void (*EndFrame) (void);
|
||||
|
||||
void (*AppActivate)( qboolean activate );
|
||||
|
||||
} refexport_t;
|
||||
|
||||
//
|
||||
// these are the functions imported by the refresh module
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
void (*Sys_Error) (int err_level, char *str, ...);
|
||||
|
||||
void (*Cmd_AddCommand) (char *name, void(*cmd)(void));
|
||||
void (*Cmd_RemoveCommand) (char *name);
|
||||
int (*Cmd_Argc) (void);
|
||||
char *(*Cmd_Argv) (int i);
|
||||
void (*Cmd_ExecuteText) (int exec_when, char *text);
|
||||
|
||||
void (*Con_Printf) (int print_level, char *str, ...);
|
||||
|
||||
// files will be memory mapped read only
|
||||
// the returned buffer may be part of a larger pak file,
|
||||
// or a discrete file from anywhere in the quake search path
|
||||
// a -1 return means the file does not exist
|
||||
// NULL can be passed for buf to just determine existance
|
||||
int (*FS_LoadFile) (char *name, void **buf);
|
||||
void (*FS_FreeFile) (void *buf);
|
||||
|
||||
// gamedir will be the current directory that generated
|
||||
// files should be stored to, ie: "f:\quake\id1"
|
||||
char *(*FS_Gamedir) (void);
|
||||
|
||||
cvar_t *(*Cvar_Get) (char *name, char *value, int flags);
|
||||
cvar_t *(*Cvar_Set)( char *name, char *value );
|
||||
void (*Cvar_SetValue)( char *name, float value );
|
||||
|
||||
qboolean (*Vid_GetModeInfo)( int *width, int *height, int mode );
|
||||
void (*Vid_MenuInit)( void );
|
||||
void (*Vid_NewWindow)( int width, int height );
|
||||
} refimport_t;
|
||||
|
||||
|
||||
// this is the only function actually exported at the linker level
|
||||
typedef refexport_t (*GetRefAPI_t) (refimport_t);
|
62
client/screen.h
Normal file
62
client/screen.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// screen.h
|
||||
|
||||
void SCR_Init (void);
|
||||
|
||||
void SCR_UpdateScreen (void);
|
||||
|
||||
void SCR_SizeUp (void);
|
||||
void SCR_SizeDown (void);
|
||||
void SCR_CenterPrint (char *str);
|
||||
void SCR_BeginLoadingPlaque (void);
|
||||
void SCR_EndLoadingPlaque (void);
|
||||
|
||||
void SCR_DebugGraph (float value, int color);
|
||||
|
||||
void SCR_TouchPics (void);
|
||||
|
||||
void SCR_RunConsole (void);
|
||||
|
||||
extern float scr_con_current;
|
||||
extern float scr_conlines; // lines of console to display
|
||||
|
||||
extern int sb_lines;
|
||||
|
||||
extern cvar_t *scr_viewsize;
|
||||
extern cvar_t *crosshair;
|
||||
|
||||
extern vrect_t scr_vrect; // position of render window
|
||||
|
||||
extern char crosshair_pic[MAX_QPATH];
|
||||
extern int crosshair_width, crosshair_height;
|
||||
|
||||
void SCR_AddDirtyPoint (int x, int y);
|
||||
void SCR_DirtyScreen (void);
|
||||
|
||||
//
|
||||
// scr_cin.c
|
||||
//
|
||||
void SCR_PlayCinematic (char *name);
|
||||
qboolean SCR_DrawCinematic (void);
|
||||
void SCR_RunCinematic (void);
|
||||
void SCR_StopCinematic (void);
|
||||
void SCR_FinishCinematic (void);
|
||||
|
1214
client/snd_dma.c
Normal file
1214
client/snd_dma.c
Normal file
File diff suppressed because it is too large
Load Diff
164
client/snd_loc.h
Normal file
164
client/snd_loc.h
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// snd_loc.h -- private sound functions
|
||||
|
||||
// !!! if this is changed, the asm code must change !!!
|
||||
typedef struct
|
||||
{
|
||||
int left;
|
||||
int right;
|
||||
} portable_samplepair_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int length;
|
||||
int loopstart;
|
||||
int speed; // not needed, because converted on load?
|
||||
int width;
|
||||
int stereo;
|
||||
byte data[1]; // variable sized
|
||||
} sfxcache_t;
|
||||
|
||||
typedef struct sfx_s
|
||||
{
|
||||
char name[MAX_QPATH];
|
||||
int registration_sequence;
|
||||
sfxcache_t *cache;
|
||||
char *truename;
|
||||
} sfx_t;
|
||||
|
||||
// a playsound_t will be generated by each call to S_StartSound,
|
||||
// when the mixer reaches playsound->begin, the playsound will
|
||||
// be assigned to a channel
|
||||
typedef struct playsound_s
|
||||
{
|
||||
struct playsound_s *prev, *next;
|
||||
sfx_t *sfx;
|
||||
float volume;
|
||||
float attenuation;
|
||||
int entnum;
|
||||
int entchannel;
|
||||
qboolean fixed_origin; // use origin field instead of entnum's origin
|
||||
vec3_t origin;
|
||||
unsigned begin; // begin on this sample
|
||||
} playsound_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int channels;
|
||||
int samples; // mono samples in buffer
|
||||
int submission_chunk; // don't mix less than this #
|
||||
int samplepos; // in mono samples
|
||||
int samplebits;
|
||||
int speed;
|
||||
byte *buffer;
|
||||
} dma_t;
|
||||
|
||||
// !!! if this is changed, the asm code must change !!!
|
||||
typedef struct
|
||||
{
|
||||
sfx_t *sfx; // sfx number
|
||||
int leftvol; // 0-255 volume
|
||||
int rightvol; // 0-255 volume
|
||||
int end; // end time in global paintsamples
|
||||
int pos; // sample position in sfx
|
||||
int looping; // where to loop, -1 = no looping OBSOLETE?
|
||||
int entnum; // to allow overriding a specific sound
|
||||
int entchannel; //
|
||||
vec3_t origin; // only use if fixed_origin is set
|
||||
vec_t dist_mult; // distance multiplier (attenuation/clipK)
|
||||
int master_vol; // 0-255 master volume
|
||||
qboolean fixed_origin; // use origin instead of fetching entnum's origin
|
||||
qboolean autosound; // from an entity->sound, cleared each frame
|
||||
} channel_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int rate;
|
||||
int width;
|
||||
int channels;
|
||||
int loopstart;
|
||||
int samples;
|
||||
int dataofs; // chunk starts this many bytes from file start
|
||||
} wavinfo_t;
|
||||
|
||||
|
||||
/*
|
||||
====================================================================
|
||||
|
||||
SYSTEM SPECIFIC FUNCTIONS
|
||||
|
||||
====================================================================
|
||||
*/
|
||||
|
||||
// initializes cycling through a DMA buffer and returns information on it
|
||||
qboolean SNDDMA_Init(void);
|
||||
|
||||
// gets the current DMA position
|
||||
int SNDDMA_GetDMAPos(void);
|
||||
|
||||
// shutdown the DMA xfer.
|
||||
void SNDDMA_Shutdown(void);
|
||||
|
||||
void SNDDMA_BeginPainting (void);
|
||||
|
||||
void SNDDMA_Submit(void);
|
||||
|
||||
//====================================================================
|
||||
|
||||
#define MAX_CHANNELS 32
|
||||
extern channel_t channels[MAX_CHANNELS];
|
||||
|
||||
extern int paintedtime;
|
||||
extern int s_rawend;
|
||||
extern vec3_t listener_origin;
|
||||
extern vec3_t listener_forward;
|
||||
extern vec3_t listener_right;
|
||||
extern vec3_t listener_up;
|
||||
extern dma_t dma;
|
||||
extern playsound_t s_pendingplays;
|
||||
|
||||
#define MAX_RAW_SAMPLES 8192
|
||||
extern portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
|
||||
|
||||
extern cvar_t *s_volume;
|
||||
extern cvar_t *s_nosound;
|
||||
extern cvar_t *s_loadas8bit;
|
||||
extern cvar_t *s_khz;
|
||||
extern cvar_t *s_show;
|
||||
extern cvar_t *s_mixahead;
|
||||
extern cvar_t *s_testsound;
|
||||
extern cvar_t *s_primary;
|
||||
|
||||
wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength);
|
||||
|
||||
void S_InitScaletable (void);
|
||||
|
||||
sfxcache_t *S_LoadSound (sfx_t *s);
|
||||
|
||||
void S_IssuePlaysound (playsound_t *ps);
|
||||
|
||||
void S_PaintChannels(int endtime);
|
||||
|
||||
// picks a channel based on priorities, empty slots, number of channels
|
||||
channel_t *S_PickChannel(int entnum, int entchannel);
|
||||
|
||||
// spatializes a channel
|
||||
void S_Spatialize(channel_t *ch);
|
359
client/snd_mem.c
Normal file
359
client/snd_mem.c
Normal file
@ -0,0 +1,359 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// snd_mem.c: sound caching
|
||||
|
||||
#include "client.h"
|
||||
#include "snd_loc.h"
|
||||
|
||||
int cache_full_cycle;
|
||||
|
||||
byte *S_Alloc (int size);
|
||||
|
||||
/*
|
||||
================
|
||||
ResampleSfx
|
||||
================
|
||||
*/
|
||||
void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data)
|
||||
{
|
||||
int outcount;
|
||||
int srcsample;
|
||||
float stepscale;
|
||||
int i;
|
||||
int sample, samplefrac, fracstep;
|
||||
sfxcache_t *sc;
|
||||
|
||||
sc = sfx->cache;
|
||||
if (!sc)
|
||||
return;
|
||||
|
||||
stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
|
||||
|
||||
outcount = sc->length / stepscale;
|
||||
sc->length = outcount;
|
||||
if (sc->loopstart != -1)
|
||||
sc->loopstart = sc->loopstart / stepscale;
|
||||
|
||||
sc->speed = dma.speed;
|
||||
if (s_loadas8bit->value)
|
||||
sc->width = 1;
|
||||
else
|
||||
sc->width = inwidth;
|
||||
sc->stereo = 0;
|
||||
|
||||
// resample / decimate to the current source rate
|
||||
|
||||
if (stepscale == 1 && inwidth == 1 && sc->width == 1)
|
||||
{
|
||||
// fast special case
|
||||
for (i=0 ; i<outcount ; i++)
|
||||
((signed char *)sc->data)[i]
|
||||
= (int)( (unsigned char)(data[i]) - 128);
|
||||
}
|
||||
else
|
||||
{
|
||||
// general case
|
||||
samplefrac = 0;
|
||||
fracstep = stepscale*256;
|
||||
for (i=0 ; i<outcount ; i++)
|
||||
{
|
||||
srcsample = samplefrac >> 8;
|
||||
samplefrac += fracstep;
|
||||
if (inwidth == 2)
|
||||
sample = LittleShort ( ((short *)data)[srcsample] );
|
||||
else
|
||||
sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
|
||||
if (sc->width == 2)
|
||||
((short *)sc->data)[i] = sample;
|
||||
else
|
||||
((signed char *)sc->data)[i] = sample >> 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
==============
|
||||
S_LoadSound
|
||||
==============
|
||||
*/
|
||||
sfxcache_t *S_LoadSound (sfx_t *s)
|
||||
{
|
||||
char namebuffer[MAX_QPATH];
|
||||
byte *data;
|
||||
wavinfo_t info;
|
||||
int len;
|
||||
float stepscale;
|
||||
sfxcache_t *sc;
|
||||
int size;
|
||||
char *name;
|
||||
|
||||
if (s->name[0] == '*')
|
||||
return NULL;
|
||||
|
||||
// see if still in memory
|
||||
sc = s->cache;
|
||||
if (sc)
|
||||
return sc;
|
||||
|
||||
//Com_Printf ("S_LoadSound: %x\n", (int)stackbuf);
|
||||
// load it in
|
||||
if (s->truename)
|
||||
name = s->truename;
|
||||
else
|
||||
name = s->name;
|
||||
|
||||
if (name[0] == '#')
|
||||
strcpy(namebuffer, &name[1]);
|
||||
else
|
||||
Com_sprintf (namebuffer, sizeof(namebuffer), "sound/%s", name);
|
||||
|
||||
// Com_Printf ("loading %s\n",namebuffer);
|
||||
|
||||
size = FS_LoadFile (namebuffer, (void **)&data);
|
||||
|
||||
if (!data)
|
||||
{
|
||||
Com_DPrintf ("Couldn't load %s\n", namebuffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
info = GetWavinfo (s->name, data, size);
|
||||
if (info.channels != 1)
|
||||
{
|
||||
Com_Printf ("%s is a stereo sample\n",s->name);
|
||||
FS_FreeFile (data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stepscale = (float)info.rate / dma.speed;
|
||||
len = info.samples / stepscale;
|
||||
|
||||
len = len * info.width * info.channels;
|
||||
|
||||
sc = s->cache = Z_Malloc (len + sizeof(sfxcache_t));
|
||||
if (!sc)
|
||||
{
|
||||
FS_FreeFile (data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sc->length = info.samples;
|
||||
sc->loopstart = info.loopstart;
|
||||
sc->speed = info.rate;
|
||||
sc->width = info.width;
|
||||
sc->stereo = info.channels;
|
||||
|
||||
ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);
|
||||
|
||||
FS_FreeFile (data);
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
WAV loading
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
|
||||
byte *data_p;
|
||||
byte *iff_end;
|
||||
byte *last_chunk;
|
||||
byte *iff_data;
|
||||
int iff_chunk_len;
|
||||
|
||||
|
||||
short GetLittleShort(void)
|
||||
{
|
||||
short val = 0;
|
||||
val = *data_p;
|
||||
val = val + (*(data_p+1)<<8);
|
||||
data_p += 2;
|
||||
return val;
|
||||
}
|
||||
|
||||
int GetLittleLong(void)
|
||||
{
|
||||
int 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)
|
||||
{ // didn't find the chunk
|
||||
data_p = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
data_p += 4;
|
||||
iff_chunk_len = GetLittleLong();
|
||||
if (iff_chunk_len < 0)
|
||||
{
|
||||
data_p = NULL;
|
||||
return;
|
||||
}
|
||||
// if (iff_chunk_len > 1024*1024)
|
||||
// Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
|
||||
data_p -= 8;
|
||||
last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
|
||||
if (!strncmp(data_p, name, 4))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void FindChunk(char *name)
|
||||
{
|
||||
last_chunk = iff_data;
|
||||
FindNextChunk (name);
|
||||
}
|
||||
|
||||
|
||||
void DumpChunks(void)
|
||||
{
|
||||
char str[5];
|
||||
|
||||
str[4] = 0;
|
||||
data_p=iff_data;
|
||||
do
|
||||
{
|
||||
memcpy (str, data_p, 4);
|
||||
data_p += 4;
|
||||
iff_chunk_len = GetLittleLong();
|
||||
Com_Printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len);
|
||||
data_p += (iff_chunk_len + 1) & ~1;
|
||||
} while (data_p < iff_end);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
GetWavinfo
|
||||
============
|
||||
*/
|
||||
wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
|
||||
{
|
||||
wavinfo_t info;
|
||||
int i;
|
||||
int format;
|
||||
int samples;
|
||||
|
||||
memset (&info, 0, sizeof(info));
|
||||
|
||||
if (!wav)
|
||||
return info;
|
||||
|
||||
iff_data = wav;
|
||||
iff_end = wav + wavlength;
|
||||
|
||||
// find "RIFF" chunk
|
||||
FindChunk("RIFF");
|
||||
if (!(data_p && !strncmp(data_p+8, "WAVE", 4)))
|
||||
{
|
||||
Com_Printf("Missing RIFF/WAVE chunks\n");
|
||||
return info;
|
||||
}
|
||||
|
||||
// get "fmt " chunk
|
||||
iff_data = data_p + 12;
|
||||
// DumpChunks ();
|
||||
|
||||
FindChunk("fmt ");
|
||||
if (!data_p)
|
||||
{
|
||||
Com_Printf("Missing fmt chunk\n");
|
||||
return info;
|
||||
}
|
||||
data_p += 8;
|
||||
format = GetLittleShort();
|
||||
if (format != 1)
|
||||
{
|
||||
Com_Printf("Microsoft PCM format only\n");
|
||||
return info;
|
||||
}
|
||||
|
||||
info.channels = GetLittleShort();
|
||||
info.rate = GetLittleLong();
|
||||
data_p += 4+2;
|
||||
info.width = GetLittleShort() / 8;
|
||||
|
||||
// get cue chunk
|
||||
FindChunk("cue ");
|
||||
if (data_p)
|
||||
{
|
||||
data_p += 32;
|
||||
info.loopstart = GetLittleLong();
|
||||
// Com_Printf("loopstart=%d\n", sfx->loopstart);
|
||||
|
||||
// if the next chunk is a LIST chunk, look for a cue length marker
|
||||
FindNextChunk ("LIST");
|
||||
if (data_p)
|
||||
{
|
||||
if (!strncmp (data_p + 28, "mark", 4))
|
||||
{ // this is not a proper parse, but it works with cooledit...
|
||||
data_p += 24;
|
||||
i = GetLittleLong (); // samples in loop
|
||||
info.samples = info.loopstart + i;
|
||||
// Com_Printf("looped length: %i\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
info.loopstart = -1;
|
||||
|
||||
// find data chunk
|
||||
FindChunk("data");
|
||||
if (!data_p)
|
||||
{
|
||||
Com_Printf("Missing data chunk\n");
|
||||
return info;
|
||||
}
|
||||
|
||||
data_p += 4;
|
||||
samples = GetLittleLong () / info.width;
|
||||
|
||||
if (info.samples)
|
||||
{
|
||||
if (samples < info.samples)
|
||||
Com_Error (ERR_DROP, "Sound %s has a bad loop length", name);
|
||||
}
|
||||
else
|
||||
info.samples = samples;
|
||||
|
||||
info.dataofs = data_p - wav;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
497
client/snd_mix.c
Normal file
497
client/snd_mix.c
Normal file
@ -0,0 +1,497 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// snd_mix.c -- portable code to mix sounds for snd_dma.c
|
||||
|
||||
#include "client.h"
|
||||
#include "snd_loc.h"
|
||||
|
||||
#define PAINTBUFFER_SIZE 2048
|
||||
portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
|
||||
int snd_scaletable[32][256];
|
||||
int *snd_p, snd_linear_count, snd_vol;
|
||||
short *snd_out;
|
||||
|
||||
void S_WriteLinearBlastStereo16 (void);
|
||||
|
||||
#if !(defined __linux__ && defined __i386__)
|
||||
#if !id386
|
||||
|
||||
void S_WriteLinearBlastStereo16 (void)
|
||||
{
|
||||
int i;
|
||||
int val;
|
||||
|
||||
for (i=0 ; i<snd_linear_count ; i+=2)
|
||||
{
|
||||
val = snd_p[i]>>8;
|
||||
if (val > 0x7fff)
|
||||
snd_out[i] = 0x7fff;
|
||||
else if (val < (short)0x8000)
|
||||
snd_out[i] = (short)0x8000;
|
||||
else
|
||||
snd_out[i] = val;
|
||||
|
||||
val = snd_p[i+1]>>8;
|
||||
if (val > 0x7fff)
|
||||
snd_out[i+1] = 0x7fff;
|
||||
else if (val < (short)0x8000)
|
||||
snd_out[i+1] = (short)0x8000;
|
||||
else
|
||||
snd_out[i+1] = val;
|
||||
}
|
||||
}
|
||||
#else
|
||||
__declspec( naked ) void S_WriteLinearBlastStereo16 (void)
|
||||
{
|
||||
__asm {
|
||||
|
||||
push edi
|
||||
push ebx
|
||||
mov ecx,ds:dword ptr[snd_linear_count]
|
||||
mov ebx,ds:dword ptr[snd_p]
|
||||
mov edi,ds:dword ptr[snd_out]
|
||||
LWLBLoopTop:
|
||||
mov eax,ds:dword ptr[-8+ebx+ecx*4]
|
||||
sar eax,8
|
||||
cmp eax,07FFFh
|
||||
jg LClampHigh
|
||||
cmp eax,0FFFF8000h
|
||||
jnl LClampDone
|
||||
mov eax,0FFFF8000h
|
||||
jmp LClampDone
|
||||
LClampHigh:
|
||||
mov eax,07FFFh
|
||||
LClampDone:
|
||||
mov edx,ds:dword ptr[-4+ebx+ecx*4]
|
||||
sar edx,8
|
||||
cmp edx,07FFFh
|
||||
jg LClampHigh2
|
||||
cmp edx,0FFFF8000h
|
||||
jnl LClampDone2
|
||||
mov edx,0FFFF8000h
|
||||
jmp LClampDone2
|
||||
LClampHigh2:
|
||||
mov edx,07FFFh
|
||||
LClampDone2:
|
||||
shl edx,16
|
||||
and eax,0FFFFh
|
||||
or edx,eax
|
||||
mov ds:dword ptr[-4+edi+ecx*2],edx
|
||||
sub ecx,2
|
||||
jnz LWLBLoopTop
|
||||
pop ebx
|
||||
pop edi
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void S_TransferStereo16 (unsigned long *pbuf, int endtime)
|
||||
{
|
||||
int lpos;
|
||||
int lpaintedtime;
|
||||
|
||||
snd_p = (int *) paintbuffer;
|
||||
lpaintedtime = paintedtime;
|
||||
|
||||
while (lpaintedtime < endtime)
|
||||
{
|
||||
// handle recirculating buffer issues
|
||||
lpos = lpaintedtime & ((dma.samples>>1)-1);
|
||||
|
||||
snd_out = (short *) pbuf + (lpos<<1);
|
||||
|
||||
snd_linear_count = (dma.samples>>1) - lpos;
|
||||
if (lpaintedtime + snd_linear_count > endtime)
|
||||
snd_linear_count = endtime - lpaintedtime;
|
||||
|
||||
snd_linear_count <<= 1;
|
||||
|
||||
// write a linear blast of samples
|
||||
S_WriteLinearBlastStereo16 ();
|
||||
|
||||
snd_p += snd_linear_count;
|
||||
lpaintedtime += (snd_linear_count>>1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
S_TransferPaintBuffer
|
||||
|
||||
===================
|
||||
*/
|
||||
void S_TransferPaintBuffer(int endtime)
|
||||
{
|
||||
int out_idx;
|
||||
int count;
|
||||
int out_mask;
|
||||
int *p;
|
||||
int step;
|
||||
int val;
|
||||
unsigned long *pbuf;
|
||||
|
||||
pbuf = (unsigned long *)dma.buffer;
|
||||
|
||||
if (s_testsound->value)
|
||||
{
|
||||
int i;
|
||||
int count;
|
||||
|
||||
// write a fixed sine wave
|
||||
count = (endtime - paintedtime);
|
||||
for (i=0 ; i<count ; i++)
|
||||
paintbuffer[i].left = paintbuffer[i].right = sin((paintedtime+i)*0.1)*20000*256;
|
||||
}
|
||||
|
||||
|
||||
if (dma.samplebits == 16 && dma.channels == 2)
|
||||
{ // optimized case
|
||||
S_TransferStereo16 (pbuf, endtime);
|
||||
}
|
||||
else
|
||||
{ // general case
|
||||
p = (int *) paintbuffer;
|
||||
count = (endtime - paintedtime) * dma.channels;
|
||||
out_mask = dma.samples - 1;
|
||||
out_idx = paintedtime * dma.channels & out_mask;
|
||||
step = 3 - dma.channels;
|
||||
|
||||
if (dma.samplebits == 16)
|
||||
{
|
||||
short *out = (short *) pbuf;
|
||||
while (count--)
|
||||
{
|
||||
val = *p >> 8;
|
||||
p+= step;
|
||||
if (val > 0x7fff)
|
||||
val = 0x7fff;
|
||||
else if (val < (short)0x8000)
|
||||
val = (short)0x8000;
|
||||
out[out_idx] = val;
|
||||
out_idx = (out_idx + 1) & out_mask;
|
||||
}
|
||||
}
|
||||
else if (dma.samplebits == 8)
|
||||
{
|
||||
unsigned char *out = (unsigned char *) pbuf;
|
||||
while (count--)
|
||||
{
|
||||
val = *p >> 8;
|
||||
p+= step;
|
||||
if (val > 0x7fff)
|
||||
val = 0x7fff;
|
||||
else if (val < (short)0x8000)
|
||||
val = (short)0x8000;
|
||||
out[out_idx] = (val>>8) + 128;
|
||||
out_idx = (out_idx + 1) & out_mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
CHANNEL MIXING
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime, int offset);
|
||||
void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime, int offset);
|
||||
|
||||
void S_PaintChannels(int endtime)
|
||||
{
|
||||
int i;
|
||||
int end;
|
||||
channel_t *ch;
|
||||
sfxcache_t *sc;
|
||||
int ltime, count;
|
||||
playsound_t *ps;
|
||||
|
||||
snd_vol = s_volume->value*256;
|
||||
|
||||
//Com_Printf ("%i to %i\n", paintedtime, endtime);
|
||||
while (paintedtime < endtime)
|
||||
{
|
||||
// if paintbuffer is smaller than DMA buffer
|
||||
end = endtime;
|
||||
if (endtime - paintedtime > PAINTBUFFER_SIZE)
|
||||
end = paintedtime + PAINTBUFFER_SIZE;
|
||||
|
||||
// start any playsounds
|
||||
while (1)
|
||||
{
|
||||
ps = s_pendingplays.next;
|
||||
if (ps == &s_pendingplays)
|
||||
break; // no more pending sounds
|
||||
if (ps->begin <= paintedtime)
|
||||
{
|
||||
S_IssuePlaysound (ps);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ps->begin < end)
|
||||
end = ps->begin; // stop here
|
||||
break;
|
||||
}
|
||||
|
||||
// clear the paint buffer
|
||||
if (s_rawend < paintedtime)
|
||||
{
|
||||
// Com_Printf ("clear\n");
|
||||
memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t));
|
||||
}
|
||||
else
|
||||
{ // copy from the streaming sound source
|
||||
int s;
|
||||
int stop;
|
||||
|
||||
stop = (end < s_rawend) ? end : s_rawend;
|
||||
|
||||
for (i=paintedtime ; i<stop ; i++)
|
||||
{
|
||||
s = i&(MAX_RAW_SAMPLES-1);
|
||||
paintbuffer[i-paintedtime] = s_rawsamples[s];
|
||||
}
|
||||
// if (i != end)
|
||||
// Com_Printf ("partial stream\n");
|
||||
// else
|
||||
// Com_Printf ("full stream\n");
|
||||
for ( ; i<end ; i++)
|
||||
{
|
||||
paintbuffer[i-paintedtime].left =
|
||||
paintbuffer[i-paintedtime].right = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// paint in the channels.
|
||||
ch = channels;
|
||||
for (i=0; i<MAX_CHANNELS ; i++, ch++)
|
||||
{
|
||||
ltime = paintedtime;
|
||||
|
||||
while (ltime < end)
|
||||
{
|
||||
if (!ch->sfx || (!ch->leftvol && !ch->rightvol) )
|
||||
break;
|
||||
|
||||
// max painting is to the end of the buffer
|
||||
count = end - ltime;
|
||||
|
||||
// might be stopped by running out of data
|
||||
if (ch->end - ltime < count)
|
||||
count = ch->end - ltime;
|
||||
|
||||
sc = S_LoadSound (ch->sfx);
|
||||
if (!sc)
|
||||
break;
|
||||
|
||||
if (count > 0 && ch->sfx)
|
||||
{
|
||||
if (sc->width == 1)// FIXME; 8 bit asm is wrong now
|
||||
S_PaintChannelFrom8(ch, sc, count, ltime - paintedtime);
|
||||
else
|
||||
S_PaintChannelFrom16(ch, sc, count, ltime - paintedtime);
|
||||
|
||||
ltime += count;
|
||||
}
|
||||
|
||||
// if at end of loop, restart
|
||||
if (ltime >= ch->end)
|
||||
{
|
||||
if (ch->autosound)
|
||||
{ // autolooping sounds always go back to start
|
||||
ch->pos = 0;
|
||||
ch->end = ltime + sc->length;
|
||||
}
|
||||
else if (sc->loopstart >= 0)
|
||||
{
|
||||
ch->pos = sc->loopstart;
|
||||
ch->end = ltime + sc->length - ch->pos;
|
||||
}
|
||||
else
|
||||
{ // channel just stopped
|
||||
ch->sfx = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// transfer out according to DMA format
|
||||
S_TransferPaintBuffer(end);
|
||||
paintedtime = end;
|
||||
}
|
||||
}
|
||||
|
||||
void S_InitScaletable (void)
|
||||
{
|
||||
int i, j;
|
||||
int scale;
|
||||
|
||||
s_volume->modified = false;
|
||||
for (i=0 ; i<32 ; i++)
|
||||
{
|
||||
scale = i * 8 * 256 * s_volume->value;
|
||||
for (j=0 ; j<256 ; j++)
|
||||
snd_scaletable[i][j] = ((signed char)j) * scale;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if !(defined __linux__ && defined __i386__)
|
||||
#if !id386
|
||||
|
||||
void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count, int offset)
|
||||
{
|
||||
int data;
|
||||
int *lscale, *rscale;
|
||||
unsigned char *sfx;
|
||||
int i;
|
||||
portable_samplepair_t *samp;
|
||||
|
||||
if (ch->leftvol > 255)
|
||||
ch->leftvol = 255;
|
||||
if (ch->rightvol > 255)
|
||||
ch->rightvol = 255;
|
||||
|
||||
lscale = snd_scaletable[ ch->leftvol >> 11];
|
||||
rscale = snd_scaletable[ ch->rightvol >> 11];
|
||||
sfx = (signed char *)sc->data + ch->pos;
|
||||
|
||||
samp = &paintbuffer[offset];
|
||||
|
||||
for (i=0 ; i<count ; i++, samp++)
|
||||
{
|
||||
data = sfx[i];
|
||||
samp->left += lscale[data];
|
||||
samp->right += rscale[data];
|
||||
}
|
||||
|
||||
ch->pos += count;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
__declspec( naked ) void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count, int offset)
|
||||
{
|
||||
__asm {
|
||||
push esi
|
||||
push edi
|
||||
push ebx
|
||||
push ebp
|
||||
mov ebx,ds:dword ptr[4+16+esp]
|
||||
mov esi,ds:dword ptr[8+16+esp]
|
||||
mov eax,ds:dword ptr[4+ebx]
|
||||
mov edx,ds:dword ptr[8+ebx]
|
||||
cmp eax,255
|
||||
jna LLeftSet
|
||||
mov eax,255
|
||||
LLeftSet:
|
||||
cmp edx,255
|
||||
jna LRightSet
|
||||
mov edx,255
|
||||
LRightSet:
|
||||
and eax,0F8h
|
||||
add esi,20
|
||||
and edx,0F8h
|
||||
mov edi,ds:dword ptr[16+ebx]
|
||||
mov ecx,ds:dword ptr[12+16+esp]
|
||||
add esi,edi
|
||||
shl eax,7
|
||||
add edi,ecx
|
||||
shl edx,7
|
||||
mov ds:dword ptr[16+ebx],edi
|
||||
add eax,offset snd_scaletable
|
||||
add edx,offset snd_scaletable
|
||||
sub ebx,ebx
|
||||
mov bl,ds:byte ptr[-1+esi+ecx*1]
|
||||
test ecx,1
|
||||
jz LMix8Loop
|
||||
mov edi,ds:dword ptr[eax+ebx*4]
|
||||
mov ebp,ds:dword ptr[edx+ebx*4]
|
||||
add edi,ds:dword ptr[paintbuffer+0-8+ecx*8]
|
||||
add ebp,ds:dword ptr[paintbuffer+4-8+ecx*8]
|
||||
mov ds:dword ptr[paintbuffer+0-8+ecx*8],edi
|
||||
mov ds:dword ptr[paintbuffer+4-8+ecx*8],ebp
|
||||
mov bl,ds:byte ptr[-2+esi+ecx*1]
|
||||
dec ecx
|
||||
jz LDone
|
||||
LMix8Loop:
|
||||
mov edi,ds:dword ptr[eax+ebx*4]
|
||||
mov ebp,ds:dword ptr[edx+ebx*4]
|
||||
add edi,ds:dword ptr[paintbuffer+0-8+ecx*8]
|
||||
add ebp,ds:dword ptr[paintbuffer+4-8+ecx*8]
|
||||
mov bl,ds:byte ptr[-2+esi+ecx*1]
|
||||
mov ds:dword ptr[paintbuffer+0-8+ecx*8],edi
|
||||
mov ds:dword ptr[paintbuffer+4-8+ecx*8],ebp
|
||||
mov edi,ds:dword ptr[eax+ebx*4]
|
||||
mov ebp,ds:dword ptr[edx+ebx*4]
|
||||
mov bl,ds:byte ptr[-3+esi+ecx*1]
|
||||
add edi,ds:dword ptr[paintbuffer+0-8*2+ecx*8]
|
||||
add ebp,ds:dword ptr[paintbuffer+4-8*2+ecx*8]
|
||||
mov ds:dword ptr[paintbuffer+0-8*2+ecx*8],edi
|
||||
mov ds:dword ptr[paintbuffer+4-8*2+ecx*8],ebp
|
||||
sub ecx,2
|
||||
jnz LMix8Loop
|
||||
LDone:
|
||||
pop ebp
|
||||
pop ebx
|
||||
pop edi
|
||||
pop esi
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count, int offset)
|
||||
{
|
||||
int data;
|
||||
int left, right;
|
||||
int leftvol, rightvol;
|
||||
signed short *sfx;
|
||||
int i;
|
||||
portable_samplepair_t *samp;
|
||||
|
||||
leftvol = ch->leftvol*snd_vol;
|
||||
rightvol = ch->rightvol*snd_vol;
|
||||
sfx = (signed short *)sc->data + ch->pos;
|
||||
|
||||
samp = &paintbuffer[offset];
|
||||
for (i=0 ; i<count ; i++, samp++)
|
||||
{
|
||||
data = sfx[i];
|
||||
left = (data * leftvol)>>8;
|
||||
right = (data * rightvol)>>8;
|
||||
samp->left += left;
|
||||
samp->right += right;
|
||||
}
|
||||
|
||||
ch->pos += count;
|
||||
}
|
||||
|
45
client/sound.h
Normal file
45
client/sound.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
struct sfx_s;
|
||||
|
||||
void S_Init (void);
|
||||
void S_Shutdown (void);
|
||||
|
||||
// if origin is NULL, the sound will be dynamically sourced from the entity
|
||||
void S_StartSound (vec3_t origin, int entnum, int entchannel, struct sfx_s *sfx, float fvol, float attenuation, float timeofs);
|
||||
void S_StartLocalSound (char *s);
|
||||
|
||||
void S_RawSamples (int samples, int rate, int width, int channels, byte *data);
|
||||
|
||||
void S_StopAllSounds(void);
|
||||
void S_Update (vec3_t origin, vec3_t v_forward, vec3_t v_right, vec3_t v_up);
|
||||
|
||||
void S_Activate (qboolean active);
|
||||
|
||||
void S_BeginRegistration (void);
|
||||
struct sfx_s *S_RegisterSound (char *sample);
|
||||
void S_EndRegistration (void);
|
||||
|
||||
struct sfx_s *S_FindName (char *name, qboolean create);
|
||||
|
||||
// the sound code makes callbacks to the client for entitiy position
|
||||
// information, so entities can be dynamically re-spatialized
|
||||
void CL_GetEntitySoundOrigin (int ent, vec3_t org);
|
42
client/vid.h
Normal file
42
client/vid.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// vid.h -- video driver defs
|
||||
|
||||
typedef struct vrect_s
|
||||
{
|
||||
int x,y,width,height;
|
||||
} vrect_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
} viddef_t;
|
||||
|
||||
extern viddef_t viddef; // global video state
|
||||
|
||||
// Video module initialisation etc
|
||||
void VID_Init (void);
|
||||
void VID_Shutdown (void);
|
||||
void VID_CheckChanges (void);
|
||||
|
||||
void VID_MenuInit( void );
|
||||
void VID_MenuDraw( void );
|
||||
const char *VID_MenuKey( int );
|
95
client/x86.c
Normal file
95
client/x86.c
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include "client.h"
|
||||
|
||||
#if id386
|
||||
|
||||
static unsigned long bias;
|
||||
static unsigned long *histogram;
|
||||
static unsigned long start, range;
|
||||
static unsigned long bias;
|
||||
|
||||
__declspec( naked ) void x86_TimerStart( void )
|
||||
{
|
||||
__asm _emit 0fh
|
||||
__asm _emit 31h
|
||||
__asm mov start, eax
|
||||
__asm ret
|
||||
}
|
||||
|
||||
__declspec( naked ) void x86_TimerStop( void )
|
||||
{
|
||||
__asm push edi
|
||||
__asm mov edi, histogram
|
||||
__asm _emit 0fh
|
||||
__asm _emit 31h
|
||||
__asm sub eax, start
|
||||
__asm sub eax, bias
|
||||
__asm js discard
|
||||
__asm cmp eax, range
|
||||
__asm jge discard
|
||||
__asm lea edi, [edi + eax*4]
|
||||
__asm inc dword ptr [edi]
|
||||
discard:
|
||||
__asm pop edi
|
||||
__asm ret
|
||||
}
|
||||
|
||||
#pragma warning( disable: 4035 )
|
||||
static __declspec( naked ) unsigned long x86_TimerStopBias( void )
|
||||
{
|
||||
__asm push edi
|
||||
__asm mov edi, histogram
|
||||
__asm _emit 0fh
|
||||
__asm _emit 31h
|
||||
__asm sub eax, start
|
||||
__asm pop edi
|
||||
__asm ret
|
||||
}
|
||||
#pragma warning( default:4035 )
|
||||
|
||||
void x86_TimerInit( unsigned long smallest, unsigned length )
|
||||
{
|
||||
int i;
|
||||
unsigned long biastable[100];
|
||||
|
||||
range = length;
|
||||
bias = 10000;
|
||||
|
||||
for ( i = 0; i < 100; i++ )
|
||||
{
|
||||
x86_TimerStart();
|
||||
biastable[i] = x86_TimerStopBias();
|
||||
|
||||
if ( bias > biastable[i] )
|
||||
bias = biastable[i];
|
||||
}
|
||||
|
||||
bias += smallest;
|
||||
histogram = Z_Malloc( range * sizeof( unsigned long ) );
|
||||
}
|
||||
|
||||
unsigned long *x86_TimerGetHistogram( void )
|
||||
{
|
||||
return histogram;
|
||||
}
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user