08 Jul 2011
This commit is contained in:
parent
3296d44539
commit
dc5dc9f653
33
change.log
33
change.log
|
@ -1,8 +1,35 @@
|
|||
build ????
|
||||
|
||||
Fixed wrong sound angles whe client see in the camera
|
||||
Fix crash on change gl_texturemode.
|
||||
Change relationsip for GetLocalPlayer. Now it's always valid.
|
||||
Client: fix drawing beams for 'solid' mode
|
||||
Image: fix BMP loader for 4-bit color bmp's
|
||||
Client: fix lightlevel calculating for local client (remove 'ambient' base from final value)
|
||||
GameUI: first implementation of custom strings and support 'strings.lst' parsing
|
||||
GameUI: replace unneeded button 'credits' with button 'previews'
|
||||
Render: fix sprite interpolation
|
||||
Render: fix angled sprites offset
|
||||
Render: implement detail textures like in Steam Half-Life (thx n00b)
|
||||
Client: rework env_funnel effect
|
||||
|
||||
build 1598
|
||||
|
||||
Client: fix crosshair drawing
|
||||
Sound: change libmad mp3 decoder on a mpg123
|
||||
Client: fix gibs randomization for TE_BREAKMODEL
|
||||
Engine: fix modelloader bug (engine crash after not found map)
|
||||
Video: add resolution 1366x768
|
||||
GameUI: fix skill select
|
||||
Network: change 'svc_setangle' message, include rollangle
|
||||
Render: fix chrome rendering on a studiomodels
|
||||
Render: added video memory economy mode - cvar 'gl_luminance_textures'
|
||||
GameDLL: first implementation of extended engineinterface. Metamod is supported now
|
||||
|
||||
build 1557
|
||||
|
||||
Sound: fixed wrong sound angles when client see in the camera
|
||||
Render: fix crash on change gl_texturemode and gl_anisotropy.
|
||||
Client: change relationsip for GetLocalPlayer. Now it's always valid.
|
||||
Server: rewrite SV_Multicast for correct work with custom user cameras
|
||||
Server: rewrite FIND_CLIENT_IN_PVS like in QW
|
||||
|
||||
build 1540
|
||||
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<html>
|
||||
<body>
|
||||
<pre>
|
||||
<h1>Build Log</h1>
|
||||
<h3>
|
||||
--------------------Configuration: cl_dll - Win32 Release--------------------
|
||||
</h3>
|
||||
<h3>Command Lines</h3>
|
||||
|
||||
|
||||
|
||||
<h3>Results</h3>
|
||||
client.dll - 0 error(s), 0 warning(s)
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -137,7 +137,7 @@ char* READ_STRING( void )
|
|||
if ( giRead+1 > giSize )
|
||||
break; // no more characters
|
||||
|
||||
c = READ_CHAR();
|
||||
c = READ_BYTE();
|
||||
if (c == -1 || c == 0)
|
||||
break;
|
||||
string[l] = c;
|
||||
|
|
|
@ -75,7 +75,8 @@ typedef struct texture_s
|
|||
struct texture_s *anim_next; // in the animation sequence
|
||||
struct texture_s *alternate_anims; // bmodels in frmae 1 use these
|
||||
int fb_texturenum; // auto-luma texturenum
|
||||
unsigned int unused[3]; // reserved
|
||||
int dt_texturenum; // detail-texture binding
|
||||
unsigned int unused[2]; // reserved
|
||||
} texture_t;
|
||||
|
||||
typedef struct
|
||||
|
|
|
@ -59,6 +59,7 @@ CBaseEntity
|
|||
|
||||
extern "C" EXPORT int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion );
|
||||
extern "C" EXPORT int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion );
|
||||
extern "C" EXPORT int Server_GetPhysicsInterface( int iVersion, server_physics_api_t *pfuncsFromEngine, physics_interface_t *pFunctionTable );
|
||||
|
||||
extern int DispatchSpawn( edict_t *pent );
|
||||
extern void DispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd );
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
// Holds engine functionality callbacks
|
||||
enginefuncs_t g_engfuncs;
|
||||
globalvars_t *gpGlobals;
|
||||
|
||||
server_physics_api_t g_physfuncs;
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
<html>
|
||||
<body>
|
||||
<pre>
|
||||
<h1>Build Log</h1>
|
||||
<h3>
|
||||
--------------------Configuration: hl - Win32 Release--------------------
|
||||
</h3>
|
||||
<h3>Command Lines</h3>
|
||||
Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP32FA.tmp" with contents
|
||||
[
|
||||
/nologo /G5 /MT /W3 /O2 /I "..\dlls" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\game_shared" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /D "CLIENT_WEAPONS" /Fr"..\temp\dlls\!release/" /Fp"..\temp\dlls\!release/hl.pch" /YX /Fo"..\temp\dlls\!release/" /Fd"..\temp\dlls\!release/" /FD /c
|
||||
"D:\Xash3D\src_main\dlls\client.cpp"
|
||||
]
|
||||
Creating command line "cl.exe @"C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP32FA.tmp""
|
||||
Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP32FB.tmp" with contents
|
||||
[
|
||||
kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"..\temp\dlls\!release/hl.pdb" /debug /machine:I386 /def:".\hl.def" /out:"..\temp\dlls\!release/hl.dll" /implib:"..\temp\dlls\!release/hl.lib"
|
||||
"\Xash3D\src_main\temp\dlls\!release\aflock.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\agrunt.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\airtank.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\animating.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\animation.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\apache.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\barnacle.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\barney.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\bigmomma.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\bloater.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\bmodels.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\bullsquid.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\buttons.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\cbase.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\client.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\combat.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\controller.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\crossbow.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\crowbar.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\defaultai.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\doors.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\effects.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\egon.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\explode.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\flyingmonster.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\func_break.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\func_tank.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\game.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\gamerules.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\gargantua.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\gauss.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\genericmonster.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\ggrenade.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\globals.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\gman.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\h_ai.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\h_battery.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\h_cine.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\h_cycler.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\h_export.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\handgrenade.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\hassassin.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\headcrab.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\healthkit.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\hgrunt.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\hl_wpn_glock.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\hornet.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\hornetgun.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\houndeye.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\ichthyosaur.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\islave.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\items.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\leech.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\lights.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\maprules.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\monstermaker.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\monsters.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\monsterstate.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\mortar.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\mp5.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\multiplay_gamerules.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\nihilanth.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\nodes.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\osprey.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\pathcorner.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\plane.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\plats.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\player.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\pm_debug.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\pm_math.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\pm_shared.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\python.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\rat.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\roach.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\rpg.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\satchel.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\schedule.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\scientist.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\scripted.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\shotgun.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\singleplay_gamerules.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\skill.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\sound.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\soundent.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\spectator.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\squadmonster.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\squeakgrenade.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\subs.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\talkmonster.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\teamplay_gamerules.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\tempmonster.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\tentacle.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\triggers.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\tripmine.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\turret.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\util.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\voice_gamemgr.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\weapons.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\world.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\xen.obj"
|
||||
"\Xash3D\src_main\temp\dlls\!release\zombie.obj"
|
||||
]
|
||||
Creating command line "link.exe @"C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP32FB.tmp""
|
||||
Creating temporary file "C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP32FC.bat" with contents
|
||||
[
|
||||
@echo off
|
||||
copy \Xash3D\src_main\temp\dlls\!release\hl.dll "D:\Xash3D\valve\dlls\hl.dll"
|
||||
]
|
||||
Creating command line ""C:\DOCUME~1\ÌÈØÀ\LOCALS~1\Temp\RSP32FC.bat""
|
||||
Compiling...
|
||||
client.cpp
|
||||
Linking...
|
||||
Creating library ..\temp\dlls\!release/hl.lib and object ..\temp\dlls\!release/hl.exp
|
||||
<h3>Output Window</h3>
|
||||
Performing Custom Build Step on \Xash3D\src_main\temp\dlls\!release\hl.dll
|
||||
‘ª®¯¨à®¢ ® ä ©«®¢: 1.
|
||||
|
||||
|
||||
|
||||
<h3>Results</h3>
|
||||
hl.dll - 0 error(s), 0 warning(s)
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,28 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
#ifndef PHYSCALLBACK_H
|
||||
#define PHYSCALLBACK_H
|
||||
#pragma once
|
||||
|
||||
#include "physint.h"
|
||||
|
||||
// Must be provided by user of this code
|
||||
extern server_physics_api_t g_physfuncs;
|
||||
|
||||
// The actual physic callbacks
|
||||
#define LINK_ENTITY (*g_physfuncs.pfnLinkEdict)
|
||||
#define PHYSICS_TIME (*g_physfuncs.pfnGetServerTime)
|
||||
|
||||
#endif //PHYSCALLBACK_H
|
|
@ -22,6 +22,11 @@
|
|||
#ifndef ENGINECALLBACK_H
|
||||
#include "enginecallback.h"
|
||||
#endif
|
||||
|
||||
#ifndef PHYSCALLBACK_H
|
||||
#include "physcallback.h"
|
||||
#endif
|
||||
|
||||
inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin, entvars_t *ent ); // implementation later in this file
|
||||
|
||||
extern globalvars_t *gpGlobals;
|
||||
|
|
|
@ -767,6 +767,7 @@ void CBasePlayerItem::AttachToPlayer ( CBasePlayer *pPlayer )
|
|||
pev->owner = pPlayer->edict();
|
||||
pev->nextthink = gpGlobals->time + .1;
|
||||
SetTouch( NULL );
|
||||
SetThink( NULL );
|
||||
}
|
||||
|
||||
// CALLED THROUGH the newly-touched weapon's instance. The existing player weapon is pOriginal
|
||||
|
|
110
dlls/world.cpp
110
dlls/world.cpp
|
@ -33,6 +33,7 @@
|
|||
#include "weapons.h"
|
||||
#include "gamerules.h"
|
||||
#include "teamplay_gamerules.h"
|
||||
#include "physcallback.h"
|
||||
|
||||
extern CGraph WorldGraph;
|
||||
extern CSoundEnt *pSoundEnt;
|
||||
|
@ -748,3 +749,112 @@ void CWorld :: KeyValue( KeyValueData *pkvd )
|
|||
else
|
||||
CBaseEntity::KeyValue( pkvd );
|
||||
}
|
||||
|
||||
//
|
||||
// Xash3D physics interface
|
||||
//
|
||||
|
||||
typedef void (__cdecl *LINK_ENTITY_FN)( entvars_t *pev );
|
||||
|
||||
//
|
||||
// attempt to create custom entity when default method is failed
|
||||
// 0 - attempt to create, -1 - reject to create
|
||||
//
|
||||
int DispatchCreateEntity( edict_t *pent, const char *szName )
|
||||
{
|
||||
/*
|
||||
#ifdef CREATE_ENTITY_TEST
|
||||
// quake armor entities. we just replaced it with item_battery...
|
||||
if( !strcmp( szName, "item_armor1" ) || !strcmp( szName, "item_armor2" ))
|
||||
{
|
||||
LINK_ENTITY_FN SpawnEdict;
|
||||
|
||||
// ugly method to get acess with himself exports
|
||||
SpawnEdict = (LINK_ENTITY_FN)GetProcAddress( GetModuleHandle( "hl" ), "item_battery" );
|
||||
|
||||
if( SpawnEdict != NULL ) // found the valid spawn
|
||||
{
|
||||
// BUGBUG: old classname hanging in memory
|
||||
pent->v.classname = ALLOC_STRING( "item_battery" );
|
||||
|
||||
// ALERT( at_console, "DispatchCreateEntity: replace %s with %s\n", szName, STRING( pent->v.classname ));
|
||||
|
||||
SpawnEdict( &pent->v );
|
||||
return 0; // handled
|
||||
}
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// run custom physics for each entity
|
||||
// return 0 to use built-in engine physic
|
||||
//
|
||||
int DispatchPhysicsEntity( edict_t *pEdict )
|
||||
{
|
||||
CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pEdict);
|
||||
|
||||
if( !pEntity )
|
||||
{
|
||||
// ALERT( at_console, "skip %s [%i] without private data\n", STRING( pEdict->v.classname ), ENTINDEX( pEdict ));
|
||||
return 0; // not initialized
|
||||
}
|
||||
|
||||
// NOTE: at this point pEntity assume to be valid
|
||||
/*
|
||||
#ifdef CUSTOM_PHYSICS_TEST
|
||||
// test alien controller without physics, thinking only
|
||||
if( FClassnameIs( pEntity->pev, "monster_alien_controller" ))
|
||||
{
|
||||
float thinktime;
|
||||
|
||||
thinktime = pEntity->pev->nextthink;
|
||||
if( thinktime <= 0.0f || thinktime > PHYSICS_TIME() + gpGlobals->frametime )
|
||||
return 1;
|
||||
|
||||
if( thinktime < PHYSICS_TIME( ))
|
||||
thinktime = PHYSICS_TIME(); // don't let things stay in the past.
|
||||
// it is possible to start that way
|
||||
// by a trigger with a local time.
|
||||
pEntity->pev->nextthink = 0.0f;
|
||||
gpGlobals->time = thinktime;
|
||||
|
||||
DispatchThink( pEdict );
|
||||
|
||||
#ifdef GRAVITY_TEST
|
||||
// stupid fake gravity test
|
||||
pEntity->pev->origin.z -= 1;
|
||||
LINK_ENTITY( pEdict, true );
|
||||
#endif
|
||||
|
||||
return 1; // handled
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static physics_interface_t gPhysicsInterface =
|
||||
{
|
||||
SV_PHYSICS_INTERFACE_VERSION,
|
||||
DispatchCreateEntity,
|
||||
DispatchPhysicsEntity,
|
||||
};
|
||||
|
||||
int Server_GetPhysicsInterface( int iVersion, server_physics_api_t *pfuncsFromEngine, physics_interface_t *pFunctionTable )
|
||||
{
|
||||
if ( !pFunctionTable || !pfuncsFromEngine || iVersion != SV_PHYSICS_INTERFACE_VERSION )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// copy new physics interface
|
||||
memcpy(&g_physfuncs, pfuncsFromEngine, sizeof(server_physics_api_t));
|
||||
|
||||
// fill engine callbacks
|
||||
memcpy( pFunctionTable, &gPhysicsInterface, sizeof( physics_interface_t ) );
|
||||
|
||||
return TRUE;
|
||||
}
|
|
@ -250,6 +250,96 @@ typedef struct cl_enginefuncs_s
|
|||
void (*pfnSetMousePos)( int x, int y );
|
||||
void (*pfnSetMouseEnable)( qboolean fEnable );
|
||||
|
||||
// Returns pointer to start of registered cvar linked list. Added for VGUI console autocomplete?
|
||||
void* (*pfnGetCvarList)( void );
|
||||
|
||||
// Returns pointer to start of registered command linked list. Added for VGUI console autocomplete?
|
||||
void* (*pfnGetCmdList)( void );
|
||||
|
||||
// Not sure about this - convert cvar_t pointer to cvar name? Why?
|
||||
char* (*pfnCvarNameFromPointer)( void *pointer );
|
||||
|
||||
// Not sure abput this - convert cmd_function_t pointer to command name? Why?
|
||||
char* (*pfnCmdNameFromPointer)( void *pointer );
|
||||
|
||||
// Returns current time for this client? Why is this needed when GetClientTime() already exists?
|
||||
float (*pfnGetCurrentTime)( void );
|
||||
|
||||
// Unsure - always seems to return 800.0f (no, it's not horizontal resolution)
|
||||
float (*pfnGetGravityFactor)( void );
|
||||
|
||||
// Appears to be identical to function in IEngineStudio
|
||||
void* (*pfnGetModelByIndex)( int index );
|
||||
|
||||
// Appears to modifies hidden cvar gl_texsort.
|
||||
void (*pfnSetGL_TexSort)( int value );
|
||||
|
||||
// Colour scaling values for screen. Only works when gl_texsort is active.
|
||||
void (*pfnSetGL_TexSort_Colour)( float red, float green, float blue );
|
||||
|
||||
// Final scaling factor for screen. Only works when gl_texsort is active.
|
||||
void (*pfnSetGL_TexSort_Scale)( float scale );
|
||||
|
||||
// Seems to be a client entry point to the pfnSequenceGet function introduced for CS:CZ
|
||||
void* (*pfnSequenceGet)( const char *fileName, const char *entryName );
|
||||
|
||||
// Draws a sprite on the screen - parameters are likely incorrect.
|
||||
void (*pfnDrawSpriteGeneric)( int frame, int x, int y, const wrect_t *prc, int u1, int u2, int u3, int u4 );
|
||||
|
||||
// Seems to be a client entry point to the pfnSequencePickSentence function introduced for CS:CZ
|
||||
void* (*pfnSequencePickSentence)( const char *groupName, int pickMethod, int *picked );
|
||||
|
||||
// Unknown (deals with wchar_t's)
|
||||
void (*pfnUnknownFunction6)( void *u1, void *u2, void *u3, void *u4, void *u5, void *u6 );
|
||||
|
||||
// Unknown (deals with wchar_t's)
|
||||
void (*pfnUnknownFunction7)( void *u1, void *u2 );
|
||||
|
||||
// Unknown (something to do with players infostring?)
|
||||
char* (*pfnUnknownFunction8)( char *u1 );
|
||||
|
||||
// Completely unknown
|
||||
void (*pfnUnknownFunction9)( void *u1, void *u2 );
|
||||
|
||||
// Completely unknown
|
||||
void (*pfnUnknownFunction10)( void *u1, void *u2, void *u3, void *u4, void *u5 );
|
||||
|
||||
// Seems to be a client entry point to the pfnGetApproxWavePlayLen function introduced for CS:CZ
|
||||
unsigned int (*pfnGetApproxWavePlayLen)( char *filename );
|
||||
|
||||
// Completely unknown
|
||||
int (*pfnUnknownFunction11)( void );
|
||||
|
||||
// Sets cvar value - why is this needed when Cvar_SetValue already exists?
|
||||
void (*Cvar_Set)( char *name, char *value );
|
||||
|
||||
// Seems to be a client entry point to the pfnIsCareerMatch function introduced for CS:CZ
|
||||
int (*pfnIsCareerMatch)( void );
|
||||
|
||||
// Starts a local sound - why is this needed?
|
||||
void (*pfnStartDynamicSound)( char *filename, float volume, float pitch );
|
||||
|
||||
// MP3 interface - unsure what int parameter is. Just queues the sound up - have to issue command "mp3 play" to start it. */
|
||||
void (*pfnMP3_InitStream)( char *filename, int i1 );
|
||||
|
||||
// Returns unknown, constantly increasing float. Timing? (calls QueryPerformanceCounters)
|
||||
float (*pfnUnknownFunction12)( void );
|
||||
|
||||
// Seems to be a client entry point to the pfnProcessTutorMessageDecayBuffer function introduced for CS:CZ
|
||||
void (*pfnProcessTutorMessageDecayBuffer)( int *buffer, int buflen );
|
||||
|
||||
// Seems to be a client entry point to the pfnConstructTutorMessageDecayBuffer function introduced for CS:CZ
|
||||
void (*pfnConstructTutorMessageDecayBuffer)( int *buffer, int buflen );
|
||||
|
||||
// Seems to be a client entry point to the pfnResetTutorMessageDecayData function introduced for CS:CZ
|
||||
void (*pfnResetTutorMessageDecayData)( void );
|
||||
|
||||
// Seems to be an exact copy of the previous StartDynamicSound function???
|
||||
void (*pfnStartDynamicSound2)( char *filename, float volume, float pitch );
|
||||
|
||||
// Seems to be an exact copy of the previous FillRGBA function???
|
||||
void (*pfnFillRGBA2)( int x, int y, int width, int height, int r, int g, int b, int a );
|
||||
|
||||
} cl_enginefunc_t;
|
||||
|
||||
#define CLDLL_INTERFACE_VERSION 7
|
||||
|
|
|
@ -110,15 +110,9 @@ void CL_UpdateEntityFields( cl_entity_t *ent )
|
|||
|
||||
if( m_pGround && m_pGround->curstate.movetype == MOVETYPE_PUSH )
|
||||
{
|
||||
studiohdr_t *phdr;
|
||||
mstudioseqdesc_t *pseqdesc;
|
||||
qboolean applyVel, applyAvel;
|
||||
qboolean applyVel, applyAvel;
|
||||
|
||||
d = 1.0f - cl.lerpFrac; // use backlerp to interpolate pusher position
|
||||
phdr = (studiohdr_t *)Mod_Extradata( ent->model );
|
||||
ASSERT( phdr != NULL );
|
||||
pseqdesc = (mstudioseqdesc_t *)((byte *)phdr + phdr->seqindex) + ent->curstate.sequence;
|
||||
|
||||
d = d - 1.0f;
|
||||
|
||||
applyVel = !VectorCompare( m_pGround->curstate.origin, m_pGround->prevstate.origin );
|
||||
|
|
|
@ -867,7 +867,7 @@ void CL_DrawCrosshair( void )
|
|||
|
||||
clgame.ds.pSprite = clgame.ds.pCrosshair;
|
||||
|
||||
GL_SetRenderMode( kRenderTransAlpha );
|
||||
GL_SetRenderMode( kRenderTransTexture );
|
||||
*(int *)clgame.ds.spriteColor = *(int *)clgame.ds.rgbaCrosshair;
|
||||
|
||||
SPR_EnableScissor( x - 0.5f * width, y - 0.5f * height, width, height );
|
||||
|
@ -3685,7 +3685,7 @@ void CL_UnloadProgs( void )
|
|||
Q_memset( &clgame, 0, sizeof( clgame ));
|
||||
|
||||
Cvar_Unlink();
|
||||
Cmd_Unlink();
|
||||
Cmd_Unlink( CMD_CLIENTDLL );
|
||||
}
|
||||
|
||||
qboolean CL_LoadProgs( const char *name )
|
||||
|
|
|
@ -259,7 +259,7 @@ usercmd_t CL_CreateCmd( void )
|
|||
active = ( cls.state == ca_active && !cl.refdef.paused && !cl.refdef.intermission );
|
||||
clgame.dllFuncs.CL_CreateMove( cl.time - cl.oldtime, &cmd, active );
|
||||
|
||||
R_LightForPoint( cl.frame.local.client.origin, &color, false, 128.0f );
|
||||
R_LightForPoint( cl.frame.local.client.origin, &color, false, false, 128.0f );
|
||||
cmd.lightlevel = (color.r + color.g + color.b) / 3;
|
||||
|
||||
// never let client.dll calc frametime for player
|
||||
|
@ -818,6 +818,33 @@ void CL_LocalServers_f( void )
|
|||
Netchan_OutOfBandPrint( NS_CLIENT, adr, "info %i", PROTOCOL_VERSION );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_InternetServers_f
|
||||
=================
|
||||
*/
|
||||
void CL_InternetServers_f( void )
|
||||
{
|
||||
netadr_t adr;
|
||||
char part1query[12];
|
||||
char part2query[128];
|
||||
string fullquery;
|
||||
|
||||
MsgDev( D_INFO, "Scanning for servers on the internet area...\n" );
|
||||
NET_Config( true ); // allow remote
|
||||
|
||||
if( !NET_StringToAdr( MASTERSERVER_ADR, &adr ) )
|
||||
MsgDev( D_INFO, "Can't resolve adr: %s\n", MASTERSERVER_ADR );
|
||||
|
||||
Q_snprintf( part1query, sizeof( part1query ), "%c%c0.0.0.0:0", 0x31, 0xFF );
|
||||
Q_snprintf( part2query, sizeof( part2query ), "\\gamedir\\%s_xash\\nap\\%d", GI->gamedir, 70 );
|
||||
|
||||
Q_memcpy( fullquery, part1query, sizeof( part1query ));
|
||||
Q_memcpy( fullquery + sizeof( part1query ), part2query, Q_strlen( part2query ));
|
||||
|
||||
NET_SendPacket( NS_CLIENT, sizeof( part1query ) + Q_strlen( part2query ) + 1, fullquery, adr );
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
CL_Packet_f
|
||||
|
@ -1116,6 +1143,8 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
|
|||
char *args;
|
||||
char *c, buf[MAX_SYSPATH];
|
||||
int len = sizeof( buf );
|
||||
int dataoffset = 0;
|
||||
netadr_t servadr;
|
||||
|
||||
BF_Clear( msg );
|
||||
BF_ReadLong( msg ); // skip the -1
|
||||
|
@ -1202,6 +1231,33 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
|
|||
// user out of band message (must be handled in CL_ConnectionlessPacket)
|
||||
if( len > 0 ) Netchan_OutOfBand( NS_SERVER, from, len, buf );
|
||||
}
|
||||
else if( msg->pData[0] == 0xFF && msg->pData[1] == 0xFF && msg->pData[2] == 0xFF && msg->pData[3] == 0xFF && msg->pData[4] == 0x66 && msg->pData[5] == 0x0A )
|
||||
{
|
||||
dataoffset = 6;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
servadr.type = NA_IP;
|
||||
servadr.ip[0] = msg->pData[dataoffset + 0];
|
||||
servadr.ip[1] = msg->pData[dataoffset + 1];
|
||||
servadr.ip[2] = msg->pData[dataoffset + 2];
|
||||
servadr.ip[3] = msg->pData[dataoffset + 3];
|
||||
|
||||
servadr.port = *(word *)&msg->pData[dataoffset + 4];
|
||||
|
||||
if( !servadr.port )
|
||||
break;
|
||||
|
||||
MsgDev( D_INFO, "Found server: %s\n", NET_AdrToString( servadr ));
|
||||
|
||||
NET_Config( true ); // allow remote
|
||||
|
||||
Netchan_OutOfBandPrint( NS_CLIENT, servadr, "info %i", PROTOCOL_VERSION );
|
||||
|
||||
dataoffset += 6;
|
||||
|
||||
}
|
||||
}
|
||||
else MsgDev( D_ERROR, "bad connectionless packet from %s:\n%s\n", NET_AdrToString( from ), args );
|
||||
}
|
||||
|
||||
|
@ -1277,8 +1333,8 @@ void CL_ReadNetMessage( void )
|
|||
|
||||
if( Netchan_CopyFileFragments( &cls.netchan, &net_message ))
|
||||
{
|
||||
// Remove from resource request stuff.
|
||||
// CL_ProcessFile( true, cls.netchan.incomingfilename );
|
||||
// remove from resource request stuff.
|
||||
CL_ProcessFile( true, cls.netchan.incomingfilename );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1315,6 +1371,28 @@ void CL_ReadPackets( void )
|
|||
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
CL_ProcessFile
|
||||
|
||||
A file has been received via the fragmentation/reassembly layer, put it in the right spot and
|
||||
see if we have finished downloading files.
|
||||
====================
|
||||
*/
|
||||
void CL_ProcessFile( BOOL successfully_received, const char *filename )
|
||||
{
|
||||
MsgDev( D_INFO, "Received %s, but file processing is not hooked up!!!\n", filename );
|
||||
|
||||
if( cls.downloadfileid == cls.downloadcount - 1 )
|
||||
{
|
||||
MsgDev( D_INFO,"All Files downloaded\n" );
|
||||
|
||||
BF_WriteByte( &cls.netchan.message, clc_stringcmd );
|
||||
BF_WriteString( &cls.netchan.message, "continueloading" );
|
||||
}
|
||||
|
||||
cls.downloadfileid++;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
/*
|
||||
|
@ -1443,6 +1521,7 @@ void CL_InitLocal( void )
|
|||
// register our commands
|
||||
Cmd_AddCommand ("pause", NULL, "pause the game (if the server allows pausing)" );
|
||||
Cmd_AddCommand ("localservers", CL_LocalServers_f, "collect info about local servers" );
|
||||
Cmd_AddCommand ("internetservers", CL_InternetServers_f, "collect info about internet servers" );
|
||||
Cmd_AddCommand ("cd", CL_PlayCDTrack_f, "Play cd-track (not real cd-player of course)" );
|
||||
|
||||
Cmd_AddCommand ("userinfo", CL_Userinfo_f, "print current client userinfo" );
|
||||
|
|
|
@ -38,7 +38,6 @@ void UI_UpdateMenu( float realtime )
|
|||
if( !menu.hInstance ) return;
|
||||
menu.dllFuncs.pfnRedraw( realtime );
|
||||
UI_UpdateUserinfo();
|
||||
Con_DrawVersion();
|
||||
}
|
||||
|
||||
void UI_KeyEvent( int key, qboolean down )
|
||||
|
|
|
@ -72,9 +72,9 @@ const char *svc_strings[256] =
|
|||
"svc_packetentities",
|
||||
"svc_deltapacketentities",
|
||||
"svc_chokecount",
|
||||
"svc_unused43",
|
||||
"svc_resourcelist",
|
||||
"svc_deltamovevars",
|
||||
"svc_unused45",
|
||||
"svc_customization",
|
||||
"svc_unused46",
|
||||
"svc_crosshairangle",
|
||||
"svc_soundfade",
|
||||
|
@ -97,8 +97,9 @@ typedef struct
|
|||
qboolean parsing;
|
||||
} msg_debug_t;
|
||||
|
||||
static msg_debug_t cls_message_debug;
|
||||
static int starting_count;
|
||||
static msg_debug_t cls_message_debug;
|
||||
static int starting_count;
|
||||
static resourcelist_t reslist;
|
||||
|
||||
const char *CL_MsgInfo( int cmd )
|
||||
{
|
||||
|
@ -450,6 +451,11 @@ void CL_ParseEvent( sizebuf_t *msg )
|
|||
CL_ParseReliableEvent( msg, 0 );
|
||||
}
|
||||
|
||||
void CL_ParseCustomization( sizebuf_t *msg )
|
||||
{
|
||||
// FIXME: ???
|
||||
}
|
||||
|
||||
/*
|
||||
=====================================================================
|
||||
|
||||
|
@ -695,6 +701,7 @@ void CL_ParseSetAngle( sizebuf_t *msg )
|
|||
{
|
||||
cl.refdef.cl_viewangles[0] = BF_ReadBitAngle( msg, 16 );
|
||||
cl.refdef.cl_viewangles[1] = BF_ReadBitAngle( msg, 16 );
|
||||
cl.refdef.cl_viewangles[2] = BF_ReadBitAngle( msg, 16 );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -893,6 +900,88 @@ void CL_ServerInfo( sizebuf_t *msg )
|
|||
Info_SetValueForKey( cl.serverinfo, key, value );
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
CL_CheckingResFile
|
||||
|
||||
==============
|
||||
*/
|
||||
void CL_CheckingResFile( char *pResFileName )
|
||||
{
|
||||
sizebuf_t buf;
|
||||
byte data[32];
|
||||
|
||||
if( FS_FileExists( pResFileName, false ))
|
||||
return; // already existing
|
||||
|
||||
cls.downloadcount++;
|
||||
|
||||
Msg( "Starting downloads file: %s\n", pResFileName );
|
||||
|
||||
if( cls.state == ca_disconnected ) return;
|
||||
|
||||
BF_Init( &buf, "ClientPacket", data, sizeof( data ));
|
||||
BF_WriteByte( &buf, clc_resourcelist );
|
||||
BF_WriteString( &buf, pResFileName );
|
||||
|
||||
if( !cls.netchan.remote_address.type ) // download in singleplayer ???
|
||||
cls.netchan.remote_address.type = NA_LOOPBACK;
|
||||
|
||||
// make sure message will be delivered
|
||||
Netchan_Transmit( &cls.netchan, BF_GetNumBytesWritten( &buf ), BF_GetData( &buf ));
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
CL_CheckingSoundResFile
|
||||
|
||||
==============
|
||||
*/
|
||||
void CL_CheckingSoundResFile( char *pResFileName )
|
||||
{
|
||||
string filepath;
|
||||
|
||||
Q_snprintf( filepath, sizeof( filepath ), "sound/%s", pResFileName );
|
||||
CL_CheckingResFile( filepath );
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
CL_ParseResourceList
|
||||
|
||||
==============
|
||||
*/
|
||||
void CL_ParseResourceList( sizebuf_t *msg )
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
Q_memset( &reslist, 0, sizeof( resourcelist_t ));
|
||||
|
||||
reslist.rescount = BF_ReadWord( msg ) - 1;
|
||||
|
||||
for( i = 0; i < reslist.rescount; i++ )
|
||||
{
|
||||
reslist.restype[i] = BF_ReadWord( msg );
|
||||
Q_strncpy( reslist.resnames[i], BF_ReadString( msg ), CS_SIZE );
|
||||
}
|
||||
|
||||
cls.downloadcount = 0;
|
||||
|
||||
for( i = 0; i < reslist.rescount; i++ )
|
||||
{
|
||||
if( reslist.restype[i] == t_sound )
|
||||
CL_CheckingSoundResFile( reslist.resnames[i] );
|
||||
else CL_CheckingResFile( reslist.resnames[i] );
|
||||
}
|
||||
|
||||
if( !cls.downloadcount )
|
||||
{
|
||||
BF_WriteByte( &cls.netchan.message, clc_stringcmd );
|
||||
BF_WriteString( &cls.netchan.message, "continueloading" );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
CL_ParseDirector
|
||||
|
@ -1229,6 +1318,9 @@ void CL_ParseServerMessage( sizebuf_t *msg )
|
|||
case svc_deltamovevars:
|
||||
CL_ParseMovevars( msg );
|
||||
break;
|
||||
case svc_customization:
|
||||
CL_ParseCustomization( msg );
|
||||
break;
|
||||
case svc_centerprint:
|
||||
CL_CenterPrint( BF_ReadString( msg ), 0.35f );
|
||||
break;
|
||||
|
@ -1293,6 +1385,9 @@ void CL_ParseServerMessage( sizebuf_t *msg )
|
|||
}
|
||||
}
|
||||
break;
|
||||
case svc_resourcelist:
|
||||
CL_ParseResourceList( msg );
|
||||
break;
|
||||
case svc_director:
|
||||
CL_ParseDirector( msg );
|
||||
break;
|
||||
|
|
|
@ -47,6 +47,7 @@ void SCR_DrawFPS( void )
|
|||
static int framecount = 0;
|
||||
double newtime;
|
||||
char fpsstring[32];
|
||||
int offset;
|
||||
|
||||
if( cls.state != ca_active ) return;
|
||||
if( !cl_showfps->integer || cl.background ) return;
|
||||
|
@ -75,7 +76,9 @@ void SCR_DrawFPS( void )
|
|||
Q_snprintf( fpsstring, sizeof( fpsstring ), "%4i fps", (int)(calc + 0.5));
|
||||
MakeRGBA( color, 255, 255, 255, 255 );
|
||||
}
|
||||
Con_DrawString( scr_width->integer - 68, 4, fpsstring, color );
|
||||
|
||||
Con_DrawStringLen( fpsstring, &offset, NULL );
|
||||
Con_DrawString( scr_width->integer - offset - 2, 4, fpsstring, color );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -446,7 +449,7 @@ void SCR_Init( void )
|
|||
|
||||
if( host.state != HOST_RESTART && !UI_LoadProgs( ))
|
||||
{
|
||||
Msg( "^1Error: ^7can't initialize MainUI.dll\n" ); // there is non fatal for us
|
||||
Msg( "^1Error: ^7can't initialize menu.dll\n" ); // there is non fatal for us
|
||||
if( !host.developer ) host.developer = 1; // we need console, because menu is missing
|
||||
}
|
||||
|
||||
|
|
|
@ -866,11 +866,12 @@ CL_BreakModel
|
|||
Create a shards
|
||||
==============
|
||||
*/
|
||||
void CL_BreakModel( const vec3_t pos, const vec3_t size, const vec3_t dir, float random, float life, int count, int modelIndex, char flags )
|
||||
void CL_BreakModel( const vec3_t pos, const vec3_t size, const vec3_t direction, float random, float life, int count, int modelIndex, char flags )
|
||||
{
|
||||
int i, frameCount;
|
||||
TEMPENTITY *pTemp;
|
||||
char type;
|
||||
vec3_t dir;
|
||||
|
||||
if( !modelIndex ) return;
|
||||
type = flags & BREAK_TYPEMASK;
|
||||
|
@ -886,13 +887,28 @@ void CL_BreakModel( const vec3_t pos, const vec3_t size, const vec3_t dir, float
|
|||
count = (size[0] * size[1] + size[1] * size[2] + size[2] * size[0]) / (3 * SHARD_VOLUME * SHARD_VOLUME);
|
||||
}
|
||||
|
||||
VectorCopy( direction, dir );
|
||||
|
||||
// limit to 100 pieces
|
||||
if( count > 100 ) count = 100;
|
||||
|
||||
if( VectorIsNull( direction ))
|
||||
random *= 10;
|
||||
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
vec3_t vecSpot;
|
||||
|
||||
if( VectorIsNull( direction ))
|
||||
{
|
||||
// random direction for each piece
|
||||
dir[0] = Com_RandomFloat( -1.0f, 1.0f );
|
||||
dir[1] = Com_RandomFloat( -1.0f, 1.0f );
|
||||
dir[2] = Com_RandomFloat( -1.0f, 1.0f );
|
||||
|
||||
VectorNormalize( dir );
|
||||
}
|
||||
|
||||
// fill up the box with stuff
|
||||
vecSpot[0] = pos[0] + Com_RandomFloat( -0.5f, 0.5f ) * size[0];
|
||||
vecSpot[1] = pos[1] + Com_RandomFloat( -0.5f, 0.5f ) * size[1];
|
||||
|
@ -1287,46 +1303,46 @@ void CL_FunnelSprite( const vec3_t pos, int spriteIndex, int flags )
|
|||
{
|
||||
for( j = -256; j <= 256; j += 32 )
|
||||
{
|
||||
if( pTemp || !spriteIndex )
|
||||
if( flags & SF_FUNNEL_REVERSE )
|
||||
{
|
||||
pPart = CL_AllocParticle( NULL );
|
||||
pTemp = NULL;
|
||||
VectorCopy( pos, m_vecPos );
|
||||
|
||||
dest[0] = pos[0] + i;
|
||||
dest[1] = pos[1] + j;
|
||||
dest[2] = pos[2] + Com_RandomFloat( 100, 800 );
|
||||
|
||||
// send particle heading to dest at a random speed
|
||||
VectorSubtract( dest, m_vecPos, dir );
|
||||
|
||||
// velocity based on how far particle has to travel away from org
|
||||
vel = dest[2] / 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_vecPos[0] = pos[0] + i;
|
||||
m_vecPos[1] = pos[1] + j;
|
||||
m_vecPos[2] = pos[2] + Com_RandomFloat( 100, 800 );
|
||||
|
||||
// send particle heading to org at a random speed
|
||||
VectorSubtract( pos, m_vecPos, dir );
|
||||
|
||||
// velocity based on how far particle starts from org
|
||||
vel = m_vecPos[2] / 8;
|
||||
}
|
||||
|
||||
if( pPart && spriteIndex && CL_PointContents( m_vecPos ) == CONTENTS_EMPTY )
|
||||
{
|
||||
pTemp = CL_TempEntAlloc( pos, Mod_Handle( spriteIndex ));
|
||||
pPart = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
pPart = CL_AllocParticle( NULL );
|
||||
pTemp = NULL;
|
||||
}
|
||||
|
||||
if( pTemp || pPart )
|
||||
{
|
||||
if( flags & SF_FUNNEL_REVERSE )
|
||||
{
|
||||
VectorCopy( pos, m_vecPos );
|
||||
|
||||
dest[0] = pos[0] + i;
|
||||
dest[1] = pos[1] + j;
|
||||
dest[2] = pos[2] + Com_RandomFloat( 100, 800 );
|
||||
|
||||
// send particle heading to dest at a random speed
|
||||
VectorSubtract( dest, m_vecPos, dir );
|
||||
|
||||
// velocity based on how far particle has to travel away from org
|
||||
vel = dest[2] / 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_vecPos[0] = pos[0] + i;
|
||||
m_vecPos[1] = pos[1] + j;
|
||||
m_vecPos[2] = pos[2] + Com_RandomFloat( 100, 800 );
|
||||
|
||||
// send particle heading to org at a random speed
|
||||
VectorSubtract( pos, m_vecPos, dir );
|
||||
|
||||
// velocity based on how far particle starts from org
|
||||
vel = m_vecPos[2] / 8;
|
||||
}
|
||||
|
||||
flDist = VectorNormalizeLength( dir ); // save the distance
|
||||
if( vel < 64 ) vel = 64;
|
||||
|
||||
|
@ -1339,9 +1355,10 @@ void CL_FunnelSprite( const vec3_t pos, int spriteIndex, int flags )
|
|||
VectorScale( dir, vel, pTemp->entity.baseline.origin );
|
||||
pTemp->entity.curstate.rendermode = kRenderTransAdd;
|
||||
pTemp->flags |= FTENT_FADEOUT;
|
||||
pTemp->fadeSpeed = 2.0f;
|
||||
pTemp->die = cl.time + Com_RandomFloat( life * 0.5, life );
|
||||
pTemp->fadeSpeed = 3.0f;
|
||||
pTemp->die = cl.time + life - Com_RandomFloat( 0.5f, 0.6f );
|
||||
pTemp->entity.curstate.renderamt = pTemp->entity.baseline.renderamt = 255;
|
||||
pTemp->entity.curstate.scale = 0.75f;
|
||||
}
|
||||
|
||||
if( pPart )
|
||||
|
@ -1352,7 +1369,7 @@ void CL_FunnelSprite( const vec3_t pos, int spriteIndex, int flags )
|
|||
|
||||
VectorScale( dir, vel, pPart->vel );
|
||||
// die right when you get there
|
||||
pPart->die += Com_RandomFloat( life * 0.5f, life );
|
||||
pPart->die += life;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2394,7 +2411,7 @@ void CL_UpdateFlashlight( cl_entity_t *pEnt )
|
|||
VectorClear( view_ofs );
|
||||
|
||||
if(( pEnt->index - 1 ) == cl.playernum )
|
||||
VectorCopy( cl.predicted_viewofs, view_ofs );
|
||||
VectorCopy( cl.refdef.viewheight, view_ofs );
|
||||
|
||||
VectorAdd( pEnt->origin, view_ofs, vecSrc );
|
||||
VectorMA( vecSrc, FLASHLIGHT_DISTANCE, forward, vecEnd );
|
||||
|
|
|
@ -182,6 +182,7 @@ void V_PostRender( void )
|
|||
CL_DrawHUD( CL_CHANGELEVEL );
|
||||
Con_DrawConsole();
|
||||
UI_UpdateMenu( host.realtime );
|
||||
Con_DrawVersion();
|
||||
Con_DrawDebug(); // must be last
|
||||
S_ExtraUpdate();
|
||||
}
|
||||
|
|
|
@ -162,7 +162,8 @@ typedef enum
|
|||
{
|
||||
key_console = 0,
|
||||
key_game,
|
||||
key_menu
|
||||
key_menu,
|
||||
key_message
|
||||
} keydest_t;
|
||||
|
||||
typedef enum
|
||||
|
@ -441,6 +442,10 @@ typedef struct
|
|||
const float *envshot_vieworg; // envshot position
|
||||
string shotname;
|
||||
|
||||
// download info
|
||||
int downloadcount;
|
||||
int downloadfileid;
|
||||
|
||||
// demo loop control
|
||||
int demonum; // -1 = don't play demos
|
||||
string demos[MAX_DEMOS]; // when not playing
|
||||
|
@ -531,6 +536,7 @@ void SCR_TimeRefresh_f( void );
|
|||
void CL_Init( void );
|
||||
void CL_SendCommand( void );
|
||||
void CL_Disconnect_f( void );
|
||||
void CL_ProcessFile( qboolean successfully_received, const char *filename );
|
||||
void CL_GetChallengePacket( void );
|
||||
void CL_PingServers_f( void );
|
||||
void CL_ClearState( void );
|
||||
|
@ -690,6 +696,7 @@ int Con_DrawString( int x, int y, const char *string, rgba_t setColor );
|
|||
void Con_DefaultColor( int r, int g, int b );
|
||||
void Con_CharEvent( int key );
|
||||
void Key_Console( int key );
|
||||
void Key_Message( int key );
|
||||
void Con_Close( void );
|
||||
|
||||
//
|
||||
|
|
|
@ -560,19 +560,25 @@ void R_ShowTextures( void )
|
|||
R_Set2DMode( true );
|
||||
}
|
||||
|
||||
if( gl_showtextures->integer == TEX_DETAIL )
|
||||
pglClearColor( 1.0f, 0.0f, 0.5f, 1.0f );
|
||||
|
||||
pglClear( GL_COLOR_BUFFER_BIT );
|
||||
pglFinish();
|
||||
|
||||
if( gl_showtextures->integer == TEX_LIGHTMAP || gl_showtextures->integer == TEX_VGUI )
|
||||
switch( gl_showtextures->integer )
|
||||
{
|
||||
case TEX_LIGHTMAP:
|
||||
case TEX_VGUI:
|
||||
case TEX_DETAIL:
|
||||
// draw lightmaps as big images
|
||||
base_w = 5;
|
||||
base_h = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
default:
|
||||
base_w = 16;
|
||||
base_h = 12;
|
||||
break;
|
||||
}
|
||||
|
||||
for( i = j = 0; i < MAX_TEXTURES; i++ )
|
||||
|
|
|
@ -1412,7 +1412,7 @@ void CL_DrawBeam( BEAM *pbeam )
|
|||
}
|
||||
|
||||
frame = ((int)( pbeam->frame + cl.time * pbeam->frameRate ) % pbeam->frameCount );
|
||||
rendermode = ( pbeam->flags & FBEAM_SOLID ) ? kRenderNormal : kRenderTransAdd;
|
||||
rendermode = ( pbeam->flags & FBEAM_SOLID ) ? kRenderTransColor : kRenderTransAdd;
|
||||
|
||||
// set color
|
||||
VectorSet( srcColor, pbeam->r, pbeam->g, pbeam->b );
|
||||
|
|
|
@ -566,6 +566,8 @@ static void R_DecalCreate( decalinfo_t *decalinfo, msurface_t *surf, float x, fl
|
|||
if( count < MAX_OVERLAP_DECALS ) pold = NULL;
|
||||
|
||||
pdecal = R_DecalAlloc( pold );
|
||||
if( !pdecal ) return; // r_decals == 0 ???
|
||||
|
||||
pdecal->flags = decalinfo->m_Flags;
|
||||
|
||||
VectorCopy( decalinfo->m_Position, pdecal->position );
|
||||
|
|
|
@ -201,7 +201,9 @@ typedef float GLmatrix[16];
|
|||
#define GL_LUMINANCE8_ALPHA8 0x8045
|
||||
#define GL_LUMINANCE12_ALPHA4 0x8046
|
||||
#define GL_LUMINANCE12_ALPHA12 0x8047
|
||||
#define GL_LUMINANCE16_ALPHA16 0x8048
|
||||
#define GL_LUMINANCE16_ALPHA16 0x8048
|
||||
#define GL_LUMINANCE 0x1909
|
||||
#define GL_LUMINANCE_ALPHA 0x190A
|
||||
#define GL_DEPTH_COMPONENT 0x1902
|
||||
#define GL_INTENSITY 0x8049
|
||||
#define GL_INTENSITY4 0x804A
|
||||
|
|
|
@ -124,6 +124,19 @@ GL_TexFilter
|
|||
*/
|
||||
void GL_TexFilter( gltexture_t *tex, qboolean update )
|
||||
{
|
||||
qboolean allowNearest;
|
||||
|
||||
switch( tex->texType )
|
||||
{
|
||||
case TEX_NOMIP:
|
||||
case TEX_LIGHTMAP:
|
||||
allowNearest = false;
|
||||
break;
|
||||
default:
|
||||
allowNearest = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// set texture filter
|
||||
if( tex->flags & TF_DEPTHMAP )
|
||||
{
|
||||
|
@ -142,8 +155,16 @@ void GL_TexFilter( gltexture_t *tex, qboolean update )
|
|||
}
|
||||
else
|
||||
{
|
||||
pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, r_textureMagFilter );
|
||||
pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, r_textureMagFilter );
|
||||
if( r_textureMagFilter == GL_NEAREST && allowNearest )
|
||||
{
|
||||
pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, r_textureMagFilter );
|
||||
pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, r_textureMagFilter );
|
||||
}
|
||||
else
|
||||
{
|
||||
pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
|
||||
pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -345,9 +366,17 @@ void R_TextureList_f( void )
|
|||
case GL_RGB5:
|
||||
Msg( "RGB5 " );
|
||||
break;
|
||||
case GL_LUMINANCE4_ALPHA4:
|
||||
Msg( "L4A4 " );
|
||||
break;
|
||||
case GL_LUMINANCE_ALPHA:
|
||||
case GL_LUMINANCE8_ALPHA8:
|
||||
Msg( "L8A8 " );
|
||||
break;
|
||||
case GL_LUMINANCE4:
|
||||
Msg( "L4 " );
|
||||
break;
|
||||
case GL_LUMINANCE:
|
||||
case GL_LUMINANCE8:
|
||||
Msg( "L8 " );
|
||||
break;
|
||||
|
@ -469,7 +498,7 @@ void GL_RoundImageDimensions( word *width, word *height, texFlags_t flags, qbool
|
|||
GL_TextureFormat
|
||||
===============
|
||||
*/
|
||||
static GLenum GL_TextureFormat( gltexture_t *tex, int samples )
|
||||
static GLenum GL_TextureFormat( gltexture_t *tex, int *samples )
|
||||
{
|
||||
qboolean compress;
|
||||
GLenum format;
|
||||
|
@ -487,7 +516,7 @@ static GLenum GL_TextureFormat( gltexture_t *tex, int samples )
|
|||
}
|
||||
else if( compress )
|
||||
{
|
||||
switch( samples )
|
||||
switch( *samples )
|
||||
{
|
||||
case 1: format = GL_COMPRESSED_LUMINANCE_ARB; break;
|
||||
case 2: format = GL_COMPRESSED_LUMINANCE_ALPHA_ARB; break;
|
||||
|
@ -503,25 +532,51 @@ static GLenum GL_TextureFormat( gltexture_t *tex, int samples )
|
|||
{
|
||||
int bits = gl_texturebits->integer;
|
||||
|
||||
switch( samples )
|
||||
switch( *samples )
|
||||
{
|
||||
case 1: format = GL_LUMINANCE8; break;
|
||||
case 2: format = GL_LUMINANCE8_ALPHA8; break;
|
||||
case 3:
|
||||
switch( bits )
|
||||
if( gl_luminance_textures->integer )
|
||||
{
|
||||
case 16: format = GL_RGB5; break;
|
||||
case 32: format = GL_RGB8; break;
|
||||
default: format = GL_RGB; break;
|
||||
switch( bits )
|
||||
{
|
||||
case 16: format = GL_LUMINANCE4; break;
|
||||
case 32: format = GL_LUMINANCE8; break;
|
||||
default: format = GL_LUMINANCE; break;
|
||||
}
|
||||
*samples = 1; // merge for right calc statistics
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( bits )
|
||||
{
|
||||
case 16: format = GL_RGB5; break;
|
||||
case 32: format = GL_RGB8; break;
|
||||
default: format = GL_RGB; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
default:
|
||||
switch( bits )
|
||||
if( gl_luminance_textures->integer )
|
||||
{
|
||||
case 16: format = GL_RGBA4; break;
|
||||
case 32: format = GL_RGBA8; break;
|
||||
default: format = GL_RGBA; break;
|
||||
switch( bits )
|
||||
{
|
||||
case 16: format = GL_LUMINANCE4_ALPHA4; break;
|
||||
case 32: format = GL_LUMINANCE8_ALPHA8; break;
|
||||
default: format = GL_LUMINANCE_ALPHA; break;
|
||||
}
|
||||
*samples = 2; // merge for right calc statistics
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( bits )
|
||||
{
|
||||
case 16: format = GL_RGBA4; break;
|
||||
case 32: format = GL_RGBA8; break;
|
||||
default: format = GL_RGBA; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -809,7 +864,7 @@ static void GL_UploadTexture( rgbdata_t *pic, gltexture_t *tex, qboolean subImag
|
|||
|
||||
// determine format
|
||||
inFormat = PFDesc[pic->type].glFormat;
|
||||
outFormat = GL_TextureFormat( tex, samples );
|
||||
outFormat = GL_TextureFormat( tex, &samples );
|
||||
tex->format = outFormat;
|
||||
|
||||
// determine target
|
||||
|
@ -930,6 +985,9 @@ int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags )
|
|||
pic = FS_LoadImage( name, buf, size );
|
||||
if( !pic ) return 0; // couldn't loading image
|
||||
|
||||
// force upload texture as RGB or RGBA (detail textures requires this)
|
||||
if( flags & TF_FORCE_COLOR ) pic->flags |= IMAGE_HAS_COLOR;
|
||||
|
||||
// find a free texture slot
|
||||
if( r_numTextures == MAX_TEXTURES )
|
||||
Host_Error( "GL_LoadTexture: MAX_TEXTURES limit exceeds\n" );
|
||||
|
@ -1003,6 +1061,9 @@ int GL_LoadTextureInternal( const char *name, rgbdata_t *pic, texFlags_t flags,
|
|||
Host_Error( "Couldn't find texture %s for update\n", name );
|
||||
}
|
||||
|
||||
// force upload texture as RGB or RGBA (detail textures requires this)
|
||||
if( flags & TF_FORCE_COLOR ) pic->flags |= IMAGE_HAS_COLOR;
|
||||
|
||||
// find a free texture slot
|
||||
if( r_numTextures == MAX_TEXTURES )
|
||||
Host_Error( "GL_LoadTexture: MAX_TEXTURES limit exceeds\n" );
|
||||
|
@ -1345,17 +1406,18 @@ static void R_InitBuiltinTextures( void )
|
|||
char *name;
|
||||
int *texnum;
|
||||
rgbdata_t *(*init)( texFlags_t *flags );
|
||||
int texType;
|
||||
}
|
||||
textures[] =
|
||||
{
|
||||
{ "*default", &tr.defaultTexture, R_InitDefaultTexture },
|
||||
{ "*white", &tr.whiteTexture, R_InitWhiteTexture },
|
||||
{ "*black", &tr.blackTexture, R_InitBlackTexture },
|
||||
{ "*particle", &tr.particleTexture, R_InitParticleTexture },
|
||||
{ "*particle2", &tr.particleTexture2, R_InitParticleTexture2 },
|
||||
{ "*cintexture", &tr.cinTexture, R_InitCinematicTexture },
|
||||
{ "*dlight", &tr.dlightTexture, R_InitDlightTexture },
|
||||
{ "*sky", &tr.skyTexture, R_InitSkyTexture },
|
||||
{ "*default", &tr.defaultTexture, R_InitDefaultTexture, TEX_SYSTEM },
|
||||
{ "*white", &tr.whiteTexture, R_InitWhiteTexture, TEX_SYSTEM },
|
||||
{ "*black", &tr.blackTexture, R_InitBlackTexture, TEX_SYSTEM },
|
||||
{ "*particle", &tr.particleTexture, R_InitParticleTexture, TEX_SYSTEM },
|
||||
{ "*particle2", &tr.particleTexture2, R_InitParticleTexture2, TEX_SYSTEM },
|
||||
{ "*cintexture", &tr.cinTexture, R_InitCinematicTexture, TEX_NOMIP }, // force linear filter
|
||||
{ "*dlight", &tr.dlightTexture, R_InitDlightTexture, TEX_LIGHTMAP },
|
||||
{ "*sky", &tr.skyTexture, R_InitSkyTexture, TEX_SYSTEM },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
size_t i, num_builtin_textures = sizeof( textures ) / sizeof( textures[0] ) - 1;
|
||||
|
@ -1369,7 +1431,7 @@ static void R_InitBuiltinTextures( void )
|
|||
if( pic == NULL ) continue;
|
||||
*textures[i].texnum = GL_LoadTextureInternal( textures[i].name, pic, flags, false );
|
||||
|
||||
GL_SetTextureType( *textures[i].texnum, TEX_SYSTEM );
|
||||
GL_SetTextureType( *textures[i].texnum, textures[i].texType );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1428,7 +1490,9 @@ void R_ShutdownImages( void )
|
|||
|
||||
GL_SelectTexture( i );
|
||||
pglBindTexture( GL_TEXTURE_2D, 0 );
|
||||
pglBindTexture( GL_TEXTURE_CUBE_MAP_ARB, 0 );
|
||||
|
||||
if( GL_Support( GL_TEXTURECUBEMAP_EXT ))
|
||||
pglBindTexture( GL_TEXTURE_CUBE_MAP_ARB, 0 );
|
||||
}
|
||||
|
||||
for( i = 0, image = r_textures; i < r_numTextures; i++, image++ )
|
||||
|
|
|
@ -29,6 +29,7 @@ extern byte *r_temppool;
|
|||
#define BLOCK_HEIGHT 128 // lightmap block height
|
||||
|
||||
#define MAX_TEXTURES 4096
|
||||
#define MAX_DETAIL_TEXTURES 256
|
||||
#define MAX_LIGHTMAPS 128
|
||||
#define SUBDIVIDE_SIZE 64
|
||||
|
||||
|
@ -62,7 +63,8 @@ typedef enum
|
|||
TEX_LIGHTMAP, // lightmap textures
|
||||
TEX_DECAL, // decals
|
||||
TEX_VGUI, // vgui fonts or images
|
||||
TEX_CUBEMAP // cubemap textures (sky)
|
||||
TEX_CUBEMAP, // cubemap textures (sky)
|
||||
TEX_DETAIL // detail textures
|
||||
} texType_t;
|
||||
|
||||
typedef enum
|
||||
|
@ -82,6 +84,7 @@ typedef enum
|
|||
TF_MAKELUMA = BIT(12), // create luma from quake texture
|
||||
TF_NORMALMAP = BIT(13), // is a normalmap
|
||||
TF_LIGHTMAP = BIT(14), // is a lightmap
|
||||
TF_FORCE_COLOR = BIT(15), // force upload monochrome textures as RGB (detail textures)
|
||||
} texFlags_t;
|
||||
|
||||
typedef struct gltexture_s
|
||||
|
@ -103,6 +106,10 @@ typedef struct gltexture_s
|
|||
byte texType; // used for gl_showtextures
|
||||
size_t size; // upload size for debug targets
|
||||
|
||||
// detail textures stuff
|
||||
float xscale;
|
||||
float yscale;
|
||||
|
||||
struct gltexture_s *nextHash;
|
||||
} gltexture_t;
|
||||
|
||||
|
@ -308,7 +315,7 @@ void R_PushDlights( void );
|
|||
void R_AnimateLight( void );
|
||||
void R_MarkLights( dlight_t *light, int bit, mnode_t *node );
|
||||
void R_LightDir( const vec3_t origin, vec3_t lightDir, float radius );
|
||||
void R_LightForPoint( const vec3_t point, color24 *ambientLight, qboolean invLight, float radius );
|
||||
void R_LightForPoint( const vec3_t point, color24 *ambientLight, qboolean invLight, qboolean useAmbient, float radius );
|
||||
|
||||
//
|
||||
// gl_rmain.c
|
||||
|
@ -425,7 +432,6 @@ void GL_SetRenderMode( int mode );
|
|||
void R_RunViewmodelEvents( void );
|
||||
void R_DrawViewModel( void );
|
||||
int R_GetSpriteTexture( const struct model_s *m_pSpriteModel, int frame );
|
||||
void R_LightForPoint( const vec3_t point, color24 *ambientLight, qboolean invLight, float radius );
|
||||
void R_DecalShoot( int textureIndex, int entityIndex, int modelIndex, vec3_t pos, int flags, vec3_t saxis );
|
||||
void R_RemoveEfrags( struct cl_entity_s *ent );
|
||||
void R_AddEfrags( struct cl_entity_s *ent );
|
||||
|
@ -444,6 +450,7 @@ enum
|
|||
{
|
||||
GL_OPENGL_110 = 0, // base
|
||||
GL_WGL_SWAPCONTROL,
|
||||
GL_WGL_PROCADDRESS,
|
||||
GL_HARDWARE_GAMMA_CONTROL,
|
||||
GL_ARB_VERTEX_BUFFER_OBJECT_EXT,
|
||||
GL_ENV_COMBINE_EXT,
|
||||
|
@ -576,6 +583,7 @@ extern convar_t *gl_texturemode;
|
|||
extern convar_t *gl_texture_lodbias;
|
||||
extern convar_t *gl_showtextures;
|
||||
extern convar_t *gl_compress_textures;
|
||||
extern convar_t *gl_luminance_textures;
|
||||
extern convar_t *gl_wireframe;
|
||||
extern convar_t *gl_allow_static;
|
||||
extern convar_t *gl_picmip;
|
||||
|
@ -592,6 +600,7 @@ extern convar_t *r_norefresh;
|
|||
extern convar_t *r_lighting_extended;
|
||||
extern convar_t *r_lighting_modulate;
|
||||
extern convar_t *r_lighting_ambient;
|
||||
extern convar_t *r_detailtextures;
|
||||
extern convar_t *r_faceplanecull;
|
||||
extern convar_t *r_drawentities;
|
||||
extern convar_t *r_adjust_fov;
|
||||
|
|
|
@ -125,11 +125,11 @@ void R_MarkLights( dlight_t *light, int bit, mnode_t *node )
|
|||
}
|
||||
|
||||
// mark the polygons
|
||||
surf = cl.worldmodel->surfaces + node->firstsurface;
|
||||
surf = RI.currentmodel->surfaces + node->firstsurface;
|
||||
|
||||
for( i = 0; i < node->numsurfaces; i++, surf++ )
|
||||
{
|
||||
mextrasurf_t *info = SURF_INFO( surf, cl.worldmodel );
|
||||
mextrasurf_t *info = SURF_INFO( surf, RI.currentmodel );
|
||||
|
||||
if( !BoundsAndSphereIntersect( info->mins, info->maxs, light->origin, light->radius ))
|
||||
continue; // no intersection
|
||||
|
@ -160,6 +160,9 @@ void R_PushDlights( void )
|
|||
// advanced yet for this frame
|
||||
l = cl_dlights;
|
||||
|
||||
RI.currententity = clgame.entities;
|
||||
RI.currentmodel = RI.currententity->model;
|
||||
|
||||
for( i = 0; i < MAX_DLIGHTS; i++, l++ )
|
||||
{
|
||||
if( l->die < cl.time || !l->radius )
|
||||
|
@ -168,7 +171,7 @@ void R_PushDlights( void )
|
|||
if( R_CullSphere( l->origin, l->radius, 15 ))
|
||||
continue;
|
||||
|
||||
R_MarkLights( l, 1<<i, cl.worldmodel->nodes );
|
||||
R_MarkLights( l, 1<<i, RI.currentmodel->nodes );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -268,7 +271,7 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, const vec3
|
|||
R_LightForPoint
|
||||
=================
|
||||
*/
|
||||
void R_LightForPoint( const vec3_t point, color24 *ambientLight, qboolean invLight, float radius )
|
||||
void R_LightForPoint( const vec3_t point, color24 *ambientLight, qboolean invLight, qboolean useAmbient, float radius )
|
||||
{
|
||||
dlight_t *dl;
|
||||
pmtrace_t trace;
|
||||
|
@ -368,6 +371,7 @@ void R_LightForPoint( const vec3_t point, color24 *ambientLight, qboolean invLig
|
|||
|
||||
// R_RecursiveLightPoint didn't hit anything, so use default value
|
||||
ambient = bound( 0.1f, r_lighting_ambient->value, 1.0f );
|
||||
if( !useAmbient ) ambient = 0.0f; // clear ambient
|
||||
ambientLight->r = 255 * ambient;
|
||||
ambientLight->g = 255 * ambient;
|
||||
ambientLight->b = 255 * ambient;
|
||||
|
|
|
@ -63,6 +63,9 @@ static qboolean R_StaticEntity( cl_entity_t *ent )
|
|||
if( ent->curstate.frame || ent->model->flags & MODEL_CONVEYOR )
|
||||
return false;
|
||||
|
||||
if( ent->curstate.scale ) // waveheight specified
|
||||
return false;
|
||||
|
||||
if( !VectorIsNull( ent->origin ) || !VectorIsNull( ent->angles ))
|
||||
return false;
|
||||
|
||||
|
@ -375,7 +378,9 @@ R_Clear
|
|||
*/
|
||||
static void R_Clear( int bitMask )
|
||||
{
|
||||
int bits;
|
||||
int bits;
|
||||
|
||||
pglClearColor( 0.5f, 0.5f, 0.5f, 1.0f );
|
||||
|
||||
bits = GL_DEPTH_BUFFER_BIT;
|
||||
|
||||
|
@ -570,8 +575,9 @@ static void R_SetupFrame( void )
|
|||
|
||||
R_AnimateLight();
|
||||
R_RunViewmodelEvents();
|
||||
|
||||
tr.framecount++;
|
||||
|
||||
// g-cont. keep actual frame for all viewpasses
|
||||
if( !RI.refdef.nextView ) tr.framecount++;
|
||||
|
||||
// sort translucents entities by rendermode and distance
|
||||
qsort( tr.trans_entities, tr.num_trans_entities, sizeof( cl_entity_t* ), R_TransEntityCompare );
|
||||
|
@ -828,7 +834,7 @@ void R_DrawEntitiesOnList( void )
|
|||
pglDepthMask( GL_FALSE );
|
||||
glState.drawTrans = true;
|
||||
|
||||
// then draw translicent entities
|
||||
// then draw translucent entities
|
||||
for( i = 0; i < tr.num_trans_entities; i++ )
|
||||
{
|
||||
if( RI.refdef.onlyClientDraw )
|
||||
|
|
|
@ -18,6 +18,249 @@ GNU General Public License for more details.
|
|||
#include "gl_local.h"
|
||||
#include "mod_local.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *texname;
|
||||
const char *detail;
|
||||
const char material;
|
||||
int lMin;
|
||||
int lMax;
|
||||
} dmaterial_t;
|
||||
|
||||
// default rules for apply detail textures.
|
||||
// move this to external script ?
|
||||
static const dmaterial_t detail_table[] =
|
||||
{
|
||||
{ "crt", "dt_conc", 'C', 0, 0 }, // concrete
|
||||
{ "rock", "dt_rock", 'C', 0, 0 },
|
||||
{ "conc", "dt_conc", 'C', 0, 0 },
|
||||
{ "wall", "dt_brick", 'C', 0, 0 },
|
||||
{ "crete", "dt_conc", 'C', 0, 0 },
|
||||
{ "generic", "dt_brick", 'C', 0, 0 },
|
||||
{ "metal", "dt_metal%i", 'M', 1, 2 }, // metal
|
||||
{ "mtl", "dt_metal%i", 'M', 1, 2 },
|
||||
{ "pipe", "dt_metal%i", 'M', 1, 2 },
|
||||
{ "elev", "dt_metal%i", 'M', 1, 2 },
|
||||
{ "sign", "dt_metal%i", 'M', 1, 2 },
|
||||
{ "barrel", "dt_metal%i", 'M', 1, 2 },
|
||||
{ "bath", "dt_ssteel1", 'M', 1, 2 },
|
||||
{ "refbridge", "dt_metal%i", 'M', 1, 2 },
|
||||
{ "panel", "dt_ssteel1", 'M', 0, 0 },
|
||||
{ "brass", "dt_ssteel1", 'M', 0, 0 },
|
||||
{ "car", "dt_metal%i", 'M', 1, 2 },
|
||||
{ "circuit", "dt_metal%i", 'M', 1, 2 },
|
||||
{ "steel", "dt_ssteel1", 'M', 0, 0 },
|
||||
{ "dirt", "dt_ground%i", 'D', 1, 5 }, // dirt
|
||||
{ "drt", "dt_ground%i", 'D', 1, 5 },
|
||||
{ "out", "dt_ground%i", 'D', 1, 5 },
|
||||
{ "grass", "dt_grass1", 'D', 0, 0 },
|
||||
{ "mud", "dt_carpet1", 'D', 0, 0 }, // FIXME
|
||||
{ "vent", "dt_ssteel1", 'V', 1, 4 }, // vent
|
||||
{ "duct", "dt_ssteel1", 'V', 1, 4 },
|
||||
{ "tile", "dt_smooth%i", 'T', 1, 2 },
|
||||
{ "labflr", "dt_smooth%i", 'T', 1, 2 },
|
||||
{ "bath", "dt_smooth%i", 'T', 1, 2 },
|
||||
{ "grate", "dt_stone%i", 'G', 1, 4 }, // vent
|
||||
{ "stone", "dt_stone%i", 'G', 1, 4 },
|
||||
{ "grt", "dt_stone%i", 'G', 1, 4 },
|
||||
{ "wood", "dt_wood%i", 'W', 1, 3 },
|
||||
{ "wd", "dt_wood%i", 'W', 1, 3 },
|
||||
{ "table", "dt_wood%i", 'W', 1, 3 },
|
||||
{ "board", "dt_wood%i", 'W', 1, 3 },
|
||||
{ "chair", "dt_wood%i", 'W', 1, 3 },
|
||||
{ "brd", "dt_wood%i", 'W', 1, 3 },
|
||||
{ "carp", "dt_carpet1", 'W', 1, 3 },
|
||||
{ "book", "dt_wood%i", 'W', 1, 3 },
|
||||
{ "box", "dt_wood%i", 'W', 1, 3 },
|
||||
{ "cab", "dt_wood%i", 'W', 1, 3 },
|
||||
{ "couch", "dt_wood%i", 'W', 1, 3 },
|
||||
{ "crate", "dt_wood%i", 'W', 1, 3 },
|
||||
{ "poster", "dt_plaster%i", 'W', 1, 2 },
|
||||
{ "sheet", "dt_plaster%i", 'W', 1, 2 },
|
||||
{ "stucco", "dt_plaster%i", 'W', 1, 2 },
|
||||
{ "comp", "dt_smooth1", 'P', 0, 0 },
|
||||
{ "cmp", "dt_smooth1", 'P', 0, 0 },
|
||||
{ "elec", "dt_smooth1", 'P', 0, 0 },
|
||||
{ "vend", "dt_smooth1", 'P', 0, 0 },
|
||||
{ "monitor", "dt_smooth1", 'P', 0, 0 },
|
||||
{ "phone", "dt_smooth1", 'P', 0, 0 },
|
||||
{ "glass", "dt_ssteel1", 'Y', 0, 0 },
|
||||
{ "window", "dt_ssteel1", 'Y', 0, 0 },
|
||||
{ "flesh", "dt_rough1", 'F', 0, 0 },
|
||||
{ "meat", "dt_rough1", 'F', 0, 0 },
|
||||
{ "fls", "dt_rough1", 'F', 0, 0 },
|
||||
{ "ground", "dt_ground%i", 'D', 1, 5 },
|
||||
{ "gnd", "dt_ground%i", 'D', 1, 5 },
|
||||
{ "snow", "dt_snow%i", 'O', 1, 2 }, // snow
|
||||
{ NULL, NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
static const char *R_DetailTextureForName( const char *name )
|
||||
{
|
||||
const dmaterial_t *table;
|
||||
|
||||
if( !name || !*name ) return NULL;
|
||||
if( !Q_strnicmp( name, "sky", 3 ))
|
||||
return NULL; // never details for sky
|
||||
|
||||
// never apply details for liquids
|
||||
if( !Q_strnicmp( name + 1, "!lava", 5 ))
|
||||
return NULL;
|
||||
if( !Q_strnicmp( name + 1, "!slime", 6 ))
|
||||
return NULL;
|
||||
if( !Q_strnicmp( name, "!cur_90", 7 ))
|
||||
return NULL;
|
||||
if( !Q_strnicmp( name, "!cur_0", 6 ))
|
||||
return NULL;
|
||||
if( !Q_strnicmp( name, "!cur_270", 8 ))
|
||||
return NULL;
|
||||
if( !Q_strnicmp( name, "!cur_180", 8 ))
|
||||
return NULL;
|
||||
if( !Q_strnicmp( name, "!cur_up", 7 ))
|
||||
return NULL;
|
||||
if( !Q_strnicmp( name, "!cur_dwn", 8 ))
|
||||
return NULL;
|
||||
if( name[0] == '!' )
|
||||
return NULL;
|
||||
|
||||
// never apply details to the special textures
|
||||
if( !Q_strnicmp( name, "origin", 6 ))
|
||||
return NULL;
|
||||
if( !Q_strnicmp( name, "clip", 4 ))
|
||||
return NULL;
|
||||
if( !Q_strnicmp( name, "hint", 4 ))
|
||||
return NULL;
|
||||
if( !Q_strnicmp( name, "skip", 4 ))
|
||||
return NULL;
|
||||
if( !Q_strnicmp( name, "translucent", 11 ))
|
||||
return NULL;
|
||||
if( !Q_strnicmp( name, "3dsky", 5 ))
|
||||
return NULL;
|
||||
if( name[0] == '@' )
|
||||
return NULL;
|
||||
|
||||
// last check ...
|
||||
if( !Q_strnicmp( name, "null", 4 ))
|
||||
return NULL;
|
||||
|
||||
for( table = detail_table; table && table->texname; table++ )
|
||||
{
|
||||
if( Q_stristr( name, table->texname ))
|
||||
{
|
||||
if(( table->lMin + table->lMax ) > 0 )
|
||||
return va( table->detail, Com_RandomLong( table->lMin, table->lMax ));
|
||||
return table->detail;
|
||||
}
|
||||
}
|
||||
return "dt_smooth1"; // default
|
||||
}
|
||||
|
||||
void R_CreateDetailTexturesList( const char *filename )
|
||||
{
|
||||
file_t *detail_txt = NULL;
|
||||
const char *detail_name, *texname;
|
||||
int i;
|
||||
|
||||
for( i = 0; i < cl.worldmodel->numtextures; i++ )
|
||||
{
|
||||
texname = cl.worldmodel->textures[i]->name;
|
||||
detail_name = R_DetailTextureForName( texname );
|
||||
if( !detail_name ) continue;
|
||||
|
||||
// detailtexture detected
|
||||
if( detail_name )
|
||||
{
|
||||
if( !detail_txt ) detail_txt = FS_Open( filename, "wb", false );
|
||||
if( !detail_txt )
|
||||
{
|
||||
MsgDev( D_ERROR, "Can't write %s\n", filename );
|
||||
break;
|
||||
}
|
||||
|
||||
// store detailtexture description
|
||||
FS_Printf( detail_txt, "%s detail/%s 10.0 10.0\n", texname, detail_name );
|
||||
}
|
||||
}
|
||||
|
||||
if( detail_txt ) FS_Close( detail_txt );
|
||||
}
|
||||
|
||||
void R_ParseDetailTextures( const char *filename )
|
||||
{
|
||||
char *afile, *pfile;
|
||||
string token, texname, detail_texname;
|
||||
float xScale, yScale;
|
||||
texture_t *tex;
|
||||
int i;
|
||||
|
||||
if( r_detailtextures->integer >= 2 && !FS_FileExists( filename, false ))
|
||||
{
|
||||
// use built-in generator for detail textures
|
||||
R_CreateDetailTexturesList( filename );
|
||||
}
|
||||
|
||||
afile = FS_LoadFile( filename, NULL, false );
|
||||
if( !afile ) return;
|
||||
|
||||
pfile = afile;
|
||||
|
||||
// format: 'texturename' 'detailtexture' 'xScale' 'yScale'
|
||||
while(( pfile = COM_ParseFile( pfile, token )) != NULL )
|
||||
{
|
||||
texname[0] = '\0';
|
||||
|
||||
// read texname
|
||||
if( token[0] == '{' )
|
||||
{
|
||||
// NOTE: COM_ParseFile handled some symbols seperately
|
||||
// this code will be fix it
|
||||
pfile = COM_ParseFile( pfile, token );
|
||||
Q_strncat( texname, "{", sizeof( texname ));
|
||||
Q_strncat( texname, token, sizeof( texname ));
|
||||
}
|
||||
else Q_strncpy( texname, token, sizeof( texname ));
|
||||
|
||||
// read detailtexture name
|
||||
pfile = COM_ParseFile( pfile, token );
|
||||
Q_snprintf( detail_texname, sizeof( detail_texname ), "gfx/%s.tga", token );
|
||||
|
||||
// read scales
|
||||
pfile = COM_ParseFile( pfile, token );
|
||||
xScale = Q_atof( token );
|
||||
|
||||
pfile = COM_ParseFile( pfile, token );
|
||||
yScale = Q_atof( token );
|
||||
|
||||
if( xScale <= 0.0f || yScale <= 0.0f )
|
||||
continue;
|
||||
|
||||
// search for existing texture and uploading detail texture
|
||||
for( i = 0; i < cl.worldmodel->numtextures; i++ )
|
||||
{
|
||||
tex = cl.worldmodel->textures[i];
|
||||
|
||||
if( Q_stricmp( tex->name, texname ))
|
||||
continue;
|
||||
|
||||
tex->dt_texturenum = GL_LoadTexture( detail_texname, NULL, 0, TF_FORCE_COLOR );
|
||||
|
||||
// texture is loaded
|
||||
if( tex->dt_texturenum )
|
||||
{
|
||||
gltexture_t *glt;
|
||||
|
||||
GL_SetTextureType( tex->dt_texturenum, TEX_DETAIL );
|
||||
glt = R_GetTexture( tex->dt_texturenum );
|
||||
glt->xscale = xScale;
|
||||
glt->yscale = yScale;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Mem_Free( afile );
|
||||
}
|
||||
|
||||
void R_NewMap( void )
|
||||
{
|
||||
int i;
|
||||
|
@ -45,4 +288,16 @@ void R_NewMap( void )
|
|||
|
||||
cl.worldmodel->textures[i]->texturechain = NULL;
|
||||
}
|
||||
|
||||
// upload detailtextures
|
||||
if( r_detailtextures->integer )
|
||||
{
|
||||
string mapname, filepath;
|
||||
|
||||
Q_strncpy( mapname, cl.worldmodel->name, sizeof( mapname ));
|
||||
FS_StripExtension( mapname );
|
||||
Q_sprintf( filepath, "%s_detail.txt", mapname );
|
||||
|
||||
R_ParseDetailTextures( filepath );
|
||||
}
|
||||
}
|
|
@ -35,6 +35,8 @@ static byte visbytes[MAX_MAP_LEAFS/8];
|
|||
static uint r_blocklights[BLOCK_WIDTH*BLOCK_HEIGHT*3];
|
||||
static glpoly_t *fullbright_polys[MAX_TEXTURES];
|
||||
static qboolean draw_fullbrights = false;
|
||||
static glpoly_t *detail_polys[MAX_TEXTURES];
|
||||
static qboolean draw_details = false;
|
||||
static gllightmapstate_t gl_lms;
|
||||
static msurface_t *skychain = NULL;
|
||||
|
||||
|
@ -163,7 +165,8 @@ static void SubdividePolygon_r( msurface_t *warpface, int numverts, float *verts
|
|||
total_s += s;
|
||||
total_t += t;
|
||||
|
||||
if(!( warpface->flags & SURF_DRAWTURB ))
|
||||
// for speed reasons
|
||||
if( !( warpface->flags & SURF_DRAWTURB ))
|
||||
{
|
||||
// lightmap texture coordinates
|
||||
s = DotProduct( verts, warpface->texinfo->vecs[0] ) + warpface->texinfo->vecs[0][3];
|
||||
|
@ -191,8 +194,12 @@ static void SubdividePolygon_r( msurface_t *warpface, int numverts, float *verts
|
|||
VectorScale( total, vertsDiv, poly->verts[0] );
|
||||
poly->verts[0][3] = total_s * vertsDiv;
|
||||
poly->verts[0][4] = total_t * vertsDiv;
|
||||
poly->verts[0][5] = total_ls * vertsDiv;
|
||||
poly->verts[0][6] = total_lt * vertsDiv;
|
||||
|
||||
if( !( warpface->flags & SURF_DRAWTURB ))
|
||||
{
|
||||
poly->verts[0][5] = total_ls * vertsDiv;
|
||||
poly->verts[0][6] = total_lt * vertsDiv;
|
||||
}
|
||||
|
||||
// copy first vertex to last
|
||||
Q_memcpy( poly->verts[i+1], poly->verts[1], sizeof( poly->verts[0] ));
|
||||
|
@ -250,13 +257,6 @@ void GL_BuildPolygonFromSurface( msurface_t *fa )
|
|||
if( !fa->texinfo || !fa->texinfo->texture )
|
||||
return; // bad polygon ?
|
||||
|
||||
if( fa->texinfo->texture->anim_total < 0 )
|
||||
{
|
||||
// random tileing. subdivide the polygon
|
||||
GL_SubdivideSurface( fa );
|
||||
return;
|
||||
}
|
||||
|
||||
// reconstruct the polygon
|
||||
pedges = loadmodel->edges;
|
||||
lnumverts = fa->numedges;
|
||||
|
@ -324,17 +324,17 @@ texture_t *R_TextureAnimation( texture_t *base, int surfacenum )
|
|||
int reletive;
|
||||
int count, speed;
|
||||
|
||||
// random tileng textures
|
||||
// random tiling textures
|
||||
if( base->anim_total < 0 )
|
||||
{
|
||||
reletive = surfacenum % abs( base->anim_total );
|
||||
reletive = abs( surfacenum ) % abs( base->anim_total );
|
||||
|
||||
count = 0;
|
||||
while( base->anim_min > reletive || base->anim_max <= reletive )
|
||||
{
|
||||
base = base->anim_next;
|
||||
if( !base ) Host_Error( "R_TextureAnimation: broken loop\n" );
|
||||
if( ++count > 100 ) Host_Error( "R_TextureAnimation: infinite loop\n" );
|
||||
if( !base ) Host_Error( "R_TextureRandomTiling: broken loop\n" );
|
||||
if( ++count > 100 ) Host_Error( "R_TextureRandomTiling: infinite loop\n" );
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
@ -618,14 +618,13 @@ static void R_BuildLightMap( msurface_t *surf, byte *dest, int stride )
|
|||
DrawGLPoly
|
||||
================
|
||||
*/
|
||||
void DrawGLPoly( glpoly_t *p, texture_t *tex )
|
||||
void DrawGLPoly( glpoly_t *p, float xScale, float yScale )
|
||||
{
|
||||
float *v;
|
||||
float sOffset, sy;
|
||||
float tOffset, cy;
|
||||
cl_entity_t *e = RI.currententity;
|
||||
qboolean random_tiles = false;
|
||||
texture_t *t;
|
||||
glpoly_t *base;
|
||||
int i, hasScale = false;
|
||||
|
||||
if( p->flags & SURF_CONVEYOR )
|
||||
{
|
||||
|
@ -657,29 +656,21 @@ void DrawGLPoly( glpoly_t *p, texture_t *tex )
|
|||
sOffset = tOffset = 0.0f;
|
||||
}
|
||||
|
||||
if( p && p->next ) random_tiles = true;
|
||||
if( xScale != 0.0f && yScale != 0.0f )
|
||||
hasScale = true;
|
||||
|
||||
for( base = p; p != NULL; p = p->next )
|
||||
pglBegin( GL_POLYGON );
|
||||
|
||||
for( i = 0, v = p->verts[0]; i < p->numverts; i++, v += VERTEXSIZE )
|
||||
{
|
||||
float *v;
|
||||
int i;
|
||||
if( hasScale )
|
||||
pglTexCoord2f(( v[3] + sOffset ) * xScale, ( v[4] + tOffset ) * yScale );
|
||||
else pglTexCoord2f( v[3] + sOffset, v[4] + tOffset );
|
||||
|
||||
if( random_tiles && tex )
|
||||
{
|
||||
t = R_TextureAnimation( tex, base - p );
|
||||
GL_MBind( t->gl_texturenum );
|
||||
}
|
||||
|
||||
pglBegin( GL_POLYGON );
|
||||
|
||||
for( i = 0, v = p->verts[0]; i < p->numverts; i++, v += VERTEXSIZE )
|
||||
{
|
||||
pglTexCoord2f( v[3] + sOffset, v[4] + tOffset );
|
||||
pglVertex3fv( v );
|
||||
}
|
||||
|
||||
pglEnd();
|
||||
pglVertex3fv( v );
|
||||
}
|
||||
|
||||
pglEnd();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -698,23 +689,19 @@ void DrawGLPolyChain( glpoly_t *p, float soffset, float toffset )
|
|||
|
||||
for( ; p != NULL; p = p->chain )
|
||||
{
|
||||
glpoly_t *p2;
|
||||
float *v;
|
||||
int i;
|
||||
|
||||
for( p2 = p; p2 != NULL; p2 = p2->next )
|
||||
{
|
||||
pglBegin( GL_POLYGON );
|
||||
pglBegin( GL_POLYGON );
|
||||
|
||||
v = p2->verts[0];
|
||||
for( i = 0; i < p2->numverts; i++, v += VERTEXSIZE )
|
||||
{
|
||||
if( !dynamic ) pglTexCoord2f( v[5], v[6] );
|
||||
else pglTexCoord2f( v[5] - soffset, v[6] - toffset );
|
||||
pglVertex3fv( v );
|
||||
}
|
||||
pglEnd ();
|
||||
v = p->verts[0];
|
||||
for( i = 0; i < p->numverts; i++, v += VERTEXSIZE )
|
||||
{
|
||||
if( !dynamic ) pglTexCoord2f( v[5], v[6] );
|
||||
else pglTexCoord2f( v[5] - soffset, v[6] - toffset );
|
||||
pglVertex3fv( v );
|
||||
}
|
||||
pglEnd ();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -822,7 +809,7 @@ void R_BlendLightmaps( void )
|
|||
info = SURF_INFO( surf, RI.currentmodel );
|
||||
|
||||
// try uploading the block now
|
||||
if( !LM_AllocBlock( smax, tmax, &info->dlight_s, &info->dlight_t ) )
|
||||
if( !LM_AllocBlock( smax, tmax, &info->dlight_s, &info->dlight_t ))
|
||||
Host_Error( "AllocBlock: full\n" );
|
||||
|
||||
base = gl_lms.lightmap_buffer;
|
||||
|
@ -887,7 +874,7 @@ void R_RenderFullbrights( void )
|
|||
{
|
||||
if( p->flags & SURF_DRAWTURB )
|
||||
EmitWaterPolys( p, ( p->flags & SURF_NOCULL ));
|
||||
else DrawGLPoly( p, NULL ); // disable random tiling (chain is already used)
|
||||
else DrawGLPoly( p, 0.0f, 0.0f );
|
||||
}
|
||||
|
||||
fullbright_polys[i] = NULL;
|
||||
|
@ -901,6 +888,50 @@ void R_RenderFullbrights( void )
|
|||
draw_fullbrights = false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_RenderDetails
|
||||
================
|
||||
*/
|
||||
void R_RenderDetails( void )
|
||||
{
|
||||
gltexture_t *glt;
|
||||
glpoly_t *p;
|
||||
int i;
|
||||
|
||||
if( !draw_details )
|
||||
return;
|
||||
|
||||
pglEnable( GL_BLEND );
|
||||
pglBlendFunc( GL_DST_COLOR, GL_SRC_COLOR );
|
||||
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
|
||||
|
||||
if( RI.currententity->curstate.rendermode == kRenderTransAlpha )
|
||||
pglDepthFunc( GL_EQUAL );
|
||||
|
||||
for( i = 1; i < MAX_TEXTURES; i++ )
|
||||
{
|
||||
if( !detail_polys[i] )
|
||||
continue;
|
||||
|
||||
GL_Bind( GL_TEXTURE0, i );
|
||||
glt = R_GetTexture( i );
|
||||
|
||||
for( p = detail_polys[i]; p; p = p->next )
|
||||
DrawGLPoly( p, glt->xscale, glt->yscale );
|
||||
|
||||
detail_polys[i] = NULL;
|
||||
}
|
||||
|
||||
pglDisable( GL_BLEND );
|
||||
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
|
||||
|
||||
if( RI.currententity->curstate.rendermode == kRenderTransAlpha )
|
||||
pglDepthFunc( GL_LEQUAL );
|
||||
|
||||
draw_details = false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_RenderBrushPoly
|
||||
|
@ -926,7 +957,7 @@ void R_RenderBrushPoly( msurface_t *fa )
|
|||
return;
|
||||
}
|
||||
|
||||
t = R_TextureAnimation( fa->texinfo->texture, 0 );
|
||||
t = R_TextureAnimation( fa->texinfo->texture, fa - RI.currententity->model->surfaces );
|
||||
GL_MBind( t->gl_texturenum );
|
||||
|
||||
if( fa->flags & SURF_DRAWTURB )
|
||||
|
@ -943,8 +974,16 @@ void R_RenderBrushPoly( msurface_t *fa )
|
|||
fullbright_polys[t->fb_texturenum] = fa->polys;
|
||||
draw_fullbrights = true;
|
||||
}
|
||||
else if( r_detailtextures->integer && t->dt_texturenum )
|
||||
{
|
||||
// HACKHACK: store details in poly->next (only for non-water surfaces)
|
||||
// can't rendering both luma and detail textures simultaneously
|
||||
fa->polys->next = detail_polys[t->dt_texturenum];
|
||||
detail_polys[t->dt_texturenum] = fa->polys;
|
||||
draw_details = true;
|
||||
}
|
||||
|
||||
DrawGLPoly( fa->polys, fa->texinfo->texture );
|
||||
DrawGLPoly( fa->polys, 0.0f, 0.0f );
|
||||
DrawSurfaceDecals( fa );
|
||||
|
||||
// check for lightmap modification
|
||||
|
@ -1214,10 +1253,12 @@ void R_DrawBrushModel( cl_entity_t *e )
|
|||
{
|
||||
int i, k, num_sorted;
|
||||
qboolean need_sort = false;
|
||||
vec3_t origin_l, oldorigin;
|
||||
vec3_t mins, maxs;
|
||||
msurface_t *psurf;
|
||||
model_t *clmodel;
|
||||
qboolean rotated;
|
||||
matrix4x4 imatrix;
|
||||
dlight_t *l;
|
||||
|
||||
clmodel = e->model;
|
||||
|
@ -1258,25 +1299,18 @@ void R_DrawBrushModel( cl_entity_t *e )
|
|||
Matrix4x4_VectorITransform( RI.objectMatrix, temp, modelorg );
|
||||
}
|
||||
|
||||
// calculate dynamic lighting for bmodel if it's not an
|
||||
// instanced model
|
||||
if( clmodel->firstmodelsurface != 0 )
|
||||
// calculate dynamic lighting for bmodel
|
||||
for( k = 0, l = cl_dlights; k < MAX_DLIGHTS; k++, l++ )
|
||||
{
|
||||
vec3_t origin_l, oldorigin;
|
||||
matrix4x4 imatrix;
|
||||
if( l->die < cl.time || !l->radius )
|
||||
continue;
|
||||
|
||||
for( k = 0, l = cl_dlights; k < MAX_DLIGHTS; k++, l++ )
|
||||
{
|
||||
if( l->die < cl.time || !l->radius )
|
||||
continue;
|
||||
|
||||
VectorCopy( l->origin, oldorigin ); // save oldorigin
|
||||
Matrix4x4_Invert_Simple( imatrix, RI.objectMatrix );
|
||||
Matrix4x4_VectorTransform( imatrix, l->origin, origin_l );
|
||||
VectorCopy( origin_l, l->origin ); // move light in bmodel space
|
||||
R_MarkLights( l, 1<<k, clmodel->nodes + clmodel->hulls[0].firstclipnode );
|
||||
VectorCopy( oldorigin, l->origin ); // restore lightorigin
|
||||
}
|
||||
VectorCopy( l->origin, oldorigin ); // save oldorigin
|
||||
Matrix4x4_Invert_Simple( imatrix, RI.objectMatrix );
|
||||
Matrix4x4_VectorTransform( imatrix, l->origin, origin_l );
|
||||
VectorCopy( origin_l, l->origin ); // move light in bmodel space
|
||||
R_MarkLights( l, 1<<k, clmodel->nodes + clmodel->hulls[0].firstclipnode );
|
||||
VectorCopy( oldorigin, l->origin ); // restore lightorigin
|
||||
}
|
||||
|
||||
// setup the rendermode
|
||||
|
@ -1349,6 +1383,8 @@ void R_DrawBrushModel( cl_entity_t *e )
|
|||
|
||||
R_BlendLightmaps();
|
||||
R_RenderFullbrights();
|
||||
R_RenderDetails();
|
||||
|
||||
R_LoadIdentity(); // restore worldmatrix
|
||||
}
|
||||
|
||||
|
@ -1370,16 +1406,12 @@ void R_DrawStaticModel( cl_entity_t *e )
|
|||
if( R_CullBox( clmodel->mins, clmodel->maxs, RI.clipFlags ))
|
||||
return;
|
||||
|
||||
// calculate dynamic lighting for bmodel if it's not an
|
||||
// instanced model
|
||||
if( clmodel->firstmodelsurface != 0 )
|
||||
// calculate dynamic lighting for bmodel
|
||||
for( k = 0, l = cl_dlights; k < MAX_DLIGHTS; k++, l++ )
|
||||
{
|
||||
for( k = 0, l = cl_dlights; k < MAX_DLIGHTS; k++, l++ )
|
||||
{
|
||||
if( l->die < cl.time || !l->radius )
|
||||
continue;
|
||||
R_MarkLights( l, 1<<k, clmodel->nodes + clmodel->hulls[0].firstclipnode );
|
||||
}
|
||||
if( l->die < cl.time || !l->radius )
|
||||
continue;
|
||||
R_MarkLights( l, 1<<k, clmodel->nodes + clmodel->hulls[0].firstclipnode );
|
||||
}
|
||||
|
||||
psurf = &clmodel->surfaces[clmodel->firstmodelsurface];
|
||||
|
@ -1463,13 +1495,12 @@ void R_PlaneForMirror( msurface_t *surf, mplane_t *out )
|
|||
R_RotateForEntity( ent );
|
||||
else R_TranslateForEntity( ent );
|
||||
|
||||
// tranform mirror plane by entity matrix
|
||||
// transform mirror plane by entity matrix
|
||||
if( !tr.modelviewIdentity )
|
||||
{
|
||||
mplane_t tmp;
|
||||
|
||||
tmp = *out;
|
||||
|
||||
Matrix4x4_TransformPositivePlane( RI.objectMatrix, tmp.normal, tmp.dist, out->normal, &out->dist );
|
||||
}
|
||||
}
|
||||
|
@ -1663,9 +1694,11 @@ R_DrawTriangleOutlines
|
|||
*/
|
||||
void R_DrawTriangleOutlines( void )
|
||||
{
|
||||
int i, j;
|
||||
glpoly_t *p, *p2;
|
||||
|
||||
int i, j;
|
||||
msurface_t *surf;
|
||||
glpoly_t *p;
|
||||
float *v;
|
||||
|
||||
if( !gl_wireframe->integer )
|
||||
return;
|
||||
|
||||
|
@ -1674,30 +1707,38 @@ void R_DrawTriangleOutlines( void )
|
|||
pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
|
||||
pglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
|
||||
|
||||
// render static surfaces first
|
||||
for( i = 0; i < MAX_LIGHTMAPS; i++ )
|
||||
{
|
||||
msurface_t *surf;
|
||||
float *v;
|
||||
|
||||
for( surf = gl_lms.lightmap_surfaces[i]; surf != NULL; surf = surf->lightmapchain )
|
||||
{
|
||||
p = surf->polys;
|
||||
|
||||
// for( ; p != NULL; p = p->chain )
|
||||
for( ; p != NULL; p = p->chain )
|
||||
{
|
||||
p2 = p;
|
||||
|
||||
for( p2 = p; p2; p2 = p2->next )
|
||||
{
|
||||
pglBegin( GL_POLYGON );
|
||||
for( j = 0, v = p2->verts[0]; j < p2->numverts; j++, v += VERTEXSIZE )
|
||||
pglVertex3fv( v );
|
||||
pglEnd ();
|
||||
}
|
||||
pglBegin( GL_POLYGON );
|
||||
v = p->verts[0];
|
||||
for( j = 0; j < p->numverts; j++, v += VERTEXSIZE )
|
||||
pglVertex3fv( v );
|
||||
pglEnd ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// render surfaces with dynamic lightmaps
|
||||
for( surf = gl_lms.dynamic_surfaces; surf != NULL; surf = surf->lightmapchain )
|
||||
{
|
||||
p = surf->polys;
|
||||
|
||||
for( ; p != NULL; p = p->chain )
|
||||
{
|
||||
pglBegin( GL_POLYGON );
|
||||
v = p->verts[0];
|
||||
for( j = 0; j < p->numverts; j++, v += VERTEXSIZE )
|
||||
pglVertex3fv( v );
|
||||
pglEnd ();
|
||||
}
|
||||
}
|
||||
|
||||
pglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
|
||||
pglEnable( GL_DEPTH_TEST );
|
||||
pglEnable( GL_TEXTURE_2D );
|
||||
|
@ -1719,6 +1760,8 @@ void R_DrawWorld( void )
|
|||
VectorCopy( RI.cullorigin, modelorg );
|
||||
Q_memset( gl_lms.lightmap_surfaces, 0, sizeof( gl_lms.lightmap_surfaces ));
|
||||
Q_memset( fullbright_polys, 0, sizeof( fullbright_polys ));
|
||||
Q_memset( detail_polys, 0, sizeof( detail_polys ));
|
||||
|
||||
RI.currentWaveHeight = RI.waveHeight;
|
||||
GL_SetRenderMode( kRenderNormal );
|
||||
gl_lms.dynamic_surfaces = NULL;
|
||||
|
@ -1735,6 +1778,7 @@ void R_DrawWorld( void )
|
|||
|
||||
R_BlendLightmaps();
|
||||
R_RenderFullbrights();
|
||||
R_RenderDetails();
|
||||
|
||||
if( skychain )
|
||||
R_DrawSkyBox();
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -26,6 +26,7 @@ GNU General Public License for more details.
|
|||
#define MAPSPRITE_SIZE 128
|
||||
|
||||
convar_t *r_sprite_lerping;
|
||||
convar_t *r_sprite_lighting;
|
||||
char group_suffix[8];
|
||||
static vec3_t sprite_mins, sprite_maxs;
|
||||
static float sprite_radius;
|
||||
|
@ -39,6 +40,7 @@ R_SpriteInit
|
|||
void R_SpriteInit( void )
|
||||
{
|
||||
r_sprite_lerping = Cvar_Get( "r_sprite_lerping", "1", CVAR_ARCHIVE, "enables sprite animation lerping" );
|
||||
r_sprite_lighting = Cvar_Get( "r_sprite_lighting", "1", CVAR_ARCHIVE, "enables sprite lighting (blood etc)" );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -459,7 +461,7 @@ mspriteframe_t *R_GetSpriteFrame( const model_t *pModel, int frame, float yaw )
|
|||
}
|
||||
else if( psprite->frames[frame].type == FRAME_ANGLED )
|
||||
{
|
||||
int angleframe = (int)(( RI.refdef.viewangles[1] - yaw ) / 360 * 8 + 0.5 - 4) & 7;
|
||||
int angleframe = (int)(Q_rint(( RI.refdef.viewangles[1] - yaw + 45.0f ) / 360 * 8) - 4) & 7;
|
||||
|
||||
// e.g. doom-style sprite monsters
|
||||
pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
|
||||
|
@ -590,7 +592,7 @@ float R_GetSpriteFrameInterpolant( cl_entity_t *ent, mspriteframe_t **oldframe,
|
|||
{
|
||||
// e.g. doom-style sprite monsters
|
||||
float yaw = ent->angles[YAW];
|
||||
int angleframe = (int)(( RI.refdef.viewangles[1] - yaw ) / 360 * 8 + 0.5 - 4) & 7;
|
||||
int angleframe = (int)(Q_rint(( RI.refdef.viewangles[1] - yaw + 45.0f ) / 360 * 8) - 4) & 7;
|
||||
|
||||
if( m_fDoInterp )
|
||||
{
|
||||
|
@ -732,6 +734,8 @@ static float R_SpriteGlowBlend( vec3_t origin, int rendermode, int renderfx, int
|
|||
if( renderfx == kRenderFxNoDissipation )
|
||||
return (float)alpha * (1.0f / 255.0f);
|
||||
|
||||
*pscale = 0.0f; // variable sized glow
|
||||
|
||||
// UNDONE: Tweak these magic numbers (19000 - falloff & 200 - sprite size)
|
||||
brightness = 19000.0 / ( dist * dist );
|
||||
brightness = bound( 0.01f, brightness, 1.0f );
|
||||
|
@ -811,7 +815,7 @@ static void R_DrawSpriteQuad( mspriteframe_t *frame, vec3_t org, vec3_t v_right,
|
|||
|
||||
static _inline qboolean R_SpriteHasLightmap( cl_entity_t *e, int texFormat )
|
||||
{
|
||||
if( !r_lighting_extended->integer )
|
||||
if( !r_sprite_lighting->integer )
|
||||
return false;
|
||||
|
||||
if( texFormat != SPR_ALPHTEST )
|
||||
|
@ -930,7 +934,7 @@ void R_DrawSpriteModel( cl_entity_t *e )
|
|||
qboolean invLight;
|
||||
|
||||
invLight = (e->curstate.effects & EF_INVLIGHT) ? true : false;
|
||||
R_LightForPoint( origin, &lightColor, invLight, sprite_radius );
|
||||
R_LightForPoint( origin, &lightColor, invLight, true, sprite_radius );
|
||||
color2[0] = (float)lightColor.r * ( 1.0f / 255.0f );
|
||||
color2[1] = (float)lightColor.g * ( 1.0f / 255.0f );
|
||||
color2[2] = (float)lightColor.b * ( 1.0f / 255.0f );
|
||||
|
@ -1013,7 +1017,7 @@ void R_DrawSpriteModel( cl_entity_t *e )
|
|||
if( ilerp != 0 )
|
||||
{
|
||||
pglColor4f( color[0], color[1], color[2], flAlpha * ilerp );
|
||||
GL_Bind( GL_TEXTURE0, frame->gl_texturenum );
|
||||
GL_Bind( GL_TEXTURE0, oldframe->gl_texturenum );
|
||||
R_DrawSpriteQuad( oldframe, origin, v_right, v_up, scale );
|
||||
}
|
||||
|
||||
|
|
|
@ -57,10 +57,11 @@ typedef struct studiolight_s
|
|||
|
||||
convar_t *r_studio_lerping;
|
||||
convar_t *r_studio_lambert;
|
||||
convar_t *r_studio_lighting;
|
||||
convar_t *r_drawviewmodel;
|
||||
convar_t *r_customdraw_playermodel;
|
||||
convar_t *cl_himodels;
|
||||
cvar_t r_shadows = { "r_shadows", "0", 0, 0 };
|
||||
cvar_t r_shadows = { "r_shadows", "0", 0, 0 }; // dead cvar. especially disabled
|
||||
cvar_t r_shadowalpha = { "r_shadowalpha", "0.5", 0, 0 };
|
||||
static r_studio_interface_t *pStudioDraw;
|
||||
static float aliasXscale, aliasYscale; // software renderer scale
|
||||
|
@ -110,6 +111,7 @@ void R_StudioInit( void )
|
|||
r_studio_lerping = Cvar_Get( "r_studio_lerping", "1", CVAR_ARCHIVE, "enables studio animation lerping" );
|
||||
r_drawviewmodel = Cvar_Get( "r_drawviewmodel", "1", 0, "draw firstperson weapon model" );
|
||||
cl_himodels = Cvar_Get( "cl_himodels", "1", CVAR_ARCHIVE, "draw high-resolution player models in multiplayer" );
|
||||
r_studio_lighting = Cvar_Get( "r_studio_lighting", "1", CVAR_ARCHIVE, "studio lighting models ( 0 - normal, 1 - extended, 2 - experimental )" );
|
||||
|
||||
// NOTE: some mods with custom studiomodel renderer may cause error when menu trying draw player model out of the loaded game
|
||||
r_customdraw_playermodel = Cvar_Get( "r_customdraw_playermodel", "0", CVAR_ARCHIVE, "allow to drawing playermodel in menu with client renderer" );
|
||||
|
@ -1230,7 +1232,7 @@ void R_StudioSetupChrome( float *pchrome, int bone, vec3_t normal )
|
|||
vec3_t chromerightvec; // g_chrome s vector in world reference frame
|
||||
vec3_t tmp; // vector pointing at bone in world reference frame
|
||||
|
||||
VectorScale( RI.currententity->origin, -1.0f, tmp );
|
||||
VectorScale( cl.refdef.vieworg, -1.0f, tmp );
|
||||
tmp[0] += g_bonestransform[bone][0][3];
|
||||
tmp[1] += g_bonestransform[bone][1][3];
|
||||
tmp[2] += g_bonestransform[bone][2][3];
|
||||
|
@ -1363,7 +1365,7 @@ void R_StudioDynamicLight( cl_entity_t *ent, alight_t *lightinfo )
|
|||
plight = &g_studiolight;
|
||||
plight->numdlights = 0; // clear previous dlights
|
||||
|
||||
if( r_lighting_extended->integer == 2 )
|
||||
if( r_studio_lighting->integer == 2 )
|
||||
Matrix3x4_OriginFromMatrix( g_lighttransform[0], origin );
|
||||
else Matrix3x4_OriginFromMatrix( g_rotationmatrix, origin );
|
||||
|
||||
|
@ -1373,7 +1375,7 @@ void R_StudioDynamicLight( cl_entity_t *ent, alight_t *lightinfo )
|
|||
|
||||
// setup ambient lighting
|
||||
invLight = (ent->curstate.effects & EF_INVLIGHT) ? true : false;
|
||||
R_LightForPoint( origin, &ambient, invLight, 0.0f ); // ignore dlights
|
||||
R_LightForPoint( origin, &ambient, invLight, true, 0.0f ); // ignore dlights
|
||||
|
||||
plight->lightcolor[0] = ambient.r * (1.0f / 255.0f);
|
||||
plight->lightcolor[1] = ambient.g * (1.0f / 255.0f);
|
||||
|
@ -1452,7 +1454,7 @@ void R_StudioEntityLight( alight_t *lightinfo )
|
|||
plight = &g_studiolight;
|
||||
plight->numelights = 0; // clear previous elights
|
||||
|
||||
if( r_lighting_extended->integer == 2 )
|
||||
if( r_studio_lighting->integer == 2 )
|
||||
Matrix3x4_OriginFromMatrix( g_lighttransform[0], origin );
|
||||
else Matrix3x4_OriginFromMatrix( g_rotationmatrix, origin );
|
||||
|
||||
|
@ -2257,12 +2259,12 @@ static int pfnIsHardware( void )
|
|||
return true;
|
||||
}
|
||||
|
||||
static void StudioDrawShadow( studiohdr_t *pstudiohdr, matrix3x4 transform[MAXSTUDIOBONES] )
|
||||
static void StudioDrawShadow( void )
|
||||
{
|
||||
// in GoldSrc shadow call is dsiabled with 'return' at start of the function
|
||||
// some mods used a hack with calling DrawShadow ahead of 'return'
|
||||
// this code is for HL compatibility.
|
||||
MsgDev( D_INFO, "GL_StudioDrawShadow()\n" ); // just a debug
|
||||
// MsgDev( D_INFO, "GL_StudioDrawShadow()\n" ); // just a debug
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2273,11 +2275,11 @@ GL_StudioDrawShadow
|
|||
*/
|
||||
void _cdecl GL_StudioDrawShadow( void )
|
||||
{
|
||||
int rendermode; // ecx@3
|
||||
float shadow_alpha; // ST18_4@4
|
||||
float shadow_alpha2; // ST14_4@4
|
||||
GLenum depthmode; // [sp+14h] [bp-8h]@6
|
||||
GLenum depthmode2; // [sp+14h] [bp-8h]@10
|
||||
int rendermode;
|
||||
float shadow_alpha;
|
||||
float shadow_alpha2;
|
||||
GLenum depthmode;
|
||||
GLenum depthmode2;
|
||||
|
||||
pglDepthMask( GL_TRUE );
|
||||
|
||||
|
@ -2303,7 +2305,7 @@ void _cdecl GL_StudioDrawShadow( void )
|
|||
depthmode = GL_GREATER;
|
||||
pglDepthFunc( depthmode );
|
||||
|
||||
MsgDev( D_INFO, "GL_StudioDrawShadow()\n" ); // just a debug
|
||||
StudioDrawShadow();
|
||||
|
||||
// if( flt_100DB994 == 0.0 || flt_107BA8A8 < 0.5 )
|
||||
depthmode2 = GL_LEQUAL;
|
||||
|
|
|
@ -35,6 +35,7 @@ convar_t *gl_texturebits;
|
|||
convar_t *gl_ignorehwgamma;
|
||||
convar_t *gl_texture_anisotropy;
|
||||
convar_t *gl_compress_textures;
|
||||
convar_t *gl_luminance_textures;
|
||||
convar_t *gl_texture_lodbias;
|
||||
convar_t *gl_showtextures;
|
||||
convar_t *gl_swapInterval;
|
||||
|
@ -60,6 +61,7 @@ convar_t *r_norefresh;
|
|||
convar_t *r_lighting_extended;
|
||||
convar_t *r_lighting_modulate;
|
||||
convar_t *r_lighting_ambient;
|
||||
convar_t *r_detailtextures;
|
||||
convar_t *r_faceplanecull;
|
||||
convar_t *r_drawentities;
|
||||
convar_t *r_adjust_fov;
|
||||
|
@ -121,10 +123,11 @@ vidmode_t vidmode[] =
|
|||
{ "Mode 13: 16x9", 1024, 600, true },
|
||||
{ "Mode 14: 16x9", 1280, 720, true },
|
||||
{ "Mode 15: 16x9", 1360, 768, true },
|
||||
{ "Mode 16: 16x9", 1440, 900, true },
|
||||
{ "Mode 17: 16x9", 1680, 1050, true },
|
||||
{ "Mode 18: 16x9", 1920, 1200, true },
|
||||
{ "Mode 19: 16x9", 2560, 1600, true },
|
||||
{ "Mode 16: 16x9", 1366, 768, true },
|
||||
{ "Mode 17: 16x9", 1440, 900, true },
|
||||
{ "Mode 18: 16x9", 1680, 1050, true },
|
||||
{ "Mode 19: 16x9", 1920, 1200, true },
|
||||
{ "Mode 20: 16x9", 2560, 1600, true },
|
||||
{ NULL, 0, 0, 0 },
|
||||
};
|
||||
|
||||
|
@ -432,13 +435,18 @@ static dllfunc_t wgl_funcs[] =
|
|||
{ "wglSwapBuffers" , (void **)&pwglSwapBuffers },
|
||||
{ "wglCreateContext" , (void **)&pwglCreateContext },
|
||||
{ "wglDeleteContext" , (void **)&pwglDeleteContext },
|
||||
{ "wglGetProcAddress" , (void **)&pwglGetProcAddress },
|
||||
{ "wglMakeCurrent" , (void **)&pwglMakeCurrent },
|
||||
{ "wglGetCurrentContext" , (void **)&pwglGetCurrentContext },
|
||||
{ "wglGetCurrentDC" , (void **)&pwglGetCurrentDC },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static dllfunc_t wglproc_funcs[] =
|
||||
{
|
||||
{ "wglGetProcAddress" , (void **)&pwglGetProcAddress },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static dllfunc_t wglswapintervalfuncs[] =
|
||||
{
|
||||
{ "wglSwapIntervalEXT" , (void **)&pwglSwapIntervalEXT },
|
||||
|
@ -524,7 +532,7 @@ void GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char *cv
|
|||
if(( name[2] == '_' || name[3] == '_' ) && !Q_strstr( glConfig.extensions_string, name ))
|
||||
{
|
||||
GL_SetExtension( r_ext, false ); // update render info
|
||||
MsgDev( D_NOTE, "- failed\n" );
|
||||
MsgDev( D_NOTE, "- ^1failed\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -541,7 +549,7 @@ void GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char *cv
|
|||
}
|
||||
|
||||
if( GL_Support( r_ext ))
|
||||
MsgDev( D_NOTE, "- enabled\n" );
|
||||
MsgDev( D_NOTE, "- ^2enabled\n" );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1405,13 +1413,14 @@ void GL_InitCommands( void )
|
|||
r_speeds = Cvar_Get( "r_speeds", "0", CVAR_ARCHIVE, "shows renderer speeds" );
|
||||
r_fullbright = Cvar_Get( "r_fullbright", "0", CVAR_CHEAT, "disable lightmaps, get fullbright for entities" );
|
||||
r_norefresh = Cvar_Get( "r_norefresh", "0", 0, "disable 3D rendering (use with caution)" );
|
||||
r_lighting_extended = Cvar_Get( "r_lighting_extended", "1", CVAR_ARCHIVE, "allow to get lighting from bmodels" );
|
||||
r_lighting_extended = Cvar_Get( "r_lighting_extended", "1", CVAR_ARCHIVE, "allow to get lighting from world and bmodels" );
|
||||
r_lighting_modulate = Cvar_Get( "r_lighting_modulate", "0.6", CVAR_ARCHIVE, "lightstyles modulate scale" );
|
||||
r_lighting_ambient = Cvar_Get( "r_lighting_ambient", "0.3", 0, "map ambient lighting scale" );
|
||||
r_adjust_fov = Cvar_Get( "r_adjust_fov", "1", CVAR_ARCHIVE, "making FOV adjustment for wide-screens" );
|
||||
r_novis = Cvar_Get( "r_novis", "0", 0, "ignore vis information (perfomance test)" );
|
||||
r_nocull = Cvar_Get( "r_nocull", "0", 0, "ignore frustrum culling (perfomance test)" );
|
||||
r_faceplanecull = Cvar_Get( "r_faceplanecull", "1", 0, "ignore face plane culling (perfomance test)" );
|
||||
r_detailtextures = Cvar_Get( "r_detailtextures", "1", CVAR_ARCHIVE, "enable detail textures support, use \"2\" for auto-generate mapname_detail.txt" );
|
||||
r_lockpvs = Cvar_Get( "r_lockpvs", "0", CVAR_CHEAT, "lockpvs area at current point (pvs test)" );
|
||||
r_lockcull = Cvar_Get( "r_lockcull", "0", CVAR_CHEAT, "lock frustrum area at current point (cull test)" );
|
||||
r_wateralpha = Cvar_Get( "r_wateralpha", "1", CVAR_ARCHIVE, "world water transparency factor" );
|
||||
|
@ -1440,7 +1449,8 @@ void GL_InitCommands( void )
|
|||
gl_extensions = Cvar_Get( "gl_extensions", "1", CVAR_GLCONFIG, "allow gl_extensions" );
|
||||
gl_texture_anisotropy = Cvar_Get( "r_anisotropy", "2.0", CVAR_ARCHIVE, "textures anisotropic filter" );
|
||||
gl_texture_lodbias = Cvar_Get( "gl_texture_lodbias", "0.0", CVAR_ARCHIVE, "LOD bias for mipmapped textures" );
|
||||
gl_compress_textures = Cvar_Get( "gl_compress_textures", "0", CVAR_ARCHIVE|CVAR_LATCH_VIDEO, "compress textures to safe video memory" );
|
||||
gl_compress_textures = Cvar_Get( "gl_compress_textures", "0", CVAR_GLCONFIG, "compress textures to safe video memory" );
|
||||
gl_luminance_textures = Cvar_Get( "gl_luminance_textures", "0", CVAR_GLCONFIG, "force all textures to luminance" );
|
||||
gl_allow_static = Cvar_Get( "gl_allow_static", "1", CVAR_ARCHIVE, "force to drawing non-moveable brushes as part of world (save FPS)" );
|
||||
gl_showtextures = Cvar_Get( "r_showtextures", "0", CVAR_CHEAT, "show all uploaded textures (type values from 1 to 9)" );
|
||||
gl_finish = Cvar_Get( "gl_finish", "0", CVAR_ARCHIVE, "use glFinish instead of glFlush" );
|
||||
|
@ -1480,9 +1490,13 @@ void GL_InitExtensions( void )
|
|||
glConfig.version_string = pglGetString( GL_VERSION );
|
||||
glConfig.extensions_string = pglGetString( GL_EXTENSIONS );
|
||||
MsgDev( D_INFO, "Video: %s\n", glConfig.renderer_string );
|
||||
|
||||
|
||||
// initalize until base opengl functions loaded
|
||||
GL_CheckExtension( "OpenGL Internal ProcAddress", wglproc_funcs, NULL, GL_WGL_PROCADDRESS );
|
||||
|
||||
GL_CheckExtension( "WGL_3DFX_gamma_control", wgl3DFXgammacontrolfuncs, NULL, GL_WGL_3DFX_GAMMA_CONTROL );
|
||||
GL_CheckExtension( "WGL_EXT_swap_control", wglswapintervalfuncs, NULL, GL_WGL_SWAPCONTROL );
|
||||
|
||||
GL_CheckExtension( "glDrawRangeElements", drawrangeelementsfuncs, "gl_drawrangeelments", GL_DRAW_RANGEELEMENTS_EXT );
|
||||
|
||||
if( !GL_Support( GL_DRAW_RANGEELEMENTS_EXT ))
|
||||
|
|
|
@ -65,7 +65,7 @@ float r_turbsin[] =
|
|||
|
||||
static qboolean CheckSkybox( const char *name )
|
||||
{
|
||||
const char *skybox_ext[3] = { "tga", "bmp", "jpg" };
|
||||
const char *skybox_ext[3] = { "jpg", "tga", "bmp" };
|
||||
int i, j, num_checked_sides;
|
||||
const char *sidename;
|
||||
|
||||
|
@ -448,6 +448,9 @@ void R_InitSky( mip_t *mt, texture_t *tx )
|
|||
uint transpix;
|
||||
int r, g, b;
|
||||
int i, j, p;
|
||||
char texname[32];
|
||||
|
||||
Q_snprintf( texname, sizeof( texname ), "%s%s.mip", ( mt->offsets[0] > 0 ) ? "#" : "", tx->name );
|
||||
|
||||
if( mt->offsets[0] > 0 )
|
||||
{
|
||||
|
@ -456,12 +459,12 @@ void R_InitSky( mip_t *mt, texture_t *tx )
|
|||
int size = (int)sizeof( mip_t ) + ((mt->width * mt->height * 85)>>6);
|
||||
if( world.version == HLBSP_VERSION ) size += sizeof( short ) + 768;
|
||||
|
||||
r_sky = FS_LoadImage( tx->name, (byte *)mt, size );
|
||||
r_sky = FS_LoadImage( texname, (byte *)mt, size );
|
||||
}
|
||||
else
|
||||
{
|
||||
// okay, loading it from wad
|
||||
r_sky = FS_LoadImage( tx->name, NULL, 0 );
|
||||
r_sky = FS_LoadImage( texname, NULL, 0 );
|
||||
}
|
||||
|
||||
// make sure what sky image is valid
|
||||
|
|
|
@ -601,6 +601,7 @@ void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate )
|
|||
{
|
||||
case SOUND_11k:
|
||||
case SOUND_22k:
|
||||
case SOUND_32k:
|
||||
case SOUND_44k:
|
||||
if( rate != pSource->rate )
|
||||
continue;
|
||||
|
@ -1004,6 +1005,11 @@ void MIX_UpsampleAllPaintbuffers( int end, int count )
|
|||
MIX_SetCurrentPaintbuffer( IROOMBUFFER );
|
||||
S_MixUpsample( count / ( SOUND_DMA_SPEED / SOUND_22k ), FILTERTYPE_LINEAR );
|
||||
#endif
|
||||
|
||||
#if (SOUND_DMA_SPEED >= SOUND_32k)
|
||||
// mix 32khz sounds:
|
||||
MIX_MixChannelsToPaintbuffer( end, SOUND_32k, SOUND_DMA_SPEED );
|
||||
#endif
|
||||
// mix all 44khz sounds to all active paintbuffers
|
||||
MIX_MixChannelsToPaintbuffer( end, SOUND_44k, SOUND_DMA_SPEED );
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ extern byte *sndpool;
|
|||
#define SOUND_DMA_SPEED 44100 // hardware playback rate
|
||||
#define SOUND_11k 11025 // 11khz sample rate
|
||||
#define SOUND_22k 22050 // 22khz sample rate
|
||||
#define SOUND_32k 32000 // 32khz sample rate
|
||||
#define SOUND_44k 44100 // 44khz sample rate
|
||||
|
||||
// fixed point stuff for real-time resampling
|
||||
|
|
|
@ -23,7 +23,7 @@ static char mond[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
|||
int Q_buildnum( void )
|
||||
{
|
||||
// do not touch this! Only author of Xash3D can increase buildnumbers!
|
||||
#if 0
|
||||
#if 1
|
||||
int m = 0, d = 0, y = 0;
|
||||
static int b = 0;
|
||||
|
||||
|
|
|
@ -365,10 +365,6 @@ void Cmd_Alias_f( void )
|
|||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
#define CMD_EXTDLL BIT( 0 ) // added by game.dll
|
||||
#define CMD_CLIENTDLL BIT( 1 ) // added by client.dll
|
||||
|
||||
typedef struct cmd_function_s
|
||||
{
|
||||
struct cmd_function_s *next;
|
||||
|
@ -444,7 +440,7 @@ void Cmd_TokenizeString( char *text )
|
|||
while( 1 )
|
||||
{
|
||||
// skip whitespace up to a /n
|
||||
while( *text && *text <= ' ' && *text != '\n' )
|
||||
while( *text && ((byte)*text) <= ' ' && *text != '\n' )
|
||||
text++;
|
||||
|
||||
if( *text == '\n' )
|
||||
|
@ -775,7 +771,7 @@ Cmd_Unlink
|
|||
unlink all commands with flag CVAR_EXTDLL
|
||||
============
|
||||
*/
|
||||
void Cmd_Unlink( void )
|
||||
void Cmd_Unlink( int group )
|
||||
{
|
||||
cmd_function_t *cmd;
|
||||
cmd_function_t **prev;
|
||||
|
@ -793,7 +789,7 @@ void Cmd_Unlink( void )
|
|||
cmd = *prev;
|
||||
if( !cmd ) break;
|
||||
|
||||
if( !( cmd->flags & CMD_EXTDLL ))
|
||||
if( group && !( cmd->flags & group ))
|
||||
{
|
||||
prev = &cmd->next;
|
||||
continue;
|
||||
|
|
|
@ -64,7 +64,7 @@ char *COM_ParseFile( char *data, char *token )
|
|||
|
||||
// skip whitespace
|
||||
skipwhite:
|
||||
while(( c = *data ) <= ' ' )
|
||||
while(( c = ((byte)*data)) <= ' ' )
|
||||
{
|
||||
if( c == 0 )
|
||||
return NULL; // end of file;
|
||||
|
@ -85,7 +85,7 @@ skipwhite:
|
|||
data++;
|
||||
while( 1 )
|
||||
{
|
||||
c = *data++;
|
||||
c = (byte)*data++;
|
||||
if( c == '\"' || !c )
|
||||
{
|
||||
token[len] = 0;
|
||||
|
@ -111,7 +111,7 @@ skipwhite:
|
|||
token[len] = c;
|
||||
data++;
|
||||
len++;
|
||||
c = *data;
|
||||
c = ((byte)*data);
|
||||
|
||||
if( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ',' )
|
||||
break;
|
||||
|
|
|
@ -79,8 +79,8 @@ typedef enum
|
|||
#define XASH_VERSION 0.85f // engine current version
|
||||
|
||||
// PERFORMANCE INFO
|
||||
#define MIN_FPS 0.1 // host minimum fps value for maxfps.
|
||||
#define MAX_FPS 1000.0 // upper limit for maxfps.
|
||||
#define MIN_FPS 15.0 // host minimum fps value for maxfps.
|
||||
#define MAX_FPS 500.0 // upper limit for maxfps.
|
||||
|
||||
#define MAX_FRAMETIME 0.1
|
||||
#define MIN_FRAMETIME 0.001
|
||||
|
|
|
@ -91,6 +91,9 @@ typedef struct
|
|||
// console input
|
||||
field_t input;
|
||||
|
||||
// chatfiled
|
||||
field_t chat;
|
||||
|
||||
// console history
|
||||
field_t historyLines[CON_HISTORY];
|
||||
int historyLine; // the line being displayed from history buffer will be <= nextHistoryLine
|
||||
|
@ -107,6 +110,7 @@ typedef struct
|
|||
} console_t;
|
||||
|
||||
static console_t con;
|
||||
static qboolean chat_team; // say_team is active
|
||||
|
||||
void Field_CharEvent( field_t *edit, int ch );
|
||||
|
||||
|
@ -214,6 +218,52 @@ int Con_StringLength( const char *string )
|
|||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_MessageMode_f
|
||||
================
|
||||
*/
|
||||
void Con_MessageMode_f( void )
|
||||
{
|
||||
chat_team = false;
|
||||
Key_SetKeyDest( key_message );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_MessageMode2_f
|
||||
================
|
||||
*/
|
||||
void Con_MessageMode2_f( void )
|
||||
{
|
||||
chat_team = true;
|
||||
Key_SetKeyDest( key_message );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_ToggleChat_f
|
||||
================
|
||||
*/
|
||||
void Con_ToggleChat_f( void )
|
||||
{
|
||||
Con_ClearTyping ();
|
||||
|
||||
if( cls.key_dest == key_console )
|
||||
{
|
||||
if( Cvar_VariableInteger( "sv_background" ))
|
||||
UI_SetActiveMenu( true );
|
||||
else UI_SetActiveMenu( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
UI_SetActiveMenu( false );
|
||||
Key_SetKeyDest( key_console );
|
||||
}
|
||||
|
||||
Con_ClearNotify();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_ToggleConsole_f
|
||||
|
@ -395,12 +445,12 @@ static void Con_LoadConchars( void )
|
|||
if( con_fontsize->integer > 2 ) Cvar_SetFloat( "con_fontsize", 2 );
|
||||
|
||||
// select properly fontsize
|
||||
if( scr_width->integer < 640 ) Cvar_SetFloat( "con_fontsize", 0 );
|
||||
if( scr_width->integer <= 640 ) Cvar_SetFloat( "con_fontsize", 0 );
|
||||
else if( scr_width->integer >= 1280 ) Cvar_SetFloat( "con_fontsize", 2 );
|
||||
else Cvar_SetFloat( "con_fontsize", 1 );
|
||||
|
||||
// loading conchars
|
||||
con.chars.hFontTexture = GL_LoadTexture( va( "fonts/font%i", con_fontsize->integer ), NULL, 0, TF_FONT );
|
||||
con.chars.hFontTexture = GL_LoadTexture( va( "fonts/font%i", con_fontsize->integer ), NULL, 0, TF_FONT|TF_NEAREST );
|
||||
|
||||
if( !con_fontsize->modified ) return; // font not changed
|
||||
|
||||
|
@ -592,6 +642,9 @@ void Con_Init( void )
|
|||
Con_ClearField( &con.input );
|
||||
con.input.widthInChars = con.linewidth;
|
||||
|
||||
Con_ClearField( &con.chat );
|
||||
con.chat.widthInChars = con.linewidth;
|
||||
|
||||
for( i = 0; i < CON_HISTORY; i++ )
|
||||
{
|
||||
Con_ClearField( &con.historyLines[i] );
|
||||
|
@ -601,6 +654,9 @@ void Con_Init( void )
|
|||
Cmd_AddCommand( "toggleconsole", Con_ToggleConsole_f, "opens or closes the console" );
|
||||
Cmd_AddCommand( "con_color", Con_SetColor_f, "set a custom console color" );
|
||||
Cmd_AddCommand( "clear", Con_Clear_f, "clear console history" );
|
||||
Cmd_AddCommand( "togglechat", Con_ToggleChat_f, "toggle console chat" );
|
||||
Cmd_AddCommand( "messagemode", Con_MessageMode_f, "enable message mode \"say\"" );
|
||||
Cmd_AddCommand( "messagemode2", Con_MessageMode2_f, "enable message mode \"say_team\"" );
|
||||
|
||||
MsgDev( D_NOTE, "Console initialized.\n" );
|
||||
con.initialized = true;
|
||||
|
@ -692,6 +748,13 @@ void Con_Print( const char *txt )
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_NPrint
|
||||
|
||||
Draw a single debug line with specified height
|
||||
================
|
||||
*/
|
||||
void Con_NPrintf( int idx, char *fmt, ... )
|
||||
{
|
||||
va_list args;
|
||||
|
@ -712,6 +775,13 @@ void Con_NPrintf( int idx, char *fmt, ... )
|
|||
con.draw_notify = true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_NXPrint
|
||||
|
||||
Draw a single debug line with specified height, color and time to live
|
||||
================
|
||||
*/
|
||||
void Con_NXPrintf( con_nprint_t *info, char *fmt, ... )
|
||||
{
|
||||
va_list args;
|
||||
|
@ -734,6 +804,13 @@ void Con_NXPrintf( con_nprint_t *info, char *fmt, ... )
|
|||
con.draw_notify = true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
UI_NPrint
|
||||
|
||||
Draw a single debug line with specified height (menu version)
|
||||
================
|
||||
*/
|
||||
void UI_NPrintf( int idx, char *fmt, ... )
|
||||
{
|
||||
va_list args;
|
||||
|
@ -754,6 +831,13 @@ void UI_NPrintf( int idx, char *fmt, ... )
|
|||
con.draw_notify = true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
UI_NXPrint
|
||||
|
||||
Draw a single debug line with specified height, color and time to live (menu version)
|
||||
================
|
||||
*/
|
||||
void UI_NXPrintf( con_nprint_t *info, char *fmt, ... )
|
||||
{
|
||||
va_list args;
|
||||
|
@ -986,7 +1070,7 @@ Key events are used for non-printable characters, others are gotten from char ev
|
|||
*/
|
||||
void Field_KeyDownEvent( field_t *edit, int key )
|
||||
{
|
||||
int len;
|
||||
int len;
|
||||
|
||||
// shift-insert is paste
|
||||
if((( key == K_INS ) || ( key == K_KP_INS )) && Key_IsDown( K_SHIFT ))
|
||||
|
@ -997,48 +1081,52 @@ void Field_KeyDownEvent( field_t *edit, int key )
|
|||
|
||||
len = Q_strlen( edit->buffer );
|
||||
|
||||
if ( key == K_DEL )
|
||||
if( key == K_DEL )
|
||||
{
|
||||
if ( edit->cursor < len )
|
||||
{
|
||||
if( edit->cursor < len )
|
||||
memmove( edit->buffer + edit->cursor, edit->buffer + edit->cursor + 1, len - edit->cursor );
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ( key == K_BACKSPACE )
|
||||
|
||||
if( key == K_BACKSPACE )
|
||||
{
|
||||
if ( edit->cursor > 0 )
|
||||
if( edit->cursor > 0 )
|
||||
{
|
||||
memmove( edit->buffer + edit->cursor - 1, edit->buffer + edit->cursor, len - edit->cursor + 1 );
|
||||
edit->cursor--;
|
||||
if ( edit->scroll ) edit->scroll--;
|
||||
if( edit->scroll ) edit->scroll--;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ( key == K_RIGHTARROW )
|
||||
|
||||
if( key == K_RIGHTARROW )
|
||||
{
|
||||
if ( edit->cursor < len ) edit->cursor++;
|
||||
if ( edit->cursor >= edit->scroll + edit->widthInChars && edit->cursor <= len )
|
||||
if( edit->cursor < len ) edit->cursor++;
|
||||
if( edit->cursor >= edit->scroll + edit->widthInChars && edit->cursor <= len )
|
||||
edit->scroll++;
|
||||
return;
|
||||
}
|
||||
if ( key == K_LEFTARROW )
|
||||
|
||||
if( key == K_LEFTARROW )
|
||||
{
|
||||
if ( edit->cursor > 0 ) edit->cursor--;
|
||||
if ( edit->cursor < edit->scroll ) edit->scroll--;
|
||||
if( edit->cursor > 0 ) edit->cursor--;
|
||||
if( edit->cursor < edit->scroll ) edit->scroll--;
|
||||
return;
|
||||
}
|
||||
if ( key == K_HOME || ( Q_tolower(key) == 'a' && Key_IsDown( K_CTRL )))
|
||||
|
||||
if( key == K_HOME || ( Q_tolower(key) == 'a' && Key_IsDown( K_CTRL )))
|
||||
{
|
||||
edit->cursor = 0;
|
||||
return;
|
||||
}
|
||||
if ( key == K_END || ( Q_tolower(key) == 'e' && Key_IsDown( K_CTRL )))
|
||||
|
||||
if( key == K_END || ( Q_tolower(key) == 'e' && Key_IsDown( K_CTRL )))
|
||||
{
|
||||
edit->cursor = len;
|
||||
return;
|
||||
}
|
||||
if ( key == K_INS )
|
||||
|
||||
if( key == K_INS )
|
||||
{
|
||||
host.key_overstrike = !host.key_overstrike;
|
||||
return;
|
||||
|
@ -1052,7 +1140,7 @@ Field_CharEvent
|
|||
*/
|
||||
void Field_CharEvent( field_t *edit, int ch )
|
||||
{
|
||||
int len;
|
||||
int len;
|
||||
|
||||
if( ch == 'v' - 'a' + 1 )
|
||||
{
|
||||
|
@ -1060,6 +1148,7 @@ void Field_CharEvent( field_t *edit, int ch )
|
|||
Field_Paste( edit );
|
||||
return;
|
||||
}
|
||||
|
||||
if( ch == 'c' - 'a' + 1 )
|
||||
{
|
||||
// ctrl-c clears the field
|
||||
|
@ -1076,6 +1165,7 @@ void Field_CharEvent( field_t *edit, int ch )
|
|||
edit->scroll = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if( ch == 'e' - 'a' + 1 )
|
||||
{
|
||||
// ctrl-e is end
|
||||
|
@ -1085,9 +1175,9 @@ void Field_CharEvent( field_t *edit, int ch )
|
|||
}
|
||||
|
||||
// ignore any other non printable chars
|
||||
if ( ch < 32 ) return;
|
||||
if( ch < 32 ) return;
|
||||
|
||||
if ( host.key_overstrike )
|
||||
if( host.key_overstrike )
|
||||
{
|
||||
if ( edit->cursor == MAX_STRING - 1 ) return;
|
||||
edit->buffer[edit->cursor] = ch;
|
||||
|
@ -1106,6 +1196,76 @@ void Field_CharEvent( field_t *edit, int ch )
|
|||
if( edit->cursor == len + 1) edit->buffer[edit->cursor] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
Field_DrawInputLine
|
||||
==================
|
||||
*/
|
||||
void Field_DrawInputLine( int x, int y, field_t *edit )
|
||||
{
|
||||
int len, cursorChar;
|
||||
int drawLen, hideChar = -1;
|
||||
int prestep, curPos;
|
||||
char str[MAX_SYSPATH];
|
||||
byte *colorDefault;
|
||||
|
||||
drawLen = edit->widthInChars;
|
||||
len = Q_strlen( edit->buffer ) + 1;
|
||||
colorDefault = g_color_table[ColorIndex( COLOR_DEFAULT )];
|
||||
|
||||
// guarantee that cursor will be visible
|
||||
if( len <= drawLen )
|
||||
{
|
||||
prestep = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( edit->scroll + drawLen > len )
|
||||
{
|
||||
edit->scroll = len - drawLen;
|
||||
if( edit->scroll < 0 ) edit->scroll = 0;
|
||||
}
|
||||
|
||||
prestep = edit->scroll;
|
||||
}
|
||||
|
||||
if( prestep + drawLen > len )
|
||||
drawLen = len - prestep;
|
||||
|
||||
// extract <drawLen> characters from the field at <prestep>
|
||||
ASSERT( drawLen < MAX_SYSPATH );
|
||||
|
||||
Q_memcpy( str, edit->buffer + prestep, drawLen );
|
||||
str[drawLen] = 0;
|
||||
|
||||
// save char for overstrike
|
||||
cursorChar = str[edit->cursor - prestep];
|
||||
|
||||
if( host.key_overstrike && cursorChar && !((int)( host.realtime * 4 ) & 1 ))
|
||||
hideChar = edit->cursor - prestep; // skip this char
|
||||
|
||||
// draw it
|
||||
Con_DrawGenericString( x, y, str, colorDefault, false, hideChar );
|
||||
|
||||
// draw the cursor
|
||||
if((int)( host.realtime * 4 ) & 1 ) return; // off blink
|
||||
|
||||
// calc cursor position
|
||||
str[edit->cursor - prestep] = 0;
|
||||
Con_DrawStringLen( str, &curPos, NULL );
|
||||
|
||||
if( host.key_overstrike && cursorChar )
|
||||
{
|
||||
// overstrike cursor
|
||||
pglEnable( GL_BLEND );
|
||||
pglDisable( GL_ALPHA_TEST );
|
||||
pglBlendFunc( GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA );
|
||||
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
|
||||
Con_DrawGenericChar( x + curPos, y, cursorChar, colorDefault );
|
||||
}
|
||||
else Con_DrawCharacter( x + curPos, y, '_', colorDefault );
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
|
@ -1247,6 +1407,42 @@ void Key_Console( int key )
|
|||
Field_KeyDownEvent( &con.input, key );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Key_Message
|
||||
|
||||
In game talk message
|
||||
================
|
||||
*/
|
||||
void Key_Message( int key )
|
||||
{
|
||||
char buffer[MAX_SYSPATH];
|
||||
|
||||
if( key == K_ESCAPE )
|
||||
{
|
||||
Key_SetKeyDest( key_game );
|
||||
Con_ClearField( &con.chat );
|
||||
return;
|
||||
}
|
||||
|
||||
if( key == K_ENTER || key == K_KP_ENTER )
|
||||
{
|
||||
if( con.chat.buffer[0] && cls.state == ca_active )
|
||||
{
|
||||
if( chat_team ) Q_snprintf( buffer, sizeof( buffer ), "say_team \"%s\"\n", con.chat.buffer );
|
||||
else Q_snprintf( buffer, sizeof( buffer ), "say \"%s\"\n", con.chat.buffer );
|
||||
|
||||
Cbuf_AddText( buffer );
|
||||
}
|
||||
|
||||
Key_SetKeyDest( key_game );
|
||||
Con_ClearField( &con.chat );
|
||||
return;
|
||||
}
|
||||
|
||||
Field_KeyDownEvent( &con.chat, key );
|
||||
}
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
|
@ -1263,74 +1459,18 @@ The input line scrolls horizontally if typing goes beyond the right edge
|
|||
*/
|
||||
void Con_DrawInput( void )
|
||||
{
|
||||
int len;
|
||||
int drawLen, hideChar = -1;
|
||||
int prestep, curPos;
|
||||
int x, y, cursorChar;
|
||||
char str[MAX_SYSPATH];
|
||||
byte *colorDefault;
|
||||
int x, y;
|
||||
|
||||
// don't draw anything (always draw if not active)
|
||||
if( cls.key_dest != key_console ) return;
|
||||
|
||||
x = QCHAR_WIDTH; // room for ']'
|
||||
y = con.vislines - ( con.charHeight * 2 );
|
||||
drawLen = con.input.widthInChars;
|
||||
len = Q_strlen( con.input.buffer ) + 1;
|
||||
colorDefault = g_color_table[ColorIndex( COLOR_DEFAULT )];
|
||||
|
||||
// guarantee that cursor will be visible
|
||||
if( len <= drawLen )
|
||||
{
|
||||
prestep = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( con.input.scroll + drawLen > len )
|
||||
{
|
||||
con.input.scroll = len - drawLen;
|
||||
if( con.input.scroll < 0 )
|
||||
con.input.scroll = 0;
|
||||
}
|
||||
prestep = con.input.scroll;
|
||||
}
|
||||
|
||||
if( prestep + drawLen > len )
|
||||
drawLen = len - prestep;
|
||||
|
||||
// extract <drawLen> characters from the field at <prestep>
|
||||
ASSERT( drawLen < MAX_SYSPATH );
|
||||
|
||||
Q_memcpy( str, con.input.buffer + prestep, drawLen );
|
||||
str[drawLen] = 0;
|
||||
|
||||
// save char for overstrike
|
||||
cursorChar = str[con.input.cursor - prestep];
|
||||
|
||||
if( host.key_overstrike && cursorChar && !((int)( host.realtime * 4 ) & 1 ))
|
||||
hideChar = con.input.cursor - prestep; // skip this char
|
||||
|
||||
// draw it
|
||||
Con_DrawGenericString( x, y, str, colorDefault, false, hideChar );
|
||||
Con_DrawCharacter( QCHAR_WIDTH >> 1, y, ']', colorDefault );
|
||||
|
||||
// draw the cursor
|
||||
if((int)( host.realtime * 4 ) & 1 ) return; // off blink
|
||||
|
||||
// calc cursor position
|
||||
str[con.input.cursor - prestep] = 0;
|
||||
Con_DrawStringLen( str, &curPos, NULL );
|
||||
|
||||
if( host.key_overstrike && cursorChar )
|
||||
{
|
||||
// overstrike cursor
|
||||
pglEnable( GL_BLEND );
|
||||
pglDisable( GL_ALPHA_TEST );
|
||||
pglBlendFunc( GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA );
|
||||
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
|
||||
Con_DrawGenericChar( x + curPos, y, cursorChar, colorDefault );
|
||||
}
|
||||
else Con_DrawCharacter( x + curPos, y, '_', colorDefault );
|
||||
Field_DrawInputLine( x, y, &con.input );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1400,33 +1540,53 @@ void Con_DrawNotify( void )
|
|||
short *text;
|
||||
float time;
|
||||
|
||||
if( !host.developer || Cvar_VariableInteger( "sv_background" ))
|
||||
return;
|
||||
|
||||
currentColor = 7;
|
||||
pglColor4ubv( g_color_table[currentColor] );
|
||||
|
||||
for( i = con.current - CON_TIMES + 1; i <= con.current; i++ )
|
||||
if( host.developer && !Cvar_VariableInteger( "sv_background" ))
|
||||
{
|
||||
if( i < 0 ) continue;
|
||||
time = con.times[i % CON_TIMES];
|
||||
if( time == 0 ) continue;
|
||||
time = host.realtime - time;
|
||||
currentColor = 7;
|
||||
pglColor4ubv( g_color_table[currentColor] );
|
||||
|
||||
if( time > con_notifytime->value )
|
||||
continue; // expired
|
||||
for( i = con.current - CON_TIMES + 1; i <= con.current; i++ )
|
||||
{
|
||||
if( i < 0 ) continue;
|
||||
time = con.times[i % CON_TIMES];
|
||||
if( time == 0 ) continue;
|
||||
time = host.realtime - time;
|
||||
|
||||
if( time > con_notifytime->value )
|
||||
continue; // expired
|
||||
|
||||
text = con.text + (i % con.totallines) * con.linewidth;
|
||||
start = con.charWidths[' ']; // offset one space at left screen side
|
||||
|
||||
for( x = 0; x < con.linewidth; x++ )
|
||||
{
|
||||
if((( text[x] >> 8 ) & 7 ) != currentColor )
|
||||
currentColor = ( text[x] >> 8 ) & 7;
|
||||
start += Con_DrawCharacter( start, v, text[x] & 0xFF, g_color_table[currentColor] );
|
||||
}
|
||||
v += con.charHeight;
|
||||
}
|
||||
}
|
||||
|
||||
if( cls.key_dest == key_message )
|
||||
{
|
||||
char buf[16];
|
||||
int len;
|
||||
|
||||
currentColor = 7;
|
||||
pglColor4ubv( g_color_table[currentColor] );
|
||||
|
||||
text = con.text + (i % con.totallines) * con.linewidth;
|
||||
start = con.charWidths[' ']; // offset one space at left screen side
|
||||
|
||||
for( x = 0; x < con.linewidth; x++ )
|
||||
{
|
||||
if((( text[x] >> 8 ) & 7 ) != currentColor )
|
||||
currentColor = ( text[x] >> 8 ) & 7;
|
||||
start += Con_DrawCharacter( start, v, text[x] & 0xFF, g_color_table[currentColor] );
|
||||
}
|
||||
v += con.charHeight;
|
||||
if( chat_team ) Q_strncpy( buf, "say_team: ", sizeof( buf ));
|
||||
else Q_strncpy( buf, "say: ", sizeof( buf ));
|
||||
|
||||
Con_DrawStringLen( buf, &len, NULL );
|
||||
Con_DrawString( start, v, buf, g_color_table[7] );
|
||||
|
||||
Field_DrawInputLine( start + len, v, &con.chat );
|
||||
}
|
||||
|
||||
pglColor4ub( 255, 255, 255, 255 );
|
||||
}
|
||||
|
||||
|
@ -1591,7 +1751,7 @@ void Con_DrawConsole( void )
|
|||
{
|
||||
if( con.displayFrac )
|
||||
Con_DrawSolidConsole( con.displayFrac );
|
||||
else if( cls.state == ca_active && cls.key_dest == key_game )
|
||||
else if( cls.state == ca_active && ( cls.key_dest == key_game || cls.key_dest == key_message ))
|
||||
Con_DrawNotify(); // draw notify lines
|
||||
}
|
||||
break;
|
||||
|
@ -1613,9 +1773,11 @@ void Con_DrawVersion( void )
|
|||
int start, height = scr_height->integer;
|
||||
string curbuild;
|
||||
|
||||
if( cls.key_dest != key_menu ) return;
|
||||
if( cls.key_dest != key_menu && cls.scrshot_action != scrshot_normal ) return;
|
||||
|
||||
Q_snprintf( curbuild, MAX_STRING, "v%i/%g (build %i)", PROTOCOL_VERSION, XASH_VERSION, Q_buildnum( ));
|
||||
if( cls.scrshot_action == scrshot_normal )
|
||||
Q_snprintf( curbuild, MAX_STRING, "Xash3D v%i/%g (build %i)", PROTOCOL_VERSION, XASH_VERSION, Q_buildnum( ));
|
||||
else Q_snprintf( curbuild, MAX_STRING, "v%i/%g (build %i)", PROTOCOL_VERSION, XASH_VERSION, Q_buildnum( ));
|
||||
Con_DrawStringLen( curbuild, &stringLen, &charH );
|
||||
start = scr_width->integer - stringLen * 1.05f;
|
||||
stringLen = Con_StringLength( curbuild );
|
||||
|
@ -1668,9 +1830,24 @@ CONSOLE INTERFACE
|
|||
|
||||
==============================================================================
|
||||
*/
|
||||
/*
|
||||
================
|
||||
Con_CharEvent
|
||||
|
||||
Console input
|
||||
================
|
||||
*/
|
||||
void Con_CharEvent( int key )
|
||||
{
|
||||
Field_CharEvent( &con.input, key );
|
||||
// distribute the key down event to the apropriate handler
|
||||
if( cls.key_dest == key_console )
|
||||
{
|
||||
Field_CharEvent( &con.input, key );
|
||||
}
|
||||
else if( cls.key_dest == key_message )
|
||||
{
|
||||
Field_CharEvent( &con.chat, key );
|
||||
}
|
||||
}
|
||||
|
||||
void Con_VidInit( void )
|
||||
|
|
|
@ -27,6 +27,9 @@ enum
|
|||
TIME_FILENAME,
|
||||
};
|
||||
|
||||
#define CMD_EXTDLL BIT( 0 ) // added by game.dll
|
||||
#define CMD_CLIENTDLL BIT( 1 ) // added by client.dll
|
||||
|
||||
typedef void (*setpair_t)( const char *key, const char *value, void *buffer, void *numpairs );
|
||||
typedef void (*xcommand_t)( void );
|
||||
|
||||
|
@ -118,7 +121,7 @@ uint Cmd_Argc( void );
|
|||
char *Cmd_Args( void );
|
||||
char *Cmd_Argv( int arg );
|
||||
void Cmd_Init( void );
|
||||
void Cmd_Unlink( void );
|
||||
void Cmd_Unlink( int group );
|
||||
void Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc );
|
||||
void Cmd_AddGameCommand( const char *cmd_name, xcommand_t function );
|
||||
void Cmd_AddClientCommand( const char *cmd_name, xcommand_t function );
|
||||
|
|
|
@ -450,7 +450,7 @@ convar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force )
|
|||
// step through the string, only copying back in characters that are printable
|
||||
while( *pS )
|
||||
{
|
||||
if( *pS < 32 || *pS > 255 )
|
||||
if( ((byte)*pS) < 32 || ((byte)*pS) > 255 )
|
||||
{
|
||||
pS++;
|
||||
continue;
|
||||
|
|
|
@ -26,6 +26,7 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, size_t filesize )
|
|||
byte palette[256][4];
|
||||
int i, columns, column, rows, row, bpp = 1;
|
||||
int cbPalBytes = 0, padSize = 0, bps = 0;
|
||||
qboolean load_qfont = false;
|
||||
bmp_t bhdr;
|
||||
|
||||
if( filesize < sizeof( bhdr )) return false;
|
||||
|
@ -81,9 +82,21 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, size_t filesize )
|
|||
image.width = columns = bhdr.width;
|
||||
image.height = rows = abs( bhdr.height );
|
||||
|
||||
if(!Image_ValidSize( name ))
|
||||
if( !Image_ValidSize( name ))
|
||||
return false;
|
||||
|
||||
// special hack for loading qfont
|
||||
if( !Q_strcmp( "#XASH_SYSTEMFONT_001", name ))
|
||||
{
|
||||
// NOTE: same as system font we can use 4-bit bmps only
|
||||
// step1: move main layer into alpha-channel (give grayscale from RED channel)
|
||||
// step2: fill main layer with 255 255 255 color (white)
|
||||
// step3: ????
|
||||
// step4: PROFIT!!! (economy up to 150 kb for menu.dll final size)
|
||||
image.flags |= IMAGE_HAS_ALPHA;
|
||||
load_qfont = true;
|
||||
}
|
||||
|
||||
if( bhdr.bitsPerPixel <= 8 )
|
||||
{
|
||||
// figure out how many entires are actually in the table
|
||||
|
@ -170,16 +183,36 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, size_t filesize )
|
|||
case 4:
|
||||
alpha = *buf_p++;
|
||||
palIndex = alpha >> 4;
|
||||
*pixbuf++ = palette[palIndex][2];
|
||||
*pixbuf++ = palette[palIndex][1];
|
||||
*pixbuf++ = palette[palIndex][0];
|
||||
*pixbuf++ = palette[palIndex][3];
|
||||
if( load_qfont )
|
||||
{
|
||||
*pixbuf++ = red = 255;
|
||||
*pixbuf++ = green = 255;
|
||||
*pixbuf++ = blue = 255;
|
||||
*pixbuf++ = palette[palIndex][2];
|
||||
}
|
||||
else
|
||||
{
|
||||
*pixbuf++ = red = palette[palIndex][2];
|
||||
*pixbuf++ = green = palette[palIndex][1];
|
||||
*pixbuf++ = blue = palette[palIndex][0];
|
||||
*pixbuf++ = palette[palIndex][3];
|
||||
}
|
||||
if( ++column == columns ) break;
|
||||
palIndex = alpha & 0x0F;
|
||||
*pixbuf++ = palette[palIndex][2];
|
||||
*pixbuf++ = palette[palIndex][1];
|
||||
*pixbuf++ = palette[palIndex][0];
|
||||
*pixbuf++ = palette[palIndex][3];
|
||||
if( load_qfont )
|
||||
{
|
||||
*pixbuf++ = red = 255;
|
||||
*pixbuf++ = green = 255;
|
||||
*pixbuf++ = blue = 255;
|
||||
*pixbuf++ = palette[palIndex][2];
|
||||
}
|
||||
else
|
||||
{
|
||||
*pixbuf++ = red = palette[palIndex][2];
|
||||
*pixbuf++ = green = palette[palIndex][1];
|
||||
*pixbuf++ = blue = palette[palIndex][0];
|
||||
*pixbuf++ = palette[palIndex][3];
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
palIndex = *buf_p++;
|
||||
|
|
|
@ -49,7 +49,7 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, size_t filesize )
|
|||
if( targa_header.id_length != 0 ) buf_p += targa_header.id_length; // skip TARGA image comment
|
||||
|
||||
// check for tga file
|
||||
if(!Image_ValidSize( name )) return false;
|
||||
if( !Image_ValidSize( name )) return false;
|
||||
|
||||
image.type = PF_RGBA_32; // always exctracted to 32-bit buffer
|
||||
|
||||
|
|
|
@ -95,8 +95,8 @@ static const loadpixformat_t load_null[] =
|
|||
|
||||
static const loadpixformat_t load_game[] =
|
||||
{
|
||||
{ "%s%s.%s", "bmp", Image_LoadBMP, IL_HINT_NO }, // WON menu images
|
||||
{ "%s%s.%s", "tga", Image_LoadTGA, IL_HINT_NO }, // hl vgui menus
|
||||
{ "%s%s.%s", "bmp", Image_LoadBMP, IL_HINT_NO }, // hl skyboxes
|
||||
{ "%s%s.%s", "jpg", Image_LoadJPG, IL_HINT_NO }, // hl skyboxes
|
||||
{ "%s%s.%s", "mip", Image_LoadMIP, IL_HINT_NO }, // hl textures from wad or buffer
|
||||
{ "%s%s.%s", "mdl", Image_LoadMDL, IL_HINT_HL }, // hl studio model skins
|
||||
|
|
|
@ -78,10 +78,11 @@ qboolean Image_LoadFNT( const char *name, const byte *buffer, size_t filesize )
|
|||
|
||||
if( filesize < sizeof( font ))
|
||||
return false;
|
||||
|
||||
Q_memcpy( &font, buffer, sizeof( font ));
|
||||
|
||||
// last sixty four bytes - what the hell ????
|
||||
size = sizeof( qfont_t ) - 4 + ( 128 * font.width * QCHAR_WIDTH ) + sizeof( short ) + 768 + 64;
|
||||
size = sizeof( qfont_t ) - 4 + ( font.height * font.width * QCHAR_WIDTH ) + sizeof( short ) + 768 + 64;
|
||||
|
||||
if( size != filesize )
|
||||
{
|
||||
|
@ -96,21 +97,22 @@ qboolean Image_LoadFNT( const char *name, const byte *buffer, size_t filesize )
|
|||
image.height = font.height;
|
||||
}
|
||||
|
||||
if(!Image_LumpValidSize( name )) return false;
|
||||
fin = buffer + sizeof( font ) - 4;
|
||||
if( !Image_LumpValidSize( name ))
|
||||
return false;
|
||||
|
||||
fin = buffer + sizeof( font ) - 4;
|
||||
pal = fin + (image.width * image.height);
|
||||
numcolors = *(short *)pal, pal += sizeof( short );
|
||||
image.flags |= IMAGE_HAS_ALPHA; // fonts always have transparency
|
||||
|
||||
if( numcolors == 768 )
|
||||
{
|
||||
// newstyle font
|
||||
Image_GetPaletteLMP( pal, LUMP_QFONT );
|
||||
image.flags |= IMAGE_HAS_ALPHA; // fonts always have transparency
|
||||
}
|
||||
else if( numcolors == 256 )
|
||||
{
|
||||
// oldstyle font
|
||||
// oldstyle font (no transparency)
|
||||
Image_GetPaletteLMP( pal, LUMP_TRANSPARENT );
|
||||
}
|
||||
else
|
||||
|
|
|
@ -548,6 +548,9 @@ void Key_Event( int key, qboolean down )
|
|||
if( host.mouse_visible && cls.state != ca_cinematic )
|
||||
return; // handled in client.dll
|
||||
break;
|
||||
case key_message:
|
||||
Key_Message( key );
|
||||
return;
|
||||
case key_console:
|
||||
if( cls.state == ca_active && !cl.background )
|
||||
Key_SetKeyDest( key_game );
|
||||
|
@ -636,6 +639,10 @@ void Key_Event( int key, qboolean down )
|
|||
{
|
||||
Key_Console( key );
|
||||
}
|
||||
else if( cls.key_dest == key_message )
|
||||
{
|
||||
Key_Message( key );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -658,6 +665,9 @@ void Key_SetKeyDest( int key_dest )
|
|||
case key_console:
|
||||
cls.key_dest = key_console;
|
||||
break;
|
||||
case key_message:
|
||||
cls.key_dest = key_message;
|
||||
break;
|
||||
default:
|
||||
Host_Error( "Key_SetKeyDest: wrong destination (%i)\n", key_dest );
|
||||
break;
|
||||
|
@ -701,7 +711,7 @@ void CL_CharEvent( int key )
|
|||
if( key == '`' || key == '~' ) return;
|
||||
|
||||
// distribute the key down event to the apropriate handler
|
||||
if( cls.key_dest == key_console )
|
||||
if( cls.key_dest == key_console || cls.key_dest == key_message )
|
||||
{
|
||||
Con_CharEvent( key );
|
||||
}
|
||||
|
|
|
@ -164,7 +164,8 @@ qboolean LibraryLoadSymbols( dll_user_t *hInst )
|
|||
goto table_error;
|
||||
}
|
||||
|
||||
if( !Q_strcmp( section_header.Name, ".rdata" ))
|
||||
if((( optional_header.DataDirectory[0].VirtualAddress >= section_header.VirtualAddress ) &&
|
||||
(optional_header.DataDirectory[0].VirtualAddress < (section_header.VirtualAddress + section_header.Misc.VirtualSize))))
|
||||
{
|
||||
rdata_found = true;
|
||||
break;
|
||||
|
|
|
@ -29,6 +29,7 @@ static model_t *com_models[MAX_MODELS]; // shared replacement modeltable
|
|||
static model_t cm_models[MAX_MODELS];
|
||||
static int cm_nummodels = 0;
|
||||
static byte visdata[MAX_MAP_LEAFS/8]; // intermediate buffer
|
||||
int bmodel_version; // global stuff to detect bsp version
|
||||
|
||||
model_t *loadmodel;
|
||||
model_t *worldmodel;
|
||||
|
@ -484,10 +485,13 @@ static void Mod_LoadTextures( const dlump_t *l )
|
|||
mip_t *mt;
|
||||
int i, j;
|
||||
|
||||
// release old sky layers first
|
||||
GL_FreeTexture( tr.solidskyTexture );
|
||||
GL_FreeTexture( tr.alphaskyTexture );
|
||||
tr.solidskyTexture = tr.alphaskyTexture = 0;
|
||||
if( world.loading )
|
||||
{
|
||||
// release old sky layers first
|
||||
GL_FreeTexture( tr.solidskyTexture );
|
||||
GL_FreeTexture( tr.alphaskyTexture );
|
||||
tr.solidskyTexture = tr.alphaskyTexture = 0;
|
||||
}
|
||||
|
||||
if( !l->filelen )
|
||||
{
|
||||
|
@ -535,7 +539,7 @@ static void Mod_LoadTextures( const dlump_t *l )
|
|||
tx->height = mt->height;
|
||||
|
||||
// check for sky texture (quake1 only!)
|
||||
if( world.version == Q1BSP_VERSION && !Q_strncmp( mt->name, "sky", 3 ))
|
||||
if( world.loading && world.version == Q1BSP_VERSION && !Q_strncmp( mt->name, "sky", 3 ))
|
||||
{
|
||||
R_InitSky( mt, tx );
|
||||
}
|
||||
|
@ -544,7 +548,7 @@ static void Mod_LoadTextures( const dlump_t *l )
|
|||
// NOTE: imagelib detect miptex version by size
|
||||
// 770 additional bytes is indicated custom palette
|
||||
int size = (int)sizeof( mip_t ) + ((mt->width * mt->height * 85)>>6);
|
||||
if( world.version == HLBSP_VERSION ) size += sizeof( short ) + 768;
|
||||
if( bmodel_version == HLBSP_VERSION ) size += sizeof( short ) + 768;
|
||||
|
||||
tx->gl_texturenum = GL_LoadTexture( texname, (byte *)mt, size, 0 );
|
||||
}
|
||||
|
@ -566,7 +570,7 @@ static void Mod_LoadTextures( const dlump_t *l )
|
|||
// NOTE: imagelib detect miptex version by size
|
||||
// 770 additional bytes is indicated custom palette
|
||||
int size = (int)sizeof( mip_t ) + ((mt->width * mt->height * 85)>>6);
|
||||
if( world.version == HLBSP_VERSION ) size += sizeof( short ) + 768;
|
||||
if( bmodel_version == HLBSP_VERSION ) size += sizeof( short ) + 768;
|
||||
|
||||
tx->fb_texturenum = GL_LoadTexture( texname, (byte *)mt, size, TF_MAKELUMA|TF_NOMIPMAP );
|
||||
}
|
||||
|
@ -789,7 +793,7 @@ static void Mod_LoadLighting( const dlump_t *l )
|
|||
if( !l->filelen ) return;
|
||||
in = (void *)(mod_base + l->fileofs);
|
||||
|
||||
switch( world.version )
|
||||
switch( bmodel_version )
|
||||
{
|
||||
case Q1BSP_VERSION:
|
||||
// expand the white lighting data
|
||||
|
@ -953,7 +957,7 @@ static void Mod_LoadSurfaces( const dlump_t *l )
|
|||
|
||||
if( loadmodel->lightdata && in->lightofs != -1 )
|
||||
{
|
||||
if( world.version == HLBSP_VERSION )
|
||||
if( bmodel_version == HLBSP_VERSION )
|
||||
out->samples = loadmodel->lightdata + (in->lightofs / 3);
|
||||
else out->samples = loadmodel->lightdata + in->lightofs;
|
||||
}
|
||||
|
@ -961,7 +965,7 @@ static void Mod_LoadSurfaces( const dlump_t *l )
|
|||
for( j = 0; j < MAXLIGHTMAPS; j++ )
|
||||
out->styles[j] = in->styles[j];
|
||||
|
||||
if( out->flags & SURF_DRAWSKY && world.version == Q1BSP_VERSION )
|
||||
if( world.loading && out->flags & SURF_DRAWSKY && world.version == Q1BSP_VERSION )
|
||||
GL_SubdivideSurface( out ); // cut up polygon for warps
|
||||
|
||||
if( out->flags & SURF_DRAWTURB )
|
||||
|
@ -1222,6 +1226,9 @@ Mod_LoadVisibility
|
|||
*/
|
||||
static void Mod_LoadVisibility( const dlump_t *l )
|
||||
{
|
||||
// bmodels has no visibility
|
||||
if( !world.loading ) return;
|
||||
|
||||
if( !l->filelen )
|
||||
{
|
||||
MsgDev( D_WARN, "map ^2%s^7 has no visibility\n", loadmodel->name );
|
||||
|
@ -1367,7 +1374,7 @@ void Mod_CalcPHS( void )
|
|||
size_t phsdatasize;
|
||||
|
||||
// no worldmodel or no visdata
|
||||
if( !worldmodel || !worldmodel->visdata )
|
||||
if( !world.loading || !worldmodel || !worldmodel->visdata )
|
||||
return;
|
||||
|
||||
MsgDev( D_NOTE, "Building PAS...\n" );
|
||||
|
@ -1539,6 +1546,7 @@ static void Mod_LoadBrushModel( model_t *mod, const void *buffer )
|
|||
// will be merged later
|
||||
loadmodel->type = mod_brush;
|
||||
if( world.loading ) world.version = i;
|
||||
bmodel_version = i; // share it
|
||||
|
||||
// swap all the lumps
|
||||
mod_base = (byte *)header;
|
||||
|
@ -1705,6 +1713,7 @@ Loads a model into the cache
|
|||
model_t *Mod_LoadModel( model_t *mod, qboolean crash )
|
||||
{
|
||||
byte *buf;
|
||||
char tempname[64];
|
||||
|
||||
if( !mod )
|
||||
{
|
||||
|
@ -1717,12 +1726,17 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
|
|||
if( mod->mempool || mod->name[0] == '*' )
|
||||
return mod;
|
||||
|
||||
// store modelname to show error
|
||||
Q_strncpy( tempname, mod->name, sizeof( tempname ));
|
||||
|
||||
buf = COM_LoadFile( mod->name, 0, NULL );
|
||||
if( !buf )
|
||||
{
|
||||
if( crash ) Host_Error( "Mod_ForName: %s couldn't load\n", mod->name );
|
||||
else MsgDev( D_ERROR, "Mod_ForName: %s couldn't load\n", mod->name );
|
||||
Q_memset( mod, 0, sizeof( model_t ));
|
||||
|
||||
if( crash ) Host_Error( "Mod_ForName: %s couldn't load\n", tempname );
|
||||
else MsgDev( D_ERROR, "Mod_ForName: %s couldn't load\n", tempname );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1753,8 +1767,8 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
|
|||
Mod_FreeModel( mod );
|
||||
|
||||
// check for loading problems
|
||||
if( crash ) Host_Error( "Mod_ForName: %s unknown format\n", mod->name );
|
||||
else MsgDev( D_ERROR, "Mod_ForName: %s unknown format\n", mod->name );
|
||||
if( crash ) Host_Error( "Mod_ForName: %s unknown format\n", tempname );
|
||||
else MsgDev( D_ERROR, "Mod_ForName: %s unknown format\n", tempname );
|
||||
return NULL;
|
||||
}
|
||||
return mod;
|
||||
|
@ -1800,11 +1814,13 @@ void Mod_LoadWorld( const char *name, uint *checksum, qboolean force )
|
|||
}
|
||||
|
||||
// clear all studio submodels on restart
|
||||
for( i = 0; i < cm_nummodels; i++ )
|
||||
// HACKHACK: throw all external BSP-models to refresh their lightmaps properly
|
||||
for( i = 1; i < cm_nummodels; i++ )
|
||||
{
|
||||
if( cm_models[i].type != mod_studio )
|
||||
continue;
|
||||
cm_models[i].submodels = NULL;
|
||||
if( cm_models[i].type == mod_studio )
|
||||
cm_models[i].submodels = NULL;
|
||||
else if( cm_models[i].type == mod_brush )
|
||||
Mod_FreeModel( cm_models + i );
|
||||
}
|
||||
|
||||
// purge all submodels
|
||||
|
|
|
@ -59,6 +59,7 @@ GNU General Public License for more details.
|
|||
// bytes will be stripped by the networking channel layer
|
||||
#define NET_MAX_MESSAGE PAD_NUMBER(( NET_MAX_PAYLOAD + HEADER_BYTES ), 16 )
|
||||
|
||||
#define MASTERSERVER_ADR "hl1master.steampowered.com:27010"
|
||||
#define PORT_MASTER 27010
|
||||
#define PORT_CLIENT 27005
|
||||
#define PORT_SERVER 27015
|
||||
|
@ -201,6 +202,7 @@ void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport );
|
|||
qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg );
|
||||
qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg );
|
||||
void Netchan_CreateFragments( qboolean server, netchan_t *chan, sizebuf_t *msg );
|
||||
int Netchan_CreateFileFragments( qboolean server, netchan_t *chan, const char *filename );
|
||||
void Netchan_Transmit( netchan_t *chan, int lengthInBytes, byte *data );
|
||||
void Netchan_TransmitBits( netchan_t *chan, int lengthInBits, byte *data );
|
||||
void Netchan_OutOfBand( int net_socket, netadr_t adr, int length, byte *data );
|
||||
|
@ -209,6 +211,7 @@ qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg );
|
|||
void Netchan_UpdateProgress( netchan_t *chan );
|
||||
qboolean Netchan_IncomingReady( netchan_t *chan );
|
||||
qboolean Netchan_CanPacket( netchan_t *chan );
|
||||
void Netchan_FragSend( netchan_t *chan );
|
||||
void Netchan_Clear( netchan_t *chan );
|
||||
|
||||
// huffman compression
|
||||
|
|
|
@ -553,7 +553,7 @@ static void NET_OpenIP( void )
|
|||
|
||||
if( !ip_sockets[NS_SERVER] )
|
||||
{
|
||||
port = Cvar_Get("ip_hostport", "0", CVAR_INIT, "network server port" )->integer;
|
||||
port = Cvar_Get( "ip_hostport", "0", CVAR_INIT, "network server port" )->integer;
|
||||
if( !port ) port = Cvar_Get( "port", va( "%i", PORT_SERVER ), CVAR_INIT, "network default port" )->integer;
|
||||
|
||||
ip_sockets[NS_SERVER] = NET_IPSocket( net_ip->string, port );
|
||||
|
|
|
@ -16,7 +16,7 @@ GNU General Public License for more details.
|
|||
#ifndef PROTOCOL_H
|
||||
#define PROTOCOL_H
|
||||
|
||||
#define PROTOCOL_VERSION 41
|
||||
#define PROTOCOL_VERSION 42
|
||||
|
||||
// server to client
|
||||
#define svc_bad 0 // immediately crash client when received
|
||||
|
@ -29,7 +29,7 @@ GNU General Public License for more details.
|
|||
#define svc_time 7 // [float] server time
|
||||
#define svc_print 8 // [byte] id [string] null terminated string
|
||||
#define svc_stufftext 9 // [string] stuffed into client's console buffer
|
||||
#define svc_setangle 10 // [angle angle] set the view angle to this absolute value
|
||||
#define svc_setangle 10 // [angle angle angle] set the view angle to this absolute value
|
||||
#define svc_serverdata 11 // [long] protocol ...
|
||||
#define svc_lightstyle 12 // [index][pattern]
|
||||
#define svc_updateuserinfo 13 // [byte] playernum, [string] userinfo
|
||||
|
@ -62,9 +62,9 @@ GNU General Public License for more details.
|
|||
#define svc_packetentities 40 // [short][...]
|
||||
#define svc_deltapacketentities 41 // [short][byte][...]
|
||||
#define svc_chokecount 42 // [byte]
|
||||
|
||||
#define svc_resourcelist 43 // [short][...]
|
||||
#define svc_deltamovevars 44 // [movevars_t]
|
||||
|
||||
#define svc_customization 45
|
||||
#define svc_crosshairangle 47 // [byte][byte]
|
||||
#define svc_soundfade 48 // [float*4] sound fade parms
|
||||
|
||||
|
@ -154,4 +154,13 @@ GNU General Public License for more details.
|
|||
#error MAX_COORD_INTEGER does not match COORD_INTEGER_BITS
|
||||
#endif
|
||||
|
||||
#define MAX_RESOURCES (MAX_MODELS+MAX_SOUNDS+MAX_CUSTOM+MAX_EVENTS)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int rescount;
|
||||
int restype[MAX_RESOURCES];
|
||||
char resnames[MAX_RESOURCES][CS_SIZE];
|
||||
} resourcelist_t;
|
||||
|
||||
#endif//PROTOCOL_H
|
Binary file not shown.
Binary file not shown.
|
@ -17,246 +17,33 @@ GNU General Public License for more details.
|
|||
|
||||
/*
|
||||
=======================================================================
|
||||
LIBMAD DEFINITION
|
||||
MPG123 DEFINITION
|
||||
=======================================================================
|
||||
*/
|
||||
#define BUFFER_GUARD 8
|
||||
#define BUFFER_MDLEN (511 + 2048 + BUFFER_GUARD)
|
||||
#define BUFFER_SIZE 4096 // must be large than BUFFER_MDLEN
|
||||
#define MP3_ERR -1
|
||||
#define MP3_OK 0
|
||||
#define MP3_NEED_MORE 1
|
||||
|
||||
#define MPEG_F_FRACBITS 28
|
||||
#define MPEG_F( x ) ((int)( x##L ))
|
||||
#define MPEG_F_ONE MPEG_F( 0x10000000 )
|
||||
#define FRAME_SIZE 16384 // must match with mp3 frame size
|
||||
|
||||
enum
|
||||
typedef struct mpeg_s
|
||||
{
|
||||
MP3_ERROR_NONE = 0x0000, // no error
|
||||
MP3_ERROR_BUFLEN = 0x0001, // input buffer too small (or EOF)
|
||||
MP3_ERROR_BUFPTR = 0x0002, // invalid (null) buffer pointer
|
||||
MP3_ERROR_NOMEM = 0x0031, // not enough memory
|
||||
MP3_ERROR_LOSTSYNC = 0x0101, // lost synchronization
|
||||
MP3_ERROR_BADLAYER = 0x0102, // reserved header layer value
|
||||
MP3_ERROR_BADBITRATE = 0x0103, // forbidden bitrate value
|
||||
MP3_ERROR_BADSAMPLERATE = 0x0104, // reserved sample frequency value
|
||||
MP3_ERROR_BADEMPHASIS = 0x0105, // reserved emphasis value
|
||||
MP3_ERROR_BADCRC = 0x0201, // CRC check failed
|
||||
MP3_ERROR_BADBITALLOC = 0x0211, // forbidden bit allocation value
|
||||
MP3_ERROR_BADSCALEFACTOR = 0x0221, // bad scalefactor index
|
||||
MP3_ERROR_BADMODE = 0x0222, // bad bitrate/mode combination
|
||||
MP3_ERROR_BADFRAMELEN = 0x0231, // bad frame length
|
||||
MP3_ERROR_BADBIGVALUES = 0x0232, // bad big_values count
|
||||
MP3_ERROR_BADBLOCKTYPE = 0x0233, // reserved block_type
|
||||
MP3_ERROR_BADSCFSI = 0x0234, // bad scalefactor selection info
|
||||
MP3_ERROR_BADDATAPTR = 0x0235, // bad main_data_begin pointer
|
||||
MP3_ERROR_BADPART3LEN = 0x0236, // bad audio data length
|
||||
MP3_ERROR_BADHUFFTABLE = 0x0237, // bad Huffman table select
|
||||
MP3_ERROR_BADHUFFDATA = 0x0238, // Huffman data overrun
|
||||
MP3_ERROR_BADSTEREO = 0x0239 // incompatible block_type for JS
|
||||
};
|
||||
void *state; // hidden decoder state
|
||||
void *vbrtag; // valid for VBR-encoded mpegs
|
||||
|
||||
enum
|
||||
{
|
||||
MODE_SINGLE_CHANNEL = 0, // single channel
|
||||
MODE_DUAL_CHANNEL, // dual channel
|
||||
MODE_JOINT_STEREO, // joint (MS/intensity) stereo
|
||||
MODE_STEREO // normal LR stereo
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint samplerate; // sampling frequency (Hz)
|
||||
word channels; // number of channels
|
||||
word length; // number of samples per channel
|
||||
int samples[2][1152]; // PCM output samples [ch][sample]
|
||||
} pcm_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int filter[2][2][2][16][8]; // polyphase filterbank outputs
|
||||
uint phase; // current processing phase
|
||||
pcm_t pcm; // PCM output
|
||||
} synth_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const byte *byte;
|
||||
word cache;
|
||||
word left;
|
||||
} bitptr_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
long seconds; // whole seconds
|
||||
dword fraction; // 1 / TIMER_RESOLUTION seconds
|
||||
} mp3_timer_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int layer; // audio layer (1, 2, or 3)
|
||||
int mode; // channel mode (see above)
|
||||
int mode_extension; // additional mode info
|
||||
int emphasis; // de-emphasis to use (see above)
|
||||
|
||||
dword bitrate; // stream bitrate (bps)
|
||||
uint samplerate; // sampling frequency (Hz)
|
||||
|
||||
word crc_check; // frame CRC accumulator
|
||||
word crc_target; // final target CRC checksum
|
||||
|
||||
int flags; // flags (see below)
|
||||
int private_bits; // private bits (see below)
|
||||
mp3_timer_t duration; // audio playing time of frame
|
||||
} mp3_header_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
mp3_header_t header; // MPEG audio header
|
||||
int options; // decoding options (from stream)
|
||||
|
||||
int sbsample[2][36][32]; // synthesis subband filter samples
|
||||
int (*overlap)[2][32][18]; // Layer III block overlap data
|
||||
} mp3_frame_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const byte *buffer; // input bitstream buffer
|
||||
const byte *bufend; // end of buffer
|
||||
dword skiplen; // bytes to skip before next frame
|
||||
|
||||
int sync; // stream sync found
|
||||
dword freerate; // free bitrate (fixed)
|
||||
|
||||
const byte *this_frame; // start of current frame
|
||||
const byte *next_frame; // start of next frame
|
||||
bitptr_t ptr; // current processing bit pointer
|
||||
|
||||
bitptr_t anc_ptr; // ancillary bits pointer
|
||||
uint anc_bitlen; // number of ancillary bits
|
||||
|
||||
byte (*data)[BUFFER_MDLEN];
|
||||
// Layer III data()
|
||||
uint md_len; // bytes in data
|
||||
|
||||
int options; // decoding options
|
||||
int error; // error code
|
||||
} mp3_stream_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
synth_t synth;
|
||||
mp3_stream_t stream;
|
||||
mp3_frame_t frame;
|
||||
int buffer_length; // for reading
|
||||
byte buffer[BUFFER_SIZE];// frame buffer
|
||||
} mpegfile_t;
|
||||
|
||||
// libmad exports
|
||||
extern void mad_synth_init( synth_t* );
|
||||
extern void mad_synth_frame( synth_t*, const mp3_frame_t* );
|
||||
extern void mad_stream_init( mp3_stream_t* );
|
||||
extern void mad_stream_buffer( mp3_stream_t*, const byte*, dword );
|
||||
extern void mad_stream_finish( mp3_stream_t* );
|
||||
extern void mad_frame_init( mp3_frame_t* );
|
||||
extern int mad_frame_decode( mp3_frame_t*, mp3_stream_t* );
|
||||
extern void mad_frame_finish( mp3_frame_t* );
|
||||
|
||||
|
||||
/*
|
||||
=================================================================
|
||||
|
||||
MPEG decompression
|
||||
|
||||
=================================================================
|
||||
*/
|
||||
static int mpeg_read( file_t *file, mpegfile_t *mpeg )
|
||||
{
|
||||
int ret;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
ret = FS_Read( file, &mpeg->buffer[mpeg->buffer_length], BUFFER_SIZE - mpeg->buffer_length );
|
||||
|
||||
// no more bytes are left
|
||||
if( ret <= 0 ) break;
|
||||
|
||||
mpeg->buffer_length += ret;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
mad_stream_buffer( &mpeg->stream, mpeg->buffer, mpeg->buffer_length );
|
||||
ret = mad_frame_decode( &mpeg->frame, &mpeg->stream );
|
||||
|
||||
if( mpeg->stream.next_frame )
|
||||
{
|
||||
int length;
|
||||
|
||||
length = mpeg->buffer + mpeg->buffer_length - mpeg->stream.next_frame;
|
||||
memmove( mpeg->buffer, mpeg->stream.next_frame, length );
|
||||
mpeg->buffer_length = length;
|
||||
}
|
||||
|
||||
if( !ret ) return 1;
|
||||
if( mpeg->stream.error == MP3_ERROR_BUFLEN )
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpeg_read_mem( const byte *buffer, int *pos, size_t filesize, mpegfile_t *mpeg )
|
||||
{
|
||||
int ret, readSize;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
readSize = ( BUFFER_SIZE - mpeg->buffer_length );
|
||||
|
||||
if(( *pos + readSize ) > filesize )
|
||||
readSize = ( filesize - *pos );
|
||||
Q_memcpy( &mpeg->buffer[mpeg->buffer_length], buffer + *pos, readSize );
|
||||
|
||||
// no more bytes are left
|
||||
if( readSize <= 0 ) break;
|
||||
*pos += readSize;
|
||||
mpeg->buffer_length += readSize;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
mad_stream_buffer( &mpeg->stream, mpeg->buffer, mpeg->buffer_length );
|
||||
ret = mad_frame_decode( &mpeg->frame, &mpeg->stream );
|
||||
|
||||
if( mpeg->stream.next_frame )
|
||||
{
|
||||
int length;
|
||||
|
||||
length = mpeg->buffer + mpeg->buffer_length - mpeg->stream.next_frame;
|
||||
memmove( mpeg->buffer, mpeg->stream.next_frame, length );
|
||||
mpeg->buffer_length = length;
|
||||
}
|
||||
|
||||
if( !ret ) return 1;
|
||||
if( mpeg->stream.error == MP3_ERROR_BUFLEN )
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpeg_scale( int sample )
|
||||
{
|
||||
sample += (1 << ( MPEG_F_FRACBITS - 16 ));
|
||||
|
||||
if( sample >= MPEG_F_ONE ) sample = MPEG_F_ONE - 1;
|
||||
else if( sample < -MPEG_F_ONE ) sample = -MPEG_F_ONE;
|
||||
|
||||
return sample >> ( MPEG_F_FRACBITS + 1 - 16 );
|
||||
}
|
||||
|
||||
static int mpeg_size( mp3_frame_t *frame, long bytes )
|
||||
{
|
||||
return bytes * 8 / frame->header.bitrate * sound.channels * sound.rate * sound.width;
|
||||
}
|
||||
int channels; // num channels
|
||||
int samples; // per one second
|
||||
int play_time;// stream size in milliseconds
|
||||
int rate; // frequency
|
||||
int outsize; // current data size
|
||||
char out[8192];// temporary buffer
|
||||
} mpeg_t;
|
||||
|
||||
// mpg123 exports
|
||||
int create_decoder( mpeg_t *mpg );
|
||||
int read_mpeg_header( mpeg_t *mpg, const char *data, long bufsize, long streamsize );
|
||||
int read_mpeg_stream( mpeg_t *mpg, const char *data, long bufsize );
|
||||
void close_decoder( mpeg_t *mpg );
|
||||
|
||||
/*
|
||||
=================================================================
|
||||
|
@ -267,39 +54,38 @@ static int mpeg_size( mp3_frame_t *frame, long bytes )
|
|||
*/
|
||||
qboolean Sound_LoadMPG( const char *name, const byte *buffer, size_t filesize )
|
||||
{
|
||||
mpegfile_t mpeg;
|
||||
size_t pos = 0;
|
||||
size_t bytesWrite = 0;
|
||||
mpeg_t mpeg;
|
||||
size_t pos = 0;
|
||||
size_t bytesWrite = 0;
|
||||
|
||||
// load the file
|
||||
if( !buffer || filesize <= 0 )
|
||||
if( !buffer || filesize < FRAME_SIZE )
|
||||
return false;
|
||||
|
||||
Q_memset( &mpeg, 0, sizeof( mpeg ));
|
||||
mad_synth_init( &mpeg.synth );
|
||||
mad_stream_init( &mpeg.stream );
|
||||
mad_frame_init( &mpeg.frame );
|
||||
// couldn't create decoder
|
||||
if( !create_decoder( &mpeg ))
|
||||
return false;
|
||||
|
||||
if( mpeg_read_mem( buffer, &pos, filesize, &mpeg ) == 0 )
|
||||
// trying to read header
|
||||
if( !read_mpeg_header( &mpeg, buffer, FRAME_SIZE, filesize ))
|
||||
{
|
||||
MsgDev( D_ERROR, "Sound_LoadMPG: (%s) is probably corrupted\n", name );
|
||||
mad_stream_finish( &mpeg.stream );
|
||||
mad_frame_finish( &mpeg.frame );
|
||||
close_decoder( &mpeg );
|
||||
return false;
|
||||
}
|
||||
|
||||
sound.channels = ( mpeg.frame.header.mode == MODE_SINGLE_CHANNEL ) ? 1 : 2;
|
||||
sound.rate = mpeg.frame.header.samplerate;
|
||||
sound.channels = mpeg.channels;
|
||||
sound.rate = mpeg.rate;
|
||||
sound.width = 2; // always 16-bit PCM
|
||||
sound.loopstart = -1;
|
||||
sound.size = mpeg_size( &mpeg.frame, filesize );
|
||||
sound.size = ( sound.channels * sound.rate * sound.width ) * ( mpeg.play_time / 1000 ); // in bytes
|
||||
pos += FRAME_SIZE; // evaluate pos
|
||||
|
||||
if( !sound.size )
|
||||
{
|
||||
// bad ogg file
|
||||
// bad mpeg file ?
|
||||
MsgDev( D_ERROR, "Sound_LoadMPG: (%s) is probably corrupted\n", name );
|
||||
mad_stream_finish( &mpeg.stream );
|
||||
mad_frame_finish( &mpeg.frame );
|
||||
close_decoder( &mpeg );
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -309,35 +95,36 @@ qboolean Sound_LoadMPG( const char *name, const byte *buffer, size_t filesize )
|
|||
// decompress mpg into pcm wav format
|
||||
while( bytesWrite < sound.size )
|
||||
{
|
||||
word *data;
|
||||
int i;
|
||||
int outsize;
|
||||
|
||||
mad_synth_frame( &mpeg.synth, &mpeg.frame );
|
||||
data = (short *)(sound.wav + bytesWrite);
|
||||
|
||||
for( i = 0; i < mpeg.synth.pcm.length; i++ )
|
||||
if( read_mpeg_stream( &mpeg, NULL, 0 ) != MP3_OK )
|
||||
{
|
||||
if( sound.channels == 2 )
|
||||
{
|
||||
*data++ = mpeg_scale( mpeg.synth.pcm.samples[0][i] );
|
||||
*data++ = mpeg_scale( mpeg.synth.pcm.samples[1][i] );
|
||||
}
|
||||
else
|
||||
{
|
||||
*data++ = mpeg_scale( mpeg.synth.pcm.samples[0][i] );
|
||||
}
|
||||
char *data = (char *)buffer + pos;
|
||||
int bufsize;
|
||||
|
||||
bytesWrite += ( sound.width * sound.channels );
|
||||
if( bytesWrite >= sound.size ) break;
|
||||
// if there are no bytes remainig so we can decompress the new frame
|
||||
if( pos + FRAME_SIZE > filesize )
|
||||
bufsize = ( filesize - pos );
|
||||
else bufsize = FRAME_SIZE;
|
||||
pos += bufsize;
|
||||
|
||||
if( read_mpeg_stream( &mpeg, data, bufsize ) != MP3_OK )
|
||||
break; // there was end of the stream
|
||||
}
|
||||
|
||||
if( !mpeg_read_mem( buffer, &pos, filesize, &mpeg ))
|
||||
break;
|
||||
if( bytesWrite + mpeg.outsize > sound.size )
|
||||
{
|
||||
outsize = ( sound.size - bytesWrite );
|
||||
Msg( "merge size from %i, to %i\n", mpeg.outsize, outsize );
|
||||
}
|
||||
else outsize = mpeg.outsize;
|
||||
|
||||
Q_memcpy( &sound.wav[bytesWrite], mpeg.out, outsize );
|
||||
bytesWrite += outsize;
|
||||
}
|
||||
|
||||
sound.samples = bytesWrite / ( sound.width * sound.channels );
|
||||
mad_stream_finish( &mpeg.stream );
|
||||
mad_frame_finish( &mpeg.frame );
|
||||
close_decoder( &mpeg );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -349,28 +136,55 @@ Stream_OpenMPG
|
|||
*/
|
||||
stream_t *Stream_OpenMPG( const char *filename )
|
||||
{
|
||||
mpegfile_t *mpegFile;
|
||||
stream_t *stream;
|
||||
file_t *file;
|
||||
mpeg_t *mpegFile;
|
||||
stream_t *stream;
|
||||
file_t *file;
|
||||
long filesize, read_len;
|
||||
char tempbuff[FRAME_SIZE];
|
||||
|
||||
file = FS_Open( filename, "rb", false );
|
||||
if( !file ) return NULL;
|
||||
|
||||
filesize = FS_FileLength( file );
|
||||
if( filesize < FRAME_SIZE )
|
||||
{
|
||||
MsgDev( D_ERROR, "Stream_OpenMPG: %s is probably corrupted\n", filename );
|
||||
FS_Close( file );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// at this point we have valid stream
|
||||
stream = Mem_Alloc( host.soundpool, sizeof( stream_t ));
|
||||
stream->file = file;
|
||||
|
||||
mpegFile = Mem_Alloc( host.soundpool, sizeof( mpegfile_t ));
|
||||
mpegFile = Mem_Alloc( host.soundpool, sizeof( mpeg_t ));
|
||||
|
||||
mad_synth_init( &mpegFile->synth );
|
||||
mad_stream_init( &mpegFile->stream );
|
||||
mad_frame_init( &mpegFile->frame );
|
||||
|
||||
if( mpeg_read( file, mpegFile ) == 0 )
|
||||
// couldn't create decoder
|
||||
if( !create_decoder( mpegFile ))
|
||||
{
|
||||
MsgDev( D_ERROR, "Stream_OpenMPG: couldn't open %s\n", filename );
|
||||
mad_stream_finish( &mpegFile->stream );
|
||||
mad_frame_finish( &mpegFile->frame );
|
||||
MsgDev( D_ERROR, "Stream_OpenMPG: couldn't create decoder\n" );
|
||||
Mem_Free( mpegFile );
|
||||
Mem_Free( stream );
|
||||
FS_Close( file );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
read_len = FS_Read( file, tempbuff, sizeof( tempbuff ));
|
||||
if( read_len < sizeof( tempbuff ))
|
||||
{
|
||||
MsgDev( D_ERROR, "Stream_OpenMPG: %s is probably corrupted\n", filename );
|
||||
close_decoder( mpegFile );
|
||||
Mem_Free( mpegFile );
|
||||
Mem_Free( stream );
|
||||
FS_Close( file );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// trying to read header
|
||||
if( !read_mpeg_header( mpegFile, tempbuff, sizeof( tempbuff ), filesize ))
|
||||
{
|
||||
MsgDev( D_ERROR, "Sound_LoadMPG: (%s) is probably corrupted\n", filename );
|
||||
close_decoder( mpegFile );
|
||||
Mem_Free( mpegFile );
|
||||
Mem_Free( stream );
|
||||
FS_Close( file );
|
||||
|
@ -378,19 +192,12 @@ stream_t *Stream_OpenMPG( const char *filename )
|
|||
}
|
||||
|
||||
stream->pos = 0; // how many samples left from previous frame
|
||||
stream->channels = ( mpegFile->frame.header.mode == MODE_SINGLE_CHANNEL ) ? 1 : 2;
|
||||
stream->rate = mpegFile->frame.header.samplerate;
|
||||
stream->channels = mpegFile->channels;
|
||||
stream->rate = mpegFile->rate;
|
||||
stream->width = 2; // always 16 bit
|
||||
stream->ptr = mpegFile;
|
||||
stream->type = WF_MPGDATA;
|
||||
|
||||
// g-cont: there is a stupid way...
|
||||
if( stream->rate > 44100 )
|
||||
{
|
||||
mpegFile->stream.options = 0x0002;
|
||||
stream->rate /= 2;
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
@ -401,52 +208,49 @@ Stream_ReadMPG
|
|||
assume stream is valid
|
||||
=================
|
||||
*/
|
||||
long Stream_ReadMPG( stream_t *stream, long bytes, void *buffer )
|
||||
long Stream_ReadMPG( stream_t *stream, long needBytes, void *buffer )
|
||||
{
|
||||
// buffer handling
|
||||
int bytesRead = 0;
|
||||
mpegfile_t *mpg;
|
||||
int bytesWritten = 0;
|
||||
mpeg_t *mpg;
|
||||
|
||||
mpg = (mpegfile_t *)stream->ptr;
|
||||
mpg = (mpeg_t *)stream->ptr;
|
||||
ASSERT( mpg != NULL );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
pcm_t *wav;
|
||||
word *data;
|
||||
int i;
|
||||
char tempbuff[FRAME_SIZE];
|
||||
long read_len, outsize;
|
||||
byte *data;
|
||||
|
||||
if( !stream->pos )
|
||||
{
|
||||
// if there are no bytes remainig so we can synth new frame
|
||||
mad_synth_frame( &mpg->synth, &mpg->frame );
|
||||
}
|
||||
wav = &mpg->synth.pcm;
|
||||
data = (word *)((byte *)buffer + bytesRead);
|
||||
|
||||
for( i = stream->pos; i < wav->length; i++ )
|
||||
{
|
||||
if( stream->channels == 2 )
|
||||
if( read_mpeg_stream( mpg, NULL, 0 ) != MP3_OK )
|
||||
{
|
||||
*data++ = mpeg_scale( wav->samples[0][i] );
|
||||
*data++ = mpeg_scale( wav->samples[1][i] );
|
||||
}
|
||||
else
|
||||
{
|
||||
*data++ = mpeg_scale( wav->samples[0][i] );
|
||||
}
|
||||
bytesRead += ( stream->width * stream->channels );
|
||||
|
||||
if( bytesRead >= bytes )
|
||||
{
|
||||
// continue from this sample on a next call
|
||||
stream->pos = i;
|
||||
return bytesRead;
|
||||
// if there are no bytes remainig so we can decompress the new frame
|
||||
read_len = FS_Read( stream->file, tempbuff, sizeof( tempbuff ));
|
||||
if( read_mpeg_stream( mpg, tempbuff, read_len ) != MP3_OK )
|
||||
break; // there was end of the stream
|
||||
}
|
||||
}
|
||||
|
||||
stream->pos = 0; // no bytes remainig
|
||||
if( !mpeg_read( stream->file, mpg )) break;
|
||||
// check remaining size
|
||||
if( bytesWritten + mpg->outsize > needBytes )
|
||||
outsize = ( needBytes - bytesWritten );
|
||||
else outsize = mpg->outsize;
|
||||
|
||||
// copy raw sample to output buffer
|
||||
data = (byte *)buffer + bytesWritten;
|
||||
Q_memcpy( data, &mpg->out[stream->pos], outsize );
|
||||
bytesWritten += outsize;
|
||||
mpg->outsize -= outsize;
|
||||
stream->pos += outsize;
|
||||
|
||||
// continue from this sample on a next call
|
||||
if( bytesWritten >= needBytes )
|
||||
return bytesWritten;
|
||||
|
||||
stream->pos = 0; // no bytes remaining
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -462,12 +266,10 @@ void Stream_FreeMPG( stream_t *stream )
|
|||
{
|
||||
if( stream->ptr )
|
||||
{
|
||||
mpegfile_t *mpg;
|
||||
mpeg_t *mpg;
|
||||
|
||||
mpg = (mpegfile_t *)stream->ptr;
|
||||
|
||||
mad_stream_finish( &mpg->stream );
|
||||
mad_frame_finish( &mpg->frame );
|
||||
mpg = (mpeg_t *)stream->ptr;
|
||||
close_decoder( mpg );
|
||||
Mem_Free( stream->ptr );
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,480 @@
|
|||
/*
|
||||
snd_mp3.c - mp3 format loading and streaming
|
||||
Copyright (C) 2010 Uncle Mike
|
||||
|
||||
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 3 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.
|
||||
*/
|
||||
|
||||
#include "soundlib.h"
|
||||
|
||||
/*
|
||||
=======================================================================
|
||||
LIBMAD DEFINITION
|
||||
=======================================================================
|
||||
*/
|
||||
#define BUFFER_GUARD 8
|
||||
#define BUFFER_MDLEN (511 + 2048 + BUFFER_GUARD)
|
||||
#define BUFFER_SIZE 4096 // must be large than BUFFER_MDLEN
|
||||
|
||||
#define MPEG_F_FRACBITS 28
|
||||
#define MPEG_F( x ) ((int)( x##L ))
|
||||
#define MPEG_F_ONE MPEG_F( 0x10000000 )
|
||||
|
||||
enum
|
||||
{
|
||||
MP3_ERROR_NONE = 0x0000, // no error
|
||||
MP3_ERROR_BUFLEN = 0x0001, // input buffer too small (or EOF)
|
||||
MP3_ERROR_BUFPTR = 0x0002, // invalid (null) buffer pointer
|
||||
MP3_ERROR_NOMEM = 0x0031, // not enough memory
|
||||
MP3_ERROR_LOSTSYNC = 0x0101, // lost synchronization
|
||||
MP3_ERROR_BADLAYER = 0x0102, // reserved header layer value
|
||||
MP3_ERROR_BADBITRATE = 0x0103, // forbidden bitrate value
|
||||
MP3_ERROR_BADSAMPLERATE = 0x0104, // reserved sample frequency value
|
||||
MP3_ERROR_BADEMPHASIS = 0x0105, // reserved emphasis value
|
||||
MP3_ERROR_BADCRC = 0x0201, // CRC check failed
|
||||
MP3_ERROR_BADBITALLOC = 0x0211, // forbidden bit allocation value
|
||||
MP3_ERROR_BADSCALEFACTOR = 0x0221, // bad scalefactor index
|
||||
MP3_ERROR_BADMODE = 0x0222, // bad bitrate/mode combination
|
||||
MP3_ERROR_BADFRAMELEN = 0x0231, // bad frame length
|
||||
MP3_ERROR_BADBIGVALUES = 0x0232, // bad big_values count
|
||||
MP3_ERROR_BADBLOCKTYPE = 0x0233, // reserved block_type
|
||||
MP3_ERROR_BADSCFSI = 0x0234, // bad scalefactor selection info
|
||||
MP3_ERROR_BADDATAPTR = 0x0235, // bad main_data_begin pointer
|
||||
MP3_ERROR_BADPART3LEN = 0x0236, // bad audio data length
|
||||
MP3_ERROR_BADHUFFTABLE = 0x0237, // bad Huffman table select
|
||||
MP3_ERROR_BADHUFFDATA = 0x0238, // Huffman data overrun
|
||||
MP3_ERROR_BADSTEREO = 0x0239 // incompatible block_type for JS
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
MODE_SINGLE_CHANNEL = 0, // single channel
|
||||
MODE_DUAL_CHANNEL, // dual channel
|
||||
MODE_JOINT_STEREO, // joint (MS/intensity) stereo
|
||||
MODE_STEREO // normal LR stereo
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint samplerate; // sampling frequency (Hz)
|
||||
word channels; // number of channels
|
||||
word length; // number of samples per channel
|
||||
int samples[2][1152]; // PCM output samples [ch][sample]
|
||||
} pcm_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int filter[2][2][2][16][8]; // polyphase filterbank outputs
|
||||
uint phase; // current processing phase
|
||||
pcm_t pcm; // PCM output
|
||||
} synth_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const byte *byte;
|
||||
word cache;
|
||||
word left;
|
||||
} bitptr_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
long seconds; // whole seconds
|
||||
dword fraction; // 1 / TIMER_RESOLUTION seconds
|
||||
} mp3_timer_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int layer; // audio layer (1, 2, or 3)
|
||||
int mode; // channel mode (see above)
|
||||
int mode_extension; // additional mode info
|
||||
int emphasis; // de-emphasis to use (see above)
|
||||
|
||||
dword bitrate; // stream bitrate (bps)
|
||||
uint samplerate; // sampling frequency (Hz)
|
||||
|
||||
word crc_check; // frame CRC accumulator
|
||||
word crc_target; // final target CRC checksum
|
||||
|
||||
int flags; // flags (see below)
|
||||
int private_bits; // private bits (see below)
|
||||
mp3_timer_t duration; // audio playing time of frame
|
||||
} mp3_header_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
mp3_header_t header; // MPEG audio header
|
||||
int options; // decoding options (from stream)
|
||||
|
||||
int sbsample[2][36][32]; // synthesis subband filter samples
|
||||
int (*overlap)[2][32][18]; // Layer III block overlap data
|
||||
} mp3_frame_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const byte *buffer; // input bitstream buffer
|
||||
const byte *bufend; // end of buffer
|
||||
dword skiplen; // bytes to skip before next frame
|
||||
|
||||
int sync; // stream sync found
|
||||
dword freerate; // free bitrate (fixed)
|
||||
|
||||
const byte *this_frame; // start of current frame
|
||||
const byte *next_frame; // start of next frame
|
||||
bitptr_t ptr; // current processing bit pointer
|
||||
|
||||
bitptr_t anc_ptr; // ancillary bits pointer
|
||||
uint anc_bitlen; // number of ancillary bits
|
||||
|
||||
byte (*data)[BUFFER_MDLEN];
|
||||
// Layer III data()
|
||||
uint md_len; // bytes in data
|
||||
|
||||
int options; // decoding options
|
||||
int error; // error code
|
||||
} mp3_stream_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
synth_t synth;
|
||||
mp3_stream_t stream;
|
||||
mp3_frame_t frame;
|
||||
int buffer_length; // for reading
|
||||
byte buffer[BUFFER_SIZE];// frame buffer
|
||||
} mpegfile_t;
|
||||
|
||||
// libmad exports
|
||||
extern void mad_synth_init( synth_t* );
|
||||
extern void mad_synth_frame( synth_t*, const mp3_frame_t* );
|
||||
extern void mad_stream_init( mp3_stream_t* );
|
||||
extern void mad_stream_buffer( mp3_stream_t*, const byte*, dword );
|
||||
extern void mad_stream_finish( mp3_stream_t* );
|
||||
extern void mad_frame_init( mp3_frame_t* );
|
||||
extern int mad_frame_decode( mp3_frame_t*, mp3_stream_t* );
|
||||
extern void mad_frame_finish( mp3_frame_t* );
|
||||
|
||||
|
||||
/*
|
||||
=================================================================
|
||||
|
||||
MPEG decompression
|
||||
|
||||
=================================================================
|
||||
*/
|
||||
static int mpeg_read( file_t *file, mpegfile_t *mpeg )
|
||||
{
|
||||
int ret;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
ret = FS_Read( file, &mpeg->buffer[mpeg->buffer_length], BUFFER_SIZE - mpeg->buffer_length );
|
||||
|
||||
// no more bytes are left
|
||||
if( ret <= 0 ) break;
|
||||
|
||||
mpeg->buffer_length += ret;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
mad_stream_buffer( &mpeg->stream, mpeg->buffer, mpeg->buffer_length );
|
||||
ret = mad_frame_decode( &mpeg->frame, &mpeg->stream );
|
||||
|
||||
if( mpeg->stream.next_frame )
|
||||
{
|
||||
int length;
|
||||
|
||||
length = mpeg->buffer + mpeg->buffer_length - mpeg->stream.next_frame;
|
||||
memmove( mpeg->buffer, mpeg->stream.next_frame, length );
|
||||
mpeg->buffer_length = length;
|
||||
}
|
||||
|
||||
if( !ret ) return 1;
|
||||
if( mpeg->stream.error == MP3_ERROR_BUFLEN )
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpeg_read_mem( const byte *buffer, int *pos, size_t filesize, mpegfile_t *mpeg )
|
||||
{
|
||||
int ret, readSize;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
readSize = ( BUFFER_SIZE - mpeg->buffer_length );
|
||||
|
||||
if(( *pos + readSize ) > filesize )
|
||||
readSize = ( filesize - *pos );
|
||||
Q_memcpy( &mpeg->buffer[mpeg->buffer_length], buffer + *pos, readSize );
|
||||
|
||||
// no more bytes are left
|
||||
if( readSize <= 0 ) break;
|
||||
*pos += readSize;
|
||||
mpeg->buffer_length += readSize;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
mad_stream_buffer( &mpeg->stream, mpeg->buffer, mpeg->buffer_length );
|
||||
ret = mad_frame_decode( &mpeg->frame, &mpeg->stream );
|
||||
|
||||
if( mpeg->stream.next_frame )
|
||||
{
|
||||
int length;
|
||||
|
||||
length = mpeg->buffer + mpeg->buffer_length - mpeg->stream.next_frame;
|
||||
memmove( mpeg->buffer, mpeg->stream.next_frame, length );
|
||||
mpeg->buffer_length = length;
|
||||
}
|
||||
|
||||
if( !ret ) return 1;
|
||||
if( mpeg->stream.error == MP3_ERROR_BUFLEN )
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpeg_scale( int sample )
|
||||
{
|
||||
sample += (1 << ( MPEG_F_FRACBITS - 16 ));
|
||||
|
||||
if( sample >= MPEG_F_ONE ) sample = MPEG_F_ONE - 1;
|
||||
else if( sample < -MPEG_F_ONE ) sample = -MPEG_F_ONE;
|
||||
|
||||
return sample >> ( MPEG_F_FRACBITS + 1 - 16 );
|
||||
}
|
||||
|
||||
static int mpeg_size( mp3_frame_t *frame, long bytes )
|
||||
{
|
||||
return bytes * 8 / frame->header.bitrate * sound.channels * sound.rate * sound.width;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================================================================
|
||||
|
||||
MPEG decompression
|
||||
|
||||
=================================================================
|
||||
*/
|
||||
qboolean Sound_LoadMPG( const char *name, const byte *buffer, size_t filesize )
|
||||
{
|
||||
mpegfile_t mpeg;
|
||||
size_t pos = 0;
|
||||
size_t bytesWrite = 0;
|
||||
|
||||
// load the file
|
||||
if( !buffer || filesize <= 0 )
|
||||
return false;
|
||||
|
||||
Q_memset( &mpeg, 0, sizeof( mpeg ));
|
||||
mad_synth_init( &mpeg.synth );
|
||||
mad_stream_init( &mpeg.stream );
|
||||
mad_frame_init( &mpeg.frame );
|
||||
|
||||
if( mpeg_read_mem( buffer, &pos, filesize, &mpeg ) == 0 )
|
||||
{
|
||||
MsgDev( D_ERROR, "Sound_LoadMPG: (%s) is probably corrupted\n", name );
|
||||
mad_stream_finish( &mpeg.stream );
|
||||
mad_frame_finish( &mpeg.frame );
|
||||
return false;
|
||||
}
|
||||
|
||||
sound.channels = ( mpeg.frame.header.mode == MODE_SINGLE_CHANNEL ) ? 1 : 2;
|
||||
sound.rate = mpeg.frame.header.samplerate;
|
||||
sound.width = 2; // always 16-bit PCM
|
||||
sound.loopstart = -1;
|
||||
sound.size = mpeg_size( &mpeg.frame, filesize );
|
||||
|
||||
if( !sound.size )
|
||||
{
|
||||
// bad ogg file
|
||||
MsgDev( D_ERROR, "Sound_LoadMPG: (%s) is probably corrupted\n", name );
|
||||
mad_stream_finish( &mpeg.stream );
|
||||
mad_frame_finish( &mpeg.frame );
|
||||
return false;
|
||||
}
|
||||
|
||||
sound.type = WF_PCMDATA;
|
||||
sound.wav = (byte *)Mem_Alloc( host.soundpool, sound.size );
|
||||
|
||||
// decompress mpg into pcm wav format
|
||||
while( bytesWrite < sound.size )
|
||||
{
|
||||
word *data;
|
||||
int i;
|
||||
|
||||
mad_synth_frame( &mpeg.synth, &mpeg.frame );
|
||||
data = (short *)(sound.wav + bytesWrite);
|
||||
|
||||
for( i = 0; i < mpeg.synth.pcm.length; i++ )
|
||||
{
|
||||
if( sound.channels == 2 )
|
||||
{
|
||||
*data++ = mpeg_scale( mpeg.synth.pcm.samples[0][i] );
|
||||
*data++ = mpeg_scale( mpeg.synth.pcm.samples[1][i] );
|
||||
}
|
||||
else
|
||||
{
|
||||
*data++ = mpeg_scale( mpeg.synth.pcm.samples[0][i] );
|
||||
}
|
||||
|
||||
bytesWrite += ( sound.width * sound.channels );
|
||||
if( bytesWrite >= sound.size ) break;
|
||||
}
|
||||
|
||||
if( !mpeg_read_mem( buffer, &pos, filesize, &mpeg ))
|
||||
break;
|
||||
}
|
||||
|
||||
sound.samples = bytesWrite / ( sound.width * sound.channels );
|
||||
mad_stream_finish( &mpeg.stream );
|
||||
mad_frame_finish( &mpeg.frame );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Stream_OpenMPG
|
||||
=================
|
||||
*/
|
||||
stream_t *Stream_OpenMPG( const char *filename )
|
||||
{
|
||||
mpegfile_t *mpegFile;
|
||||
stream_t *stream;
|
||||
file_t *file;
|
||||
|
||||
file = FS_Open( filename, "rb", false );
|
||||
if( !file ) return NULL;
|
||||
|
||||
// at this point we have valid stream
|
||||
stream = Mem_Alloc( host.soundpool, sizeof( stream_t ));
|
||||
stream->file = file;
|
||||
|
||||
mpegFile = Mem_Alloc( host.soundpool, sizeof( mpegfile_t ));
|
||||
|
||||
mad_synth_init( &mpegFile->synth );
|
||||
mad_stream_init( &mpegFile->stream );
|
||||
mad_frame_init( &mpegFile->frame );
|
||||
|
||||
if( mpeg_read( file, mpegFile ) == 0 )
|
||||
{
|
||||
MsgDev( D_ERROR, "Stream_OpenMPG: couldn't open %s\n", filename );
|
||||
mad_stream_finish( &mpegFile->stream );
|
||||
mad_frame_finish( &mpegFile->frame );
|
||||
Mem_Free( mpegFile );
|
||||
Mem_Free( stream );
|
||||
FS_Close( file );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stream->pos = 0; // how many samples left from previous frame
|
||||
stream->channels = ( mpegFile->frame.header.mode == MODE_SINGLE_CHANNEL ) ? 1 : 2;
|
||||
stream->rate = mpegFile->frame.header.samplerate;
|
||||
stream->width = 2; // always 16 bit
|
||||
stream->ptr = mpegFile;
|
||||
stream->type = WF_MPGDATA;
|
||||
|
||||
// g-cont: there is a stupid way...
|
||||
if( stream->rate > 44100 )
|
||||
{
|
||||
mpegFile->stream.options = 0x0002;
|
||||
stream->rate /= 2;
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Stream_ReadMPG
|
||||
|
||||
assume stream is valid
|
||||
=================
|
||||
*/
|
||||
long Stream_ReadMPG( stream_t *stream, long bytes, void *buffer )
|
||||
{
|
||||
// buffer handling
|
||||
int bytesRead = 0;
|
||||
mpegfile_t *mpg;
|
||||
|
||||
mpg = (mpegfile_t *)stream->ptr;
|
||||
ASSERT( mpg != NULL );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
pcm_t *wav;
|
||||
word *data;
|
||||
int i;
|
||||
|
||||
if( !stream->pos )
|
||||
{
|
||||
// if there are no bytes remainig so we can synth new frame
|
||||
mad_synth_frame( &mpg->synth, &mpg->frame );
|
||||
}
|
||||
wav = &mpg->synth.pcm;
|
||||
data = (word *)((byte *)buffer + bytesRead);
|
||||
|
||||
for( i = stream->pos; i < wav->length; i++ )
|
||||
{
|
||||
if( stream->channels == 2 )
|
||||
{
|
||||
*data++ = mpeg_scale( wav->samples[0][i] );
|
||||
*data++ = mpeg_scale( wav->samples[1][i] );
|
||||
}
|
||||
else
|
||||
{
|
||||
*data++ = mpeg_scale( wav->samples[0][i] );
|
||||
}
|
||||
bytesRead += ( stream->width * stream->channels );
|
||||
|
||||
if( bytesRead >= bytes )
|
||||
{
|
||||
// continue from this sample on a next call
|
||||
stream->pos = i;
|
||||
return bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
stream->pos = 0; // no bytes remainig
|
||||
if( !mpeg_read( stream->file, mpg )) break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Stream_FreeMPG
|
||||
|
||||
assume stream is valid
|
||||
=================
|
||||
*/
|
||||
void Stream_FreeMPG( stream_t *stream )
|
||||
{
|
||||
if( stream->ptr )
|
||||
{
|
||||
mpegfile_t *mpg;
|
||||
|
||||
mpg = (mpegfile_t *)stream->ptr;
|
||||
|
||||
mad_stream_finish( &mpg->stream );
|
||||
mad_frame_finish( &mpg->frame );
|
||||
Mem_Free( stream->ptr );
|
||||
}
|
||||
|
||||
if( stream->file )
|
||||
{
|
||||
FS_Close( stream->file );
|
||||
}
|
||||
|
||||
Mem_Free( stream );
|
||||
}
|
|
@ -146,7 +146,7 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, size_t filesize )
|
|||
iff_data = buffer;
|
||||
iff_end = buffer + filesize;
|
||||
|
||||
// dind "RIFF" chunk
|
||||
// find "RIFF" chunk
|
||||
FindChunk( "RIFF" );
|
||||
if( !( iff_dataPtr && !Q_strncmp( iff_dataPtr + 8, "WAVE", 4 )))
|
||||
{
|
||||
|
|
|
@ -259,6 +259,20 @@ typedef struct enginefuncs_s
|
|||
qboolean (*pfnVoice_SetClientListening)(int iReceiver, int iSender, qboolean bListen);
|
||||
|
||||
const char *(*pfnGetPlayerAuthId) ( edict_t *e );
|
||||
|
||||
void *(*pfnSequenceGet)( const char *fileName, const char *entryName );
|
||||
void *(*pfnSequencePickSentence)( const char *groupName, int pickMethod, int *picked );
|
||||
int (*pfnGetFileSize)( char *filename );
|
||||
unsigned int (*pfnGetApproxWavePlayLen)( const char *filepath );
|
||||
int (*pfnIsCareerMatch)( void );
|
||||
int (*pfnGetLocalizedStringLength)( const char *label );
|
||||
void (*pfnRegisterTutorMessageShown)( int mid );
|
||||
int (*pfnGetTimesTutorMessageShown)( int mid );
|
||||
void (*pfnProcessTutorMessageDecayBuffer)( int *buffer, int bufferLength );
|
||||
void (*pfnConstructTutorMessageDecayBuffer)( int *buffer, int bufferLength );
|
||||
void (*pfnResetTutorMessageDecayData)( void );
|
||||
void (*pfnQueryClientCvarValue)( const edict_t *player, const char *cvarName );
|
||||
void (*pfnQueryClientCvarValue2)( const edict_t *player, const char *cvarName, int requestID );
|
||||
} enginefuncs_t;
|
||||
// ONLY ADD NEW FUNCTIONS TO THE END OF THIS STRUCT. INTERFACE VERSION IS FROZEN AT 138
|
||||
|
||||
|
@ -476,8 +490,8 @@ typedef struct
|
|||
void (*pfnOnFreeEntPrivateData)( edict_t *pEnt );
|
||||
void (*pfnGameShutdown)(void);
|
||||
int (*pfnShouldCollide)( edict_t *pentTouched, edict_t *pentOther );
|
||||
int (*pfnCreate)( edict_t *pent, const char *szName ); // passed through pfnCreate (0 is attempt to create, -1 is reject)
|
||||
int (*pfnPhysicsEntity)( edict_t *pEntity ); // run custom physics for each entity (return 0 to use engine physic)
|
||||
void (*pfnCvarValue)( const edict_t *pEnt, const char *value );
|
||||
void (*pfnCvarValue2)( const edict_t *pEnt, int requestID, const char *cvarName, const char *value );
|
||||
} NEW_DLL_FUNCTIONS;
|
||||
typedef int (*NEW_DLL_FUNCTIONS_FN)( NEW_DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion );
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
physint.h - Server Physics Interface
|
||||
Copyright (C) 2011 Uncle Mike
|
||||
|
||||
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 3 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.
|
||||
*/
|
||||
|
||||
#ifndef PHYSINT_H
|
||||
#define PHYSINT_H
|
||||
|
||||
#define SV_PHYSICS_INTERFACE_VERSION 1
|
||||
|
||||
typedef struct server_physics_api_s
|
||||
{
|
||||
// unlink edict from old position and link onto new
|
||||
void ( *pfnLinkEdict) ( edict_t *ent, qboolean touch_triggers );
|
||||
double ( *pfnGetServerTime )( void ); // unclamped
|
||||
} server_physics_api_t;
|
||||
|
||||
// physic callbacks
|
||||
typedef struct physics_interface_s
|
||||
{
|
||||
int version;
|
||||
// passed through pfnCreate (0 is attempt to create, -1 is reject)
|
||||
int ( *SV_CreateEntity )( edict_t *pent, const char *szName );
|
||||
// run custom physics for each entity (return 0 to use built-in engine physic)
|
||||
int ( *SV_PhysicsEntity )( edict_t *pEntity );
|
||||
} physics_interface_t;
|
||||
|
||||
#endif//PHYSINT_H
|
|
@ -19,6 +19,7 @@ GNU General Public License for more details.
|
|||
#include "mathlib.h"
|
||||
#include "edict.h"
|
||||
#include "eiface.h"
|
||||
#include "physint.h" // physics interface
|
||||
#include "mod_local.h"
|
||||
#include "pm_defs.h"
|
||||
#include "pm_movevars.h"
|
||||
|
@ -29,7 +30,6 @@ GNU General Public License for more details.
|
|||
#include "world.h"
|
||||
|
||||
//=============================================================================
|
||||
#define MAX_MASTERS 8 // max recipients for heartbeat packets
|
||||
|
||||
#define SV_UPDATE_MASK (SV_UPDATE_BACKUP - 1)
|
||||
extern int SV_UPDATE_BACKUP;
|
||||
|
@ -105,6 +105,9 @@ typedef struct server_s
|
|||
string name; // map name
|
||||
string startspot; // player_start name on nextmap
|
||||
|
||||
double lastchecktime;
|
||||
int lastcheck; // number of last checked client
|
||||
|
||||
char model_precache[MAX_MODELS][CS_SIZE];
|
||||
char sound_precache[MAX_SOUNDS][CS_SIZE];
|
||||
char files_precache[MAX_CUSTOM][CS_SIZE];
|
||||
|
@ -322,6 +325,7 @@ typedef struct
|
|||
globalvars_t *globals; // server globals
|
||||
DLL_FUNCTIONS dllFuncs; // dll exported funcs
|
||||
NEW_DLL_FUNCTIONS dllFuncs2; // new dll exported funcs (can be NULL)
|
||||
physics_interface_t physFuncs; // physics interface functions (Xash3D extension)
|
||||
byte *mempool; // server premamnent pool: edicts etc
|
||||
byte *stringspool; // for shared strings
|
||||
|
||||
|
@ -353,7 +357,6 @@ typedef struct
|
|||
|
||||
//=============================================================================
|
||||
|
||||
extern netadr_t master_adr[MAX_MASTERS]; // address of the master server
|
||||
extern server_static_t svs; // persistant server info
|
||||
extern server_t sv; // local server
|
||||
extern svgame_static_t svgame; // persistant game info
|
||||
|
@ -396,6 +399,7 @@ extern convar_t *sv_send_resources;
|
|||
extern convar_t *sv_send_logos;
|
||||
extern convar_t *sv_sendvelocity;
|
||||
extern convar_t *mp_consistency;
|
||||
extern convar_t *public_server;
|
||||
extern convar_t *physinfo;
|
||||
|
||||
//===========================================================
|
||||
|
@ -415,6 +419,9 @@ void SV_InitOperatorCommands( void );
|
|||
void SV_KillOperatorCommands( void );
|
||||
void SV_UserinfoChanged( sv_client_t *cl, const char *userinfo );
|
||||
void SV_PrepWorldFrame( void );
|
||||
void SV_ProcessFile( sv_client_t *cl, char *filename );
|
||||
void SV_SendResourceList( sv_client_t *cl );
|
||||
void Master_Add( void );
|
||||
void Master_Heartbeat( void );
|
||||
void Master_Packet( void );
|
||||
|
||||
|
@ -431,6 +438,7 @@ qboolean SV_SpawnServer( const char *server, const char *startspot );
|
|||
// sv_phys.c
|
||||
//
|
||||
void SV_Physics( void );
|
||||
qboolean SV_InitPhysicsAPI( void );
|
||||
void SV_CheckVelocity( edict_t *ent );
|
||||
qboolean SV_CheckWater( edict_t *ent );
|
||||
qboolean SV_RunThink( edict_t *ent );
|
||||
|
|
|
@ -933,7 +933,7 @@ void SV_PutClientInServer( edict_t *ent )
|
|||
return;
|
||||
}
|
||||
|
||||
// enable dev-mode to prevent crash cheat-protecting from invasion
|
||||
// enable dev-mode to prevent crash cheat-protecting from Invasion mod
|
||||
if( ent->v.flags & (FL_GODMODE|FL_NOTARGET) && !Q_stricmp( GI->gamefolder, "invasion" ))
|
||||
SV_ExecuteClientCommand( client, "test\n" );
|
||||
|
||||
|
@ -943,6 +943,7 @@ void SV_PutClientInServer( edict_t *ent )
|
|||
BF_WriteByte( &client->netchan.message, svc_setangle );
|
||||
BF_WriteBitAngle( &client->netchan.message, ent->v.angles[0], 16 );
|
||||
BF_WriteBitAngle( &client->netchan.message, ent->v.angles[1], 16 );
|
||||
BF_WriteBitAngle( &client->netchan.message, ent->v.angles[2], 16 );
|
||||
ent->v.fixangle = 0;
|
||||
}
|
||||
ent->v.effects |= EF_NOINTERP;
|
||||
|
@ -1054,14 +1055,111 @@ void SV_New_f( sv_client_t *cl )
|
|||
// set up the entity for the client
|
||||
ent = EDICT_NUM( playernum + 1 );
|
||||
cl->edict = ent;
|
||||
Q_memset( &cl->lastcmd, 0, sizeof( cl->lastcmd ));
|
||||
|
||||
// begin fetching modellist
|
||||
BF_WriteByte( &cl->netchan.message, svc_stufftext );
|
||||
BF_WriteString( &cl->netchan.message, va( "cmd modellist %i %i\n", svs.spawncount, 0 ));
|
||||
if( sv_maxclients->integer == 1 )
|
||||
{
|
||||
Q_memset( &cl->lastcmd, 0, sizeof( cl->lastcmd ));
|
||||
|
||||
// begin fetching modellist
|
||||
BF_WriteByte( &cl->netchan.message, svc_stufftext );
|
||||
BF_WriteString( &cl->netchan.message, va( "cmd modellist %i %i\n", svs.spawncount, 0 ));
|
||||
}
|
||||
else
|
||||
{
|
||||
// request resource list
|
||||
BF_WriteByte( &cl->netchan.message, svc_stufftext );
|
||||
BF_WriteString( &cl->netchan.message, va( "cmd getresourelist\n" ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_ContinueLoading_f
|
||||
==================
|
||||
*/
|
||||
void SV_ContinueLoading_f( sv_client_t *cl )
|
||||
{
|
||||
if( cl->state != cs_connected )
|
||||
{
|
||||
MsgDev( D_INFO, "continueloading is not valid from the console\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
Q_memset( &cl->lastcmd, 0, sizeof( cl->lastcmd ));
|
||||
|
||||
// begin fetching modellist
|
||||
BF_WriteByte( &cl->netchan.message, svc_stufftext );
|
||||
BF_WriteString( &cl->netchan.message, va( "cmd modellist %i %i\n", svs.spawncount, 0 ));
|
||||
}
|
||||
|
||||
/*
|
||||
=======================
|
||||
SV_SendResourceList
|
||||
|
||||
NOTE: Sending the list of cached resources.
|
||||
g-cont. this is fucking big message!!! i've rewriting this code
|
||||
=======================
|
||||
*/
|
||||
void SV_SendResourceList_f( sv_client_t *cl )
|
||||
{
|
||||
int index = 0;
|
||||
int rescount = 0;
|
||||
resourcelist_t reslist;
|
||||
size_t msg_size;
|
||||
|
||||
Q_memset( &reslist, 0, sizeof( resourcelist_t ));
|
||||
|
||||
reslist.restype[rescount] = t_world; // terminator
|
||||
Q_strcpy( reslist.resnames[rescount], "NULL" );
|
||||
rescount++;
|
||||
|
||||
for( index = 1; index < MAX_MODELS && sv.model_precache[index][0]; index++ )
|
||||
{
|
||||
if( sv.model_precache[index][0] == '*' ) // internal bmodel
|
||||
continue;
|
||||
|
||||
reslist.restype[rescount] = t_model;
|
||||
Q_strcpy( reslist.resnames[rescount], sv.model_precache[index] );
|
||||
rescount++;
|
||||
}
|
||||
|
||||
for( index = 1; index < MAX_SOUNDS && sv.sound_precache[index][0]; index++ )
|
||||
{
|
||||
reslist.restype[rescount] = t_sound;
|
||||
Q_strcpy( reslist.resnames[rescount], sv.sound_precache[index] );
|
||||
rescount++;
|
||||
}
|
||||
|
||||
for( index = 1; index < MAX_EVENTS && sv.event_precache[index][0]; index++ )
|
||||
{
|
||||
reslist.restype[rescount] = t_eventscript;
|
||||
Q_strcpy( reslist.resnames[rescount], sv.event_precache[index] );
|
||||
rescount++;
|
||||
}
|
||||
|
||||
for( index = 1; index < MAX_CUSTOM && sv.files_precache[index][0]; index++ )
|
||||
{
|
||||
reslist.restype[rescount] = t_generic;
|
||||
Q_strcpy( reslist.resnames[rescount], sv.files_precache[index] );
|
||||
rescount++;
|
||||
}
|
||||
|
||||
msg_size = BF_GetRealBytesWritten( &cl->netchan.message ); // start
|
||||
|
||||
BF_WriteByte( &cl->netchan.message, svc_resourcelist );
|
||||
BF_WriteWord( &cl->netchan.message, rescount );
|
||||
|
||||
for( index = 1; index < rescount; index++ )
|
||||
{
|
||||
BF_WriteWord( &cl->netchan.message, reslist.restype[index] );
|
||||
BF_WriteString( &cl->netchan.message, reslist.resnames[index] );
|
||||
}
|
||||
|
||||
Msg( "Count res: %d\n", rescount );
|
||||
Msg( "ResList size: %s\n", Q_memprint( BF_GetRealBytesWritten( &cl->netchan.message ) - msg_size ));
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_WriteModels_f
|
||||
|
@ -1692,6 +1790,8 @@ ucmd_t ucmds[] =
|
|||
{ "usermsgs", SV_UserMessages_f },
|
||||
{ "userinfo", SV_UpdateUserinfo_f },
|
||||
{ "lightstyles", SV_WriteLightstyles_f },
|
||||
{ "getresourelist", SV_SendResourceList_f },
|
||||
{ "continueloading", SV_ContinueLoading_f },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -1741,6 +1841,10 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
|
|||
char *args;
|
||||
char *c, buf[MAX_SYSPATH];
|
||||
int len = sizeof( buf );
|
||||
dword challenge;
|
||||
int index, count = 0;
|
||||
char query[512];
|
||||
word port;
|
||||
|
||||
BF_Clear( msg );
|
||||
BF_ReadLong( msg );// skip the -1 marker
|
||||
|
@ -1758,6 +1862,25 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
|
|||
else if( !Q_strcmp( c, "getchallenge" )) SV_GetChallenge( from );
|
||||
else if( !Q_strcmp( c, "connect" )) SV_DirectConnect( from );
|
||||
else if( !Q_strcmp( c, "rcon" )) SV_RemoteCommand( from, msg );
|
||||
else if( msg->pData[0] == 0xFF && msg->pData[1] == 0xFF && msg->pData[2] == 0xFF && msg->pData[3] == 0xFF && msg->pData[4] == 0x4E && msg->pData[5] == 0x0A )
|
||||
{
|
||||
challenge = *(dword *)&msg->pData[6];
|
||||
|
||||
port = Cvar_Get( "ip_hostport", "0", CVAR_INIT, "network server port" )->integer;
|
||||
if( !port ) port = Cvar_Get( "port", va( "%i", PORT_SERVER ), CVAR_INIT, "network default port" )->integer;
|
||||
|
||||
for( index = 0; index < sv_maxclients->integer; index++ )
|
||||
{
|
||||
if( svs.clients[index].state >= cs_connected )
|
||||
count++;
|
||||
}
|
||||
|
||||
Q_snprintf( query, sizeof( query ),
|
||||
"0\n\\protocol\\7\\challenge\\%ld\\players\\%d\\max\\%d\\bots\\0\\gamedir\\%s_xash\\map\\%s\\password\\0\\os\\w\\lan\\0\\region\\255\\gameport\\%d\\specport\\27015\\dedicated\\1\\appid\\70\\type\\d\\secure\\0\\version\\1.1.2.1\\product\\valve\n",
|
||||
challenge, count, sv_maxclients->integer, GI->gamefolder, sv.name, port );
|
||||
|
||||
NET_SendPacket( NS_SERVER, Q_strlen( query ), query, from );
|
||||
}
|
||||
else if( svgame.dllFuncs.pfnConnectionlessPacket( &from, args, buf, &len ))
|
||||
{
|
||||
// user out of band message (must be handled in CL_ConnectionlessPacket)
|
||||
|
@ -1903,6 +2026,19 @@ static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg )
|
|||
player->v.animtime = sv.time + host.frametime;
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
SV_ParseResourceList
|
||||
|
||||
Parse resource list
|
||||
===================
|
||||
*/
|
||||
void SV_ParseResourceList( sv_client_t *cl, sizebuf_t *msg )
|
||||
{
|
||||
Netchan_CreateFileFragments( true, &cl->netchan, BF_ReadString( msg ));
|
||||
Netchan_FragSend( &cl->netchan );
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
SV_ExecuteClientMessage
|
||||
|
@ -1976,6 +2112,9 @@ void SV_ExecuteClientMessage( sv_client_t *cl, sizebuf_t *msg )
|
|||
if( ++stringCmdCount < 8 ) SV_ExecuteClientCommand( cl, s );
|
||||
if( cl->state == cs_zombie ) return; // disconnect command
|
||||
break;
|
||||
case clc_resourcelist:
|
||||
SV_ParseResourceList( cl, msg );
|
||||
break;
|
||||
default:
|
||||
MsgDev( D_ERROR, "SV_ReadClientMessage: clc_bad\n" );
|
||||
SV_DropClient( cl );
|
||||
|
|
|
@ -96,51 +96,6 @@ void SV_BroadcastCommand( char *fmt, ... )
|
|||
BF_WriteString( &sv.reliable_datagram, string );
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
SV_SetMaster_f
|
||||
|
||||
Specify a list of master servers
|
||||
====================
|
||||
*/
|
||||
void SV_SetMaster_f( void )
|
||||
{
|
||||
int i, slot;
|
||||
|
||||
// only dedicated servers send heartbeats
|
||||
if( host.type != HOST_DEDICATED )
|
||||
{
|
||||
Msg( "Only dedicated servers use masters.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure the server is listed public
|
||||
Cvar_Set( "public", "1" );
|
||||
|
||||
for( i = 1; i < MAX_MASTERS; i++ )
|
||||
{
|
||||
Q_memset( &master_adr[i], 0, sizeof( master_adr[i] ));
|
||||
}
|
||||
|
||||
// slot 0 will always contain the id master
|
||||
for( i = 1, slot = 1; i < Cmd_Argc(); i++ )
|
||||
{
|
||||
if( slot == MAX_MASTERS ) break;
|
||||
if( !NET_StringToAdr( Cmd_Argv( i ), &master_adr[i] ))
|
||||
{
|
||||
Msg( "Bad address: %s\n", Cmd_Argv( i ));
|
||||
continue;
|
||||
}
|
||||
|
||||
if( !master_adr[slot].port ) master_adr[slot].port = BF_BigShort( PORT_MASTER );
|
||||
Msg( "Master server at %s\n", NET_AdrToString( master_adr[slot] ));
|
||||
Msg( "Sending a ping.\n" );
|
||||
Netchan_OutOfBandPrint( NS_SERVER, master_adr[slot], "ping" );
|
||||
slot++;
|
||||
}
|
||||
svs.last_heartbeat = MAX_HEARTBEAT;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_SetPlayer
|
||||
|
@ -832,7 +787,6 @@ void SV_InitOperatorCommands( void )
|
|||
if( host.type == HOST_DEDICATED )
|
||||
{
|
||||
Cmd_AddCommand( "say", SV_ConSay_f, "send a chat message to everyone on the server" );
|
||||
Cmd_AddCommand( "setmaster", SV_SetMaster_f, "set ip address for dedicated server" );
|
||||
Cmd_AddCommand( "killserver", SV_KillServer_f, "shutdown current server" );
|
||||
}
|
||||
|
||||
|
|
|
@ -381,6 +381,7 @@ void SV_WriteClientdataToMessage( sv_client_t *cl, sizebuf_t *msg )
|
|||
BF_WriteByte( msg, svc_setangle );
|
||||
BF_WriteBitAngle( msg, clent->v.angles[0], 16 );
|
||||
BF_WriteBitAngle( msg, clent->v.angles[1], 16 );
|
||||
BF_WriteBitAngle( msg, clent->v.angles[2], 16 );
|
||||
clent->v.effects |= EF_NOINTERP;
|
||||
break;
|
||||
case 2:
|
||||
|
|
|
@ -21,11 +21,10 @@ GNU General Public License for more details.
|
|||
#include "pm_defs.h"
|
||||
#include "const.h"
|
||||
|
||||
#define DEBUG_NEW_CLIENTPVS_CHECK
|
||||
|
||||
// fatpvs stuff
|
||||
static byte fatpvs[MAX_MAP_LEAFS/8];
|
||||
static byte fatphs[MAX_MAP_LEAFS/8];
|
||||
static byte clientpvs[MAX_MAP_LEAFS/8]; // for find client in PVS
|
||||
static vec3_t viewPoint[MAX_CLIENTS];
|
||||
static byte *bitvector;
|
||||
static int fatbytes;
|
||||
|
@ -314,6 +313,10 @@ qboolean SV_Send( int dest, const vec3_t origin, const edict_t *ent )
|
|||
clientnum = cl - svs.clients;
|
||||
viewOrg = viewPoint[clientnum];
|
||||
|
||||
// Invasion issues: wrong camera position received in ENGINE_SET_PVS
|
||||
if( cl->pViewEntity && !VectorCompare( viewOrg, cl->pViewEntity->v.origin ))
|
||||
viewOrg = cl->pViewEntity->v.origin;
|
||||
|
||||
// -1 is because pvs rows are 1 based, not 0 based like leafs
|
||||
leafnum = Mod_PointLeafnum( viewOrg ) - 1;
|
||||
if( mask && (!(mask[leafnum>>3] & (1<<( leafnum & 7 )))))
|
||||
|
@ -766,7 +769,7 @@ edict_t* SV_AllocPrivateData( edict_t *ent, string_t className )
|
|||
if( !SpawnEdict )
|
||||
{
|
||||
// attempt to create custom entity (Xash3D extension)
|
||||
if( svgame.dllFuncs2.pfnCreate && svgame.dllFuncs2.pfnCreate( ent, pszClassName ) != -1 )
|
||||
if( svgame.physFuncs.SV_CreateEntity && svgame.physFuncs.SV_CreateEntity( ent, pszClassName ) != -1 )
|
||||
return ent;
|
||||
|
||||
ent->v.flags |= FL_KILLME;
|
||||
|
@ -1249,73 +1252,98 @@ edict_t *pfnFindEntityInSphere( edict_t *pStartEdict, const float *org, float fl
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
SV_CheckClientPVS
|
||||
|
||||
build the new client PVS
|
||||
=================
|
||||
*/
|
||||
int SV_CheckClientPVS( int check )
|
||||
{
|
||||
byte *pvs;
|
||||
edict_t *ent;
|
||||
mleaf_t *leaf;
|
||||
vec3_t view;
|
||||
int i;
|
||||
|
||||
// cycle to the next one
|
||||
check = bound( 1, check, svgame.globals->maxClients );
|
||||
|
||||
if( check == svgame.globals->maxClients )
|
||||
i = 1;
|
||||
else i = check + 1;
|
||||
|
||||
for( ;; i++ )
|
||||
{
|
||||
if( i == svgame.globals->maxClients + 1 )
|
||||
i = 1;
|
||||
|
||||
ent = EDICT_NUM( i );
|
||||
|
||||
if( i == check ) break; // didn't find anything else
|
||||
|
||||
if( ent->free ) continue;
|
||||
if( !ent->pvPrivateData ) continue;
|
||||
if( ent->v.flags & FL_NOTARGET ) continue;
|
||||
|
||||
// anything that is a client, or has a client as an enemy
|
||||
break;
|
||||
}
|
||||
|
||||
// get the PVS for the entity
|
||||
VectorAdd( ent->v.origin, ent->v.view_ofs, view );
|
||||
leaf = Mod_PointInLeaf( view, sv.worldmodel->nodes );
|
||||
pvs = Mod_LeafPVS( leaf, sv.worldmodel );
|
||||
memcpy( clientpvs, pvs, (sv.worldmodel->numleafs + 7) >> 3 );
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
pfnFindClientInPVS
|
||||
|
||||
FIXME: this code is totally wrong. Get PF_checkclient from QW.
|
||||
=================
|
||||
*/
|
||||
edict_t* pfnFindClientInPVS( edict_t *pEdict )
|
||||
{
|
||||
edict_t *pClient;
|
||||
sv_client_t *cl;
|
||||
vec3_t view1, view2;
|
||||
int i;
|
||||
edict_t *pClient;
|
||||
mleaf_t *leaf;
|
||||
vec3_t view;
|
||||
int i;
|
||||
|
||||
if( !SV_IsValidEdict( pEdict ))
|
||||
return svgame.edicts;
|
||||
|
||||
VectorAdd( pEdict->v.origin, pEdict->v.view_ofs, view1 );
|
||||
|
||||
for( i = 0; i < svgame.globals->maxClients; i++ )
|
||||
// find a new check if on a new frame
|
||||
if(( sv.time - sv.lastchecktime ) >= 0.1 )
|
||||
{
|
||||
pClient = EDICT_NUM( i + 1 );
|
||||
if(( cl = SV_ClientFromEdict( pClient, true )) == NULL )
|
||||
continue;
|
||||
|
||||
// check for SET_VIEW
|
||||
if( SV_IsValidEdict( cl->pViewEntity ))
|
||||
VectorAdd( cl->pViewEntity->v.origin, cl->pViewEntity->v.view_ofs, view2 );
|
||||
else VectorAdd( pClient->v.origin, pClient->v.view_ofs, view2 );
|
||||
|
||||
if( pEdict->v.modelindex )
|
||||
{
|
||||
// can use entity leafs or headnode for fast testing
|
||||
// FIXME: this is need to be detail tested!
|
||||
mleaf_t *leaf = Mod_PointInLeaf( view2, sv.worldmodel->nodes );
|
||||
byte *mask = Mod_LeafPVS( leaf, sv.worldmodel );
|
||||
|
||||
if( pfnCheckVisibility( pEdict, mask ))
|
||||
{
|
||||
return pClient;
|
||||
}
|
||||
#ifdef DEBUG_NEW_CLIENTPVS_CHECK
|
||||
else if( sv_check_errors->integer )
|
||||
{
|
||||
trace_t tr;
|
||||
tr = SV_Move( view1, vec3_origin, vec3_origin, view2, MOVE_WORLDONLY, NULL );
|
||||
|
||||
if( tr.fraction == 1.0f && !tr.allsolid )
|
||||
{
|
||||
MsgDev( D_ERROR, "CHECK_CLIENT_PVS: fail to see %s, probably client is underwater\n", SV_ClassName( pEdict ));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if( SV_OriginIn( DVIS_PVS, view1, view2 ))
|
||||
return pClient;
|
||||
}
|
||||
sv.lastcheck = SV_CheckClientPVS( sv.lastcheck );
|
||||
sv.lastchecktime = sv.time;
|
||||
}
|
||||
return svgame.edicts;
|
||||
|
||||
// return check if it might be visible
|
||||
pClient = EDICT_NUM( sv.lastcheck );
|
||||
if( !SV_ClientFromEdict( pClient, true ))
|
||||
return svgame.edicts;
|
||||
|
||||
VectorAdd( pEdict->v.origin, pEdict->v.view_ofs, view );
|
||||
leaf = Mod_PointInLeaf( view, sv.worldmodel->nodes );
|
||||
i = (leaf - sv.worldmodel->leafs) - 1;
|
||||
|
||||
if( i < 0 || !((clientpvs[i>>3]) & (1 << (i & 7))))
|
||||
return svgame.edicts;
|
||||
|
||||
// client which currently in PVS
|
||||
return pClient;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
pfnEntitiesInPVS
|
||||
|
||||
FIXME: rewrite this code. get rid of hack
|
||||
=================
|
||||
*/
|
||||
edict_t *pfnEntitiesInPVS( edict_t *pplayer )
|
||||
|
@ -1673,6 +1701,8 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
|
|||
int msg_dest;
|
||||
vec3_t origin;
|
||||
|
||||
if( !sample ) return;
|
||||
|
||||
if( attn < ATTN_NONE || attn > ATTN_IDLE )
|
||||
{
|
||||
MsgDev( D_ERROR, "SV_StartSound: attenuation %g must be in range 0-2\n", attn );
|
||||
|
@ -1781,6 +1811,8 @@ void pfnEmitAmbientSound( edict_t *ent, float *pos, const char *sample, float vo
|
|||
int msg_dest = MSG_PAS_R;
|
||||
vec3_t origin;
|
||||
|
||||
if( !sample ) return;
|
||||
|
||||
if( attn < ATTN_NONE || attn > ATTN_IDLE )
|
||||
{
|
||||
MsgDev( D_ERROR, "SV_AmbientSound: attenuation must be in range 0-2\n" );
|
||||
|
@ -3282,6 +3314,9 @@ char *pfnGetInfoKeyBuffer( edict_t *e )
|
|||
{
|
||||
sv_client_t *cl;
|
||||
|
||||
if( !SV_IsValidEdict( e ))
|
||||
return Cvar_Serverinfo(); // otherwise return ServerInfo
|
||||
|
||||
cl = SV_ClientFromEdict( e, false ); // pfnUserInfoChanged passed
|
||||
if( cl == NULL )
|
||||
{
|
||||
|
@ -3947,6 +3982,150 @@ const char *pfnGetPlayerAuthId( edict_t *e )
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnSequenceGet
|
||||
|
||||
used by CS:CZ
|
||||
=============
|
||||
*/
|
||||
void *pfnSequenceGet( const char *fileName, const char *entryName )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnSequencePickSentence
|
||||
|
||||
used by CS:CZ
|
||||
=============
|
||||
*/
|
||||
void *pfnSequencePickSentence( const char *groupName, int pickMethod, int *picked )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnGetFileSize
|
||||
|
||||
returns the filesize in bytes
|
||||
=============
|
||||
*/
|
||||
int pfnGetFileSize( char *filename )
|
||||
{
|
||||
return FS_FileSize( filename, false );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnGetApproxWavePlayLen
|
||||
|
||||
returns the wave length in samples
|
||||
=============
|
||||
*/
|
||||
uint pfnGetApproxWavePlayLen( const char *filepath )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnIsCareerMatch
|
||||
|
||||
used by CS:CZ
|
||||
=============
|
||||
*/
|
||||
int pfnIsCareerMatch( void )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnGetLocalizedStringLength
|
||||
|
||||
=============
|
||||
*/
|
||||
int pfnGetLocalizedStringLength( const char *label )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnRegisterTutorMessageShown
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnRegisterTutorMessageShown( int mid )
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnGetTimesTutorMessageShown
|
||||
|
||||
=============
|
||||
*/
|
||||
int pfnGetTimesTutorMessageShown( int mid )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnProcessTutorMessageDecayBuffer
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnProcessTutorMessageDecayBuffer( int *buffer, int bufferLength )
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnConstructTutorMessageDecayBuffer
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnConstructTutorMessageDecayBuffer( int *buffer, int bufferLength )
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnSequenceGet
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnResetTutorMessageDecayData( void )
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnQueryClientCvarValue
|
||||
|
||||
request client cvar value
|
||||
=============
|
||||
*/
|
||||
void pfnQueryClientCvarValue( const edict_t *player, const char *cvarName )
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnQueryClientCvarValue2
|
||||
|
||||
request client cvar value (bugfixed)
|
||||
=============
|
||||
*/
|
||||
void pfnQueryClientCvarValue2( const edict_t *player, const char *cvarName, int requestID )
|
||||
{
|
||||
}
|
||||
|
||||
// engine callbacks
|
||||
static enginefuncs_t gEngfuncs =
|
||||
|
@ -4095,6 +4274,19 @@ static enginefuncs_t gEngfuncs =
|
|||
pfnVoice_GetClientListening,
|
||||
pfnVoice_SetClientListening,
|
||||
pfnGetPlayerAuthId,
|
||||
pfnSequenceGet,
|
||||
pfnSequencePickSentence,
|
||||
pfnGetFileSize,
|
||||
pfnGetApproxWavePlayLen,
|
||||
pfnIsCareerMatch,
|
||||
pfnGetLocalizedStringLength,
|
||||
pfnRegisterTutorMessageShown,
|
||||
pfnGetTimesTutorMessageShown,
|
||||
pfnProcessTutorMessageDecayBuffer,
|
||||
pfnConstructTutorMessageDecayBuffer,
|
||||
pfnResetTutorMessageDecayData,
|
||||
pfnQueryClientCvarValue,
|
||||
pfnQueryClientCvarValue2,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -4388,6 +4580,9 @@ qboolean SV_LoadProgs( const char *name )
|
|||
// make sure what new dll functions is cleared
|
||||
Q_memset( &svgame.dllFuncs2, 0, sizeof( svgame.dllFuncs2 ));
|
||||
|
||||
// make sure what physic functions is cleared
|
||||
Q_memset( &svgame.physFuncs, 0, sizeof( svgame.physFuncs ));
|
||||
|
||||
// make local copy of engfuncs to prevent overwrite it with bots.dll
|
||||
Q_memcpy( &gpEngfuncs, &gEngfuncs, sizeof( gpEngfuncs ));
|
||||
|
||||
|
@ -4395,7 +4590,7 @@ qboolean SV_LoadProgs( const char *name )
|
|||
GetEntityAPI2 = (APIFUNCTION2)Com_GetProcAddress( svgame.hInstance, "GetEntityAPI2" );
|
||||
GiveNewDllFuncs = (NEW_DLL_FUNCTIONS_FN)Com_GetProcAddress( svgame.hInstance, "GetNewDLLFunctions" );
|
||||
|
||||
if( !GetEntityAPI )
|
||||
if( !GetEntityAPI && !GetEntityAPI2 )
|
||||
{
|
||||
Com_FreeLibrary( svgame.hInstance );
|
||||
MsgDev( D_NOTE, "SV_LoadProgs: failed to get address of GetEntityAPI proc\n" );
|
||||
|
@ -4430,22 +4625,29 @@ qboolean SV_LoadProgs( const char *name )
|
|||
|
||||
version = INTERFACE_VERSION;
|
||||
|
||||
if( !GetEntityAPI( &svgame.dllFuncs, version ))
|
||||
if( GetEntityAPI2 )
|
||||
{
|
||||
if( !GetEntityAPI2 )
|
||||
if( !GetEntityAPI2( &svgame.dllFuncs, &version ))
|
||||
{
|
||||
Com_FreeLibrary( svgame.hInstance );
|
||||
MsgDev( D_ERROR, "SV_LoadProgs: couldn't get entity API\n" );
|
||||
svgame.hInstance = NULL;
|
||||
return false;
|
||||
}
|
||||
else if( !GetEntityAPI2( &svgame.dllFuncs, &version ))
|
||||
{
|
||||
Com_FreeLibrary( svgame.hInstance );
|
||||
MsgDev( D_ERROR, "SV_LoadProgs: interface version %i should be %i\n", INTERFACE_VERSION, version );
|
||||
svgame.hInstance = NULL;
|
||||
return false;
|
||||
MsgDev( D_WARN, "SV_LoadProgs: interface version %i should be %i\n", INTERFACE_VERSION, version );
|
||||
|
||||
// fallback to old API
|
||||
if( !GetEntityAPI( &svgame.dllFuncs, version ))
|
||||
{
|
||||
Com_FreeLibrary( svgame.hInstance );
|
||||
MsgDev( D_ERROR, "SV_LoadProgs: couldn't get entity API\n" );
|
||||
svgame.hInstance = NULL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else MsgDev( D_AICONSOLE, "SV_LoadProgs: ^2initailized extended EntityAPI ^7ver. %i\n", version );
|
||||
}
|
||||
else if( !GetEntityAPI( &svgame.dllFuncs, version ))
|
||||
{
|
||||
Com_FreeLibrary( svgame.hInstance );
|
||||
MsgDev( D_ERROR, "SV_LoadProgs: couldn't get entity API\n" );
|
||||
svgame.hInstance = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !SV_InitStudioAPI( ))
|
||||
|
@ -4456,6 +4658,11 @@ qboolean SV_LoadProgs( const char *name )
|
|||
return false;
|
||||
}
|
||||
|
||||
if( !SV_InitPhysicsAPI( ))
|
||||
{
|
||||
MsgDev( D_WARN, "SV_LoadProgs: couldn't get physics API\n" );
|
||||
}
|
||||
|
||||
// grab function SV_SaveGameComment
|
||||
SV_InitSaveRestore ();
|
||||
|
||||
|
|
|
@ -337,6 +337,12 @@ void SV_ActivateServer( void )
|
|||
sv.paused = false;
|
||||
|
||||
Host_SetServerState( sv.state );
|
||||
|
||||
if( sv_maxclients->integer > 1 && public_server->integer )
|
||||
{
|
||||
MsgDev( D_INFO, "Add your server, to master server list\n" );
|
||||
Master_Add( );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -540,7 +546,6 @@ A brand new game has been started
|
|||
*/
|
||||
void SV_InitGame( void )
|
||||
{
|
||||
string idmaster;
|
||||
edict_t *ent;
|
||||
int i;
|
||||
|
||||
|
@ -621,8 +626,6 @@ void SV_InitGame( void )
|
|||
|
||||
// heartbeats will always be sent to the id master
|
||||
svs.last_heartbeat = MAX_HEARTBEAT; // send immediately
|
||||
Q_sprintf( idmaster, "192.246.40.37:%i", PORT_MASTER ); // TODO: parse woncomm.lst
|
||||
NET_StringToAdr( idmaster, &master_adr[0] );
|
||||
|
||||
// set client fields on player ents
|
||||
for( i = 0; i < svgame.globals->maxClients; i++ )
|
||||
|
|
|
@ -19,8 +19,6 @@ GNU General Public License for more details.
|
|||
|
||||
#define HEARTBEAT_SECONDS 300.0f // 300 seconds
|
||||
|
||||
netadr_t master_adr[MAX_MASTERS]; // address of group servers
|
||||
|
||||
convar_t *sv_zmax;
|
||||
convar_t *sv_novis; // disable server culling entities by vis
|
||||
convar_t *sv_unlag;
|
||||
|
@ -364,7 +362,7 @@ void SV_ReadPackets( void )
|
|||
|
||||
if( Netchan_CopyFileFragments( &cl->netchan, &net_message ))
|
||||
{
|
||||
// SV_ProcessFile( cl, cl->netchan.incomingfilename );
|
||||
SV_ProcessFile( cl, cl->netchan.incomingfilename );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -460,6 +458,17 @@ void SV_PrepWorldFrame( void )
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
SV_ProcessFile
|
||||
=================
|
||||
*/
|
||||
void SV_ProcessFile( sv_client_t *cl, char *filename )
|
||||
{
|
||||
// some other file...
|
||||
MsgDev( D_INFO, "Received file %s from %s\n", filename, cl->name );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
SV_IsSimulating
|
||||
|
@ -543,6 +552,23 @@ void Host_ServerFrame( void )
|
|||
|
||||
//============================================================================
|
||||
|
||||
/*
|
||||
=================
|
||||
Master_Add
|
||||
=================
|
||||
*/
|
||||
void Master_Add( void )
|
||||
{
|
||||
netadr_t adr;
|
||||
|
||||
NET_Config( true ); // allow remote
|
||||
|
||||
if( !NET_StringToAdr( MASTERSERVER_ADR, &adr ))
|
||||
MsgDev( D_INFO, "Can't resolve adr: %s\n", MASTERSERVER_ADR );
|
||||
|
||||
NET_SendPacket( NS_SERVER, 2, "\x4D\xFF", adr );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Master_Heartbeat
|
||||
|
@ -553,11 +579,8 @@ let it know we are alive, and log information
|
|||
*/
|
||||
void Master_Heartbeat( void )
|
||||
{
|
||||
char *string;
|
||||
int i;
|
||||
|
||||
if( host.type != HOST_DEDICATED || !public_server->integer )
|
||||
return; // only dedicated servers send heartbeats
|
||||
if( !public_server->integer || sv_maxclients->integer == 1 )
|
||||
return; // only public servers send heartbeats
|
||||
|
||||
// check for time wraparound
|
||||
if( svs.last_heartbeat > host.realtime )
|
||||
|
@ -568,18 +591,7 @@ void Master_Heartbeat( void )
|
|||
|
||||
svs.last_heartbeat = host.realtime;
|
||||
|
||||
// send the same string that we would give for a status OOB command
|
||||
string = SV_StatusString( );
|
||||
|
||||
// send to group master
|
||||
for( i = 0; i < MAX_MASTERS; i++ )
|
||||
{
|
||||
if( master_adr[i].port )
|
||||
{
|
||||
MsgDev( D_INFO, "Sending heartbeat to %s\n", NET_AdrToString( master_adr[i] ));
|
||||
Netchan_OutOfBandPrint( NS_SERVER, master_adr[i], "heartbeat\n%s", string );
|
||||
}
|
||||
}
|
||||
Master_Add();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -591,20 +603,6 @@ Informs all masters that this server is going down
|
|||
*/
|
||||
void Master_Shutdown( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( host.type != HOST_DEDICATED || !public_server->integer )
|
||||
return; // only dedicated servers send heartbeats
|
||||
|
||||
// send to group master
|
||||
for( i = 0; i < MAX_MASTERS; i++ )
|
||||
{
|
||||
if( master_adr[i].port )
|
||||
{
|
||||
if( i ) MsgDev( D_INFO, "Sending heartbeat to %s\n", NET_AdrToString( master_adr[i] ));
|
||||
Netchan_OutOfBandPrint( NS_SERVER, master_adr[i], "shutdown" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
|
|
@ -16,6 +16,9 @@ GNU General Public License for more details.
|
|||
#include "common.h"
|
||||
#include "server.h"
|
||||
#include "const.h"
|
||||
#include "library.h"
|
||||
|
||||
typedef int (*PHYSICAPI)( int, server_physics_api_t*, physics_interface_t* );
|
||||
|
||||
/*
|
||||
|
||||
|
@ -311,7 +314,7 @@ qboolean SV_CheckWater( edict_t *ent )
|
|||
ent->v.watertype = cont;
|
||||
ent->v.waterlevel = 1;
|
||||
|
||||
point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2]) * 0.5f;
|
||||
point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2]) * 0.5f;
|
||||
|
||||
svs.groupmask = ent->v.groupinfo;
|
||||
cont = SV_PointContents( point );
|
||||
|
@ -593,7 +596,7 @@ PUSHMOVE
|
|||
============
|
||||
SV_AllowPushRotate
|
||||
|
||||
Allows to chnage entity yaw?
|
||||
Allows to change entity yaw?
|
||||
============
|
||||
*/
|
||||
qboolean SV_AllowPushRotate( edict_t *ent )
|
||||
|
@ -1060,7 +1063,7 @@ void SV_Physics_Pusher( edict_t *ent )
|
|||
{
|
||||
if( VectorLength2( ent->v.velocity ) > STOP_EPSILON )
|
||||
{
|
||||
pBlocker = SV_PushRotate( ent, movetime );
|
||||
pBlocker = SV_PushRotate( ent, movetime );
|
||||
|
||||
if( !pBlocker )
|
||||
{
|
||||
|
@ -1529,7 +1532,7 @@ void SV_Physics_Step( edict_t *ent )
|
|||
point[0] = x ? maxs[0] : mins[0];
|
||||
point[1] = y ? maxs[1] : mins[1];
|
||||
|
||||
trace = SV_Move( point, vec3_origin, vec3_origin, point, MOVE_NORMAL, ent );
|
||||
trace = SV_Move( point, vec3_origin, vec3_origin, point, MOVE_NORMAL, ent );
|
||||
|
||||
if( trace.startsolid )
|
||||
{
|
||||
|
@ -1595,9 +1598,9 @@ static void SV_Physics_Entity( edict_t *ent )
|
|||
}
|
||||
|
||||
// user dll can override movement type (Xash3D extension)
|
||||
if( svgame.dllFuncs2.pfnPhysicsEntity )
|
||||
if( svgame.physFuncs.SV_PhysicsEntity )
|
||||
{
|
||||
if( svgame.dllFuncs2.pfnPhysicsEntity( ent ))
|
||||
if( svgame.physFuncs.SV_PhysicsEntity( ent ))
|
||||
{
|
||||
if( ent->v.flags & FL_KILLME )
|
||||
SV_FreeEdict( ent );
|
||||
|
@ -1680,4 +1683,52 @@ void SV_Physics( void )
|
|||
|
||||
// decrement svgame.numEntities if the highest number entities died
|
||||
for( ; EDICT_NUM( svgame.numEntities - 1 )->free; svgame.numEntities-- );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
SV_GetServerTime
|
||||
|
||||
Inplementation for new physics interface
|
||||
================
|
||||
*/
|
||||
double SV_GetServerTime( void )
|
||||
{
|
||||
return sv.time;
|
||||
}
|
||||
|
||||
static server_physics_api_t gPhysicsAPI =
|
||||
{
|
||||
SV_LinkEdict,
|
||||
SV_GetServerTime,
|
||||
};
|
||||
|
||||
/*
|
||||
===============
|
||||
SV_InitPhysicsAPI
|
||||
|
||||
Initialize server external physics
|
||||
===============
|
||||
*/
|
||||
qboolean SV_InitPhysicsAPI( void )
|
||||
{
|
||||
static PHYSICAPI pPhysIface;
|
||||
|
||||
pPhysIface = (PHYSICAPI)Com_GetProcAddress( svgame.hInstance, "Server_GetPhysicsInterface" );
|
||||
if( pPhysIface )
|
||||
{
|
||||
if( pPhysIface( SV_PHYSICS_INTERFACE_VERSION, &gPhysicsAPI, &svgame.physFuncs ))
|
||||
{
|
||||
MsgDev( D_AICONSOLE, "SV_LoadProgs: ^2initailized extended PhysicAPI ^7ver. %i\n", SV_PHYSICS_INTERFACE_VERSION );
|
||||
return true;
|
||||
}
|
||||
|
||||
// make sure what physic functions is cleared
|
||||
Q_memset( &svgame.physFuncs, 0, sizeof( svgame.physFuncs ));
|
||||
|
||||
return false; // just tell user about problems
|
||||
}
|
||||
|
||||
// physic interface is missed
|
||||
return true;
|
||||
}
|
|
@ -831,9 +831,9 @@ SV_RunCmd
|
|||
*/
|
||||
void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd, int random_seed )
|
||||
{
|
||||
usercmd_t cmd;
|
||||
edict_t *clent;
|
||||
vec3_t oldvel;
|
||||
usercmd_t cmd;
|
||||
int oldmsec;
|
||||
|
||||
clent = cl->edict;
|
||||
|
|
|
@ -143,8 +143,11 @@ hull_t *SV_HullForEntity( edict_t *ent, int hullNumber, vec3_t mins, vec3_t maxs
|
|||
float lastdiff = 999;
|
||||
int i;
|
||||
|
||||
#ifdef RANDOM_HULL_NULLIZATION
|
||||
hullNumber = Com_RandomLong( 0, 0 );
|
||||
#else
|
||||
hullNumber = 0; // assume we fail
|
||||
|
||||
#endif
|
||||
// select the hull automatically
|
||||
for( i = 0; i < 4; i++ )
|
||||
{
|
||||
|
|
|
@ -25,7 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "extdll.h"
|
||||
#include "basemenu.h"
|
||||
#include "keydefs.h"
|
||||
#include "images.h" // built-in resources
|
||||
#include "menufont.h" // built-in menu font
|
||||
#include "utils.h"
|
||||
#include "menu_btnsbmp_table.h"
|
||||
//CR
|
||||
|
@ -56,6 +56,7 @@ int uiInputFgColor = 0xFF555555; // 85, 85, 85, 255 // field, scrollist, che
|
|||
int uiColorWhite = 0xFFFFFFFF; // 255, 255, 255, 255 // useful for bitmaps
|
||||
int uiColorDkGrey = 0xFF404040; // 64, 64, 64, 255 // shadow and grayed items
|
||||
int uiColorBlack = 0xFF000000; // 0, 0, 0, 255 // some controls background
|
||||
int uiColorConsole = 0xFFF0B418; // just for reference
|
||||
|
||||
// color presets (this is nasty hack to allow color presets to part of text)
|
||||
const int g_iColorTable[8] =
|
||||
|
@ -204,9 +205,12 @@ void UI_DrawString( int x, int y, int w, int h, const char *string, const int co
|
|||
if( !string || !string[0] )
|
||||
return;
|
||||
|
||||
#if 0 // g-cont. disabled 29/06/2011
|
||||
// this code do a bad things with prompt dialogues
|
||||
// vertically centered
|
||||
if( !strchr( string, '\n' ))
|
||||
y = y + (( h - charH ) / 2 );
|
||||
#endif
|
||||
|
||||
if( shadow )
|
||||
{
|
||||
|
@ -727,6 +731,20 @@ void UI_RefreshServerList( void )
|
|||
CLIENT_COMMAND( FALSE, "localservers\n" );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
UI_RefreshInternetServerList
|
||||
=================
|
||||
*/
|
||||
void UI_RefreshInternetServerList( void )
|
||||
{
|
||||
uiStatic.numServers = 0;
|
||||
memset( uiStatic.serverAddresses, 0, sizeof( uiStatic.serverAddresses ));
|
||||
memset( uiStatic.serverNames, 0, sizeof( uiStatic.serverNames ));
|
||||
|
||||
CLIENT_COMMAND( FALSE, "internetservers\n" );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
UI_StartBackGroundMap
|
||||
|
@ -1201,6 +1219,7 @@ void UI_Precache( void )
|
|||
UI_SaveLoad_Precache();
|
||||
UI_MultiPlayer_Precache();
|
||||
UI_Options_Precache();
|
||||
UI_InternetGames_Precache();
|
||||
UI_LanGame_Precache();
|
||||
UI_PlayerSetup_Precache();
|
||||
UI_Controls_Precache();
|
||||
|
@ -1275,11 +1294,15 @@ void UI_ApplyCustomColors( void )
|
|||
{
|
||||
UI_ParseColor( pfile, &uiInputFgColor );
|
||||
}
|
||||
else if( !stricmp( token, "CON_TEXT_COLOR" ))
|
||||
{
|
||||
UI_ParseColor( pfile, &uiColorConsole );
|
||||
}
|
||||
}
|
||||
|
||||
int r, g, b;
|
||||
|
||||
UnpackRGB( r, g, b, uiPromptTextColor );
|
||||
UnpackRGB( r, g, b, uiColorConsole );
|
||||
ConsoleSetColor( r, g, b );
|
||||
|
||||
FREE_FILE( afile );
|
||||
|
@ -1323,9 +1346,6 @@ UI_VidInit
|
|||
int UI_VidInit( void )
|
||||
{
|
||||
UI_Precache ();
|
||||
|
||||
// setup game info
|
||||
GetGameInfo( &gMenu.m_gameinfo );
|
||||
|
||||
uiStatic.scaleX = ScreenWidth / 1024.0f;
|
||||
uiStatic.scaleY = ScreenHeight / 768.0f;
|
||||
|
@ -1350,8 +1370,17 @@ int UI_VidInit( void )
|
|||
// trying to load chapterbackgrounds.txt
|
||||
UI_LoadBackgroundMapList ();
|
||||
|
||||
// register ui font
|
||||
uiStatic.hFont = PIC_Load( "menufont", font_tga, sizeof( font_tga ));
|
||||
// register menu font
|
||||
uiStatic.hFont = PIC_Load( "#XASH_SYSTEMFONT_001", menufont_bmp, sizeof( menufont_bmp ));
|
||||
|
||||
#if 0
|
||||
FILE *f;
|
||||
|
||||
// dump menufont onto disk
|
||||
f = fopen( "menufont.bmp", "wb" );
|
||||
fwrite( menufont_bmp, sizeof( menufont_bmp ), 1, f );
|
||||
fclose( f );
|
||||
#endif
|
||||
|
||||
// reload all menu buttons
|
||||
UI_LoadBmpButtons ();
|
||||
|
@ -1387,6 +1416,7 @@ void UI_Init( void )
|
|||
Cmd_AddCommand( "menu_multiplayer", UI_MultiPlayer_Menu );
|
||||
Cmd_AddCommand( "menu_options", UI_Options_Menu );
|
||||
Cmd_AddCommand( "menu_langame", UI_LanGame_Menu );
|
||||
Cmd_AddCommand( "menu_intenetgames", UI_InternetGames_Menu );
|
||||
Cmd_AddCommand( "menu_playersetup", UI_PlayerSetup_Menu );
|
||||
Cmd_AddCommand( "menu_controls", UI_Controls_Menu );
|
||||
Cmd_AddCommand( "menu_advcontrols", UI_AdvControls_Menu );
|
||||
|
@ -1403,6 +1433,12 @@ void UI_Init( void )
|
|||
memset( uiEmptyString, ' ', sizeof( uiEmptyString )); // HACKHACK
|
||||
uiStatic.initialized = true;
|
||||
|
||||
// setup game info
|
||||
GetGameInfo( &gMenu.m_gameinfo );
|
||||
|
||||
// load custom strings
|
||||
UI_LoadCustomStrings();
|
||||
|
||||
//CR
|
||||
UI_InitTitleAnim();
|
||||
}
|
||||
|
@ -1424,6 +1460,7 @@ void UI_Shutdown( void )
|
|||
Cmd_RemoveCommand( "menu_saveload" );
|
||||
Cmd_RemoveCommand( "menu_multiplayer" );
|
||||
Cmd_RemoveCommand( "menu_options" );
|
||||
Cmd_RemoveCommand( "menu_intenetgames" );
|
||||
Cmd_RemoveCommand( "menu_langame" );
|
||||
Cmd_RemoveCommand( "menu_playersetup" );
|
||||
Cmd_RemoveCommand( "menu_controls" );
|
||||
|
|
|
@ -404,6 +404,7 @@ void UI_AdjustCursor( menuFramework_s *menu, int dir );
|
|||
void UI_DrawMenu( menuFramework_s *menu );
|
||||
const char *UI_DefaultKey( menuFramework_s *menu, int key, int down );
|
||||
const char *UI_ActivateItem( menuFramework_s *menu, menuCommon_s *item );
|
||||
void UI_RefreshInternetServerList( void );
|
||||
void UI_RefreshServerList( void );
|
||||
int UI_CreditsActive( void );
|
||||
void UI_DrawFinalCredits( void );
|
||||
|
@ -420,6 +421,7 @@ void UI_SaveGame_Precache( void );
|
|||
void UI_SaveLoad_Precache( void );
|
||||
void UI_MultiPlayer_Precache( void );
|
||||
void UI_Options_Precache( void );
|
||||
void UI_InternetGames_Precache( void );
|
||||
void UI_LanGame_Precache( void );
|
||||
void UI_PlayerSetup_Precache( void );
|
||||
void UI_Controls_Precache( void );
|
||||
|
@ -442,6 +444,7 @@ void UI_SaveGame_Menu( void );
|
|||
void UI_SaveLoad_Menu( void );
|
||||
void UI_MultiPlayer_Menu( void );
|
||||
void UI_Options_Menu( void );
|
||||
void UI_InternetGames_Menu( void );
|
||||
void UI_LanGame_Menu( void );
|
||||
void UI_PlayerSetup_Menu( void );
|
||||
void UI_Controls_Menu( void );
|
||||
|
|
|
@ -154,6 +154,10 @@ SOURCE=.\menu_gameoptions.cpp
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\menu_internetgames.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\menu_langame.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -186,6 +190,10 @@ SOURCE=.\menu_saveload.cpp
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\menu_strings.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\menu_video.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -226,11 +234,15 @@ SOURCE=.\extdll.h
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\images.h
|
||||
SOURCE=.\menu_btnsbmp_table.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\menu_btnsbmp_table.h
|
||||
SOURCE=.\menu_strings.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\menufont.H
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "utils.h"
|
||||
#include "../cl_dll/kbutton.h"
|
||||
#include "menu_btnsbmp_table.h"
|
||||
#include "menu_strings.h"
|
||||
|
||||
#define ART_BANNER "gfx/shell/head_advanced"
|
||||
|
||||
|
@ -233,7 +234,7 @@ static void UI_AdvControls_Init( void )
|
|||
uiAdvControls.invertMouse.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_NOTIFY|QMF_ACT_ONRELEASE|QMF_MOUSEONLY|QMF_DROPSHADOW;
|
||||
uiAdvControls.invertMouse.generic.x = 72;
|
||||
uiAdvControls.invertMouse.generic.y = 280;
|
||||
uiAdvControls.invertMouse.generic.name = "Reverse mouse";
|
||||
uiAdvControls.invertMouse.generic.name = MenuStrings[HINT_REVERSE_MOUSE];
|
||||
uiAdvControls.invertMouse.generic.callback = UI_AdvControls_Callback;
|
||||
uiAdvControls.invertMouse.generic.statusText = "Reverse mouse up/down axis";
|
||||
|
||||
|
@ -285,7 +286,7 @@ static void UI_AdvControls_Init( void )
|
|||
uiAdvControls.sensitivity.generic.id = ID_SENSITIVITY;
|
||||
uiAdvControls.sensitivity.generic.type = QMTYPE_SLIDER;
|
||||
uiAdvControls.sensitivity.generic.flags = QMF_PULSEIFFOCUS|QMF_DROPSHADOW;
|
||||
uiAdvControls.sensitivity.generic.name = "Mouse sensitivity";
|
||||
uiAdvControls.sensitivity.generic.name = MenuStrings[HINT_MOUSE_SENSE];
|
||||
uiAdvControls.sensitivity.generic.x = 72;
|
||||
uiAdvControls.sensitivity.generic.y = 625;
|
||||
uiAdvControls.sensitivity.generic.callback = UI_AdvControls_Callback;
|
||||
|
|
|
@ -25,7 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
#define ART_BUTTONS_MAIN "gfx/shell/btns_main.bmp" // we support bmp only
|
||||
|
||||
const char *MenuStrings[PC_BUTTONCOUNT] =
|
||||
const char *MenuButtons[PC_BUTTONCOUNT] =
|
||||
{
|
||||
"New game",
|
||||
"Resume Game",
|
||||
|
@ -143,21 +143,21 @@ void UI_LoadBmpButtons( void )
|
|||
|
||||
int pallete_sz = pHdr->bmp_offset - sizeof( bmphdr_t ) - pInfoHdr->biSize;
|
||||
|
||||
uiStatic.buttons_height = 78;
|
||||
uiStatic.buttons_height = ( pInfoHdr->biBitCount == 4 ) ? 80 : 78; // bugstompers issues
|
||||
uiStatic.buttons_width = pInfoHdr->biWidth - 3; // make some offset
|
||||
|
||||
int cutted_img_sz = pInfoHdr->biWidth * uiStatic.buttons_height * pInfoHdr->biBitCount / 8;
|
||||
int CuttedBmpSize = sizeof( bmphdr_t ) + pInfoHdr->biSize + pallete_sz + cutted_img_sz;
|
||||
byte *img_data = &bmp_buffer[bmp_len_holder-cutted_img_sz];
|
||||
|
||||
if ( pInfoHdr->biBitCount == 8 )
|
||||
if ( pInfoHdr->biBitCount <= 8 )
|
||||
{
|
||||
byte*pallete=&bmp_buffer[sizeof( bmphdr_t ) + pInfoHdr->biSize];
|
||||
byte*firstpixel_col=&pallete[img_data[0]*4];
|
||||
byte* pallete=&bmp_buffer[sizeof( bmphdr_t ) + pInfoHdr->biSize];
|
||||
byte* firstpixel_col=&pallete[img_data[0]*4];
|
||||
firstpixel_col[0]=firstpixel_col[1]=firstpixel_col[2]=0;
|
||||
}
|
||||
|
||||
CuttedDibHdr.biHeight = uiStatic.buttons_height;
|
||||
CuttedDibHdr.biHeight = 78; //uiStatic.buttons_height;
|
||||
CuttedHdr.filesz = CuttedBmpSize;
|
||||
CuttedDibHdr.biSizeImage = CuttedBmpSize - CuttedHdr.bmp_offset;
|
||||
|
||||
|
@ -178,7 +178,7 @@ void UI_LoadBmpButtons( void )
|
|||
memcpy( &raw_img_buff[offset], &CuttedDibHdr, CuttedDibHdr.biSize );
|
||||
offset += CuttedDibHdr.biSize;
|
||||
|
||||
if( CuttedDibHdr.biBitCount == 8 )
|
||||
if( CuttedDibHdr.biBitCount <= 8 )
|
||||
{
|
||||
memcpy( &raw_img_buff[offset], &bmp_buffer[offset], pallete_sz );
|
||||
offset += pallete_sz;
|
||||
|
|
|
@ -96,14 +96,14 @@ enum
|
|||
#define BUTTON_FOCUS 1
|
||||
#define BUTTON_PRESSED 2
|
||||
|
||||
extern const char *MenuStrings[PC_BUTTONCOUNT];
|
||||
extern const char *MenuButtons[PC_BUTTONCOUNT];
|
||||
|
||||
inline int PicButtonWidth( int pic_id )
|
||||
{
|
||||
if( pic_id < 0 || pic_id > PC_BUTTONCOUNT )
|
||||
return 0;
|
||||
|
||||
return strlen( MenuStrings[pic_id] );
|
||||
return strlen( MenuButtons[pic_id] );
|
||||
}
|
||||
|
||||
#endif//MENU_BTNSBMP_TABLE_H
|
|
@ -0,0 +1,467 @@
|
|||
/*
|
||||
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 "extdll.h"
|
||||
#include "basemenu.h"
|
||||
#include "utils.h"
|
||||
#include "keydefs.h"
|
||||
#include "menu_btnsbmp_table.h"
|
||||
|
||||
#define ART_BANNER "gfx/shell/head_inetgames"
|
||||
|
||||
#define ID_BACKGROUND 0
|
||||
#define ID_BANNER 1
|
||||
#define ID_JOINGAME 2
|
||||
#define ID_CREATEGAME 3
|
||||
#define ID_GAMEINFO 4
|
||||
#define ID_REFRESH 5
|
||||
#define ID_DONE 6
|
||||
#define ID_SERVERSLIST 7
|
||||
#define ID_TABLEHINT 8
|
||||
|
||||
#define ID_MSGBOX 9
|
||||
#define ID_MSGTEXT 10
|
||||
#define ID_YES 130
|
||||
#define ID_NO 131
|
||||
|
||||
#define GAME_LENGTH 18
|
||||
#define MAPNAME_LENGTH 20+GAME_LENGTH
|
||||
#define TYPE_LENGTH 16+MAPNAME_LENGTH
|
||||
#define MAXCL_LENGTH 15+TYPE_LENGTH
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char gameDescription[UI_MAX_SERVERS][256];
|
||||
char *gameDescriptionPtr[UI_MAX_SERVERS];
|
||||
|
||||
menuFramework_s menu;
|
||||
|
||||
menuBitmap_s background;
|
||||
menuBitmap_s banner;
|
||||
menuPicButton_s joinGame;
|
||||
menuPicButton_s createGame;
|
||||
menuPicButton_s gameInfo;
|
||||
menuPicButton_s refresh;
|
||||
menuPicButton_s done;
|
||||
|
||||
// joingame prompt dialog
|
||||
menuAction_s msgBox;
|
||||
menuAction_s dlgMessage1;
|
||||
menuAction_s dlgMessage2;
|
||||
menuPicButton_s yes;
|
||||
menuPicButton_s no;
|
||||
|
||||
menuScrollList_s gameList;
|
||||
menuAction_s hintMessage;
|
||||
char hintText[MAX_HINT_TEXT];
|
||||
int refreshTime;
|
||||
} uiInternetGames_t;
|
||||
|
||||
static uiInternetGames_t uiInternetGames;
|
||||
|
||||
static void UI_PromptDialog( void )
|
||||
{
|
||||
// toggle main menu between active\inactive
|
||||
// show\hide quit dialog
|
||||
uiInternetGames.joinGame.generic.flags ^= QMF_INACTIVE;
|
||||
uiInternetGames.createGame.generic.flags ^= QMF_INACTIVE;
|
||||
uiInternetGames.gameInfo.generic.flags ^= QMF_INACTIVE;
|
||||
uiInternetGames.refresh.generic.flags ^= QMF_INACTIVE;
|
||||
uiInternetGames.done.generic.flags ^= QMF_INACTIVE;
|
||||
uiInternetGames.gameList.generic.flags ^= QMF_INACTIVE;
|
||||
|
||||
uiInternetGames.msgBox.generic.flags ^= QMF_HIDDEN;
|
||||
uiInternetGames.dlgMessage1.generic.flags ^= QMF_HIDDEN;
|
||||
uiInternetGames.dlgMessage2.generic.flags ^= QMF_HIDDEN;
|
||||
uiInternetGames.no.generic.flags ^= QMF_HIDDEN;
|
||||
uiInternetGames.yes.generic.flags ^= QMF_HIDDEN;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
UI_InternetGames_KeyFunc
|
||||
=================
|
||||
*/
|
||||
static const char *UI_InternetGames_KeyFunc( int key, int down )
|
||||
{
|
||||
if( down && key == K_ESCAPE && !( uiInternetGames.dlgMessage1.generic.flags & QMF_HIDDEN ))
|
||||
{
|
||||
UI_PromptDialog();
|
||||
return uiSoundNull;
|
||||
}
|
||||
return UI_DefaultKey( &uiInternetGames.menu, key, down );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
UI_InternetGames_GetGamesList
|
||||
=================
|
||||
*/
|
||||
static void UI_InternetGames_GetGamesList( void )
|
||||
{
|
||||
int i;
|
||||
const char *info;
|
||||
|
||||
for( i = 0; i < uiStatic.numServers; i++ )
|
||||
{
|
||||
if( i >= UI_MAX_SERVERS ) break;
|
||||
info = uiStatic.serverNames[i];
|
||||
#if 1
|
||||
// NOTE: Xash3D is support hot switching between games in multiplayer
|
||||
// but this feature not detail tested and may be bugly
|
||||
if( stricmp( gMenu.m_gameinfo.gamefolder, Info_ValueForKey( info, "gamedir" )))
|
||||
continue; // filter by game
|
||||
#endif
|
||||
StringConcat( uiInternetGames.gameDescription[i], Info_ValueForKey( info, "host" ), GAME_LENGTH );
|
||||
StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, GAME_LENGTH );
|
||||
StringConcat( uiInternetGames.gameDescription[i], Info_ValueForKey( info, "map" ), MAPNAME_LENGTH );
|
||||
StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, MAPNAME_LENGTH );
|
||||
if( !strcmp( Info_ValueForKey( info, "dm" ), "1" ))
|
||||
StringConcat( uiInternetGames.gameDescription[i], "deathmatch", TYPE_LENGTH );
|
||||
else if( !strcmp( Info_ValueForKey( info, "coop" ), "1" ))
|
||||
StringConcat( uiInternetGames.gameDescription[i], "coop", TYPE_LENGTH );
|
||||
else if( !strcmp( Info_ValueForKey( info, "team" ), "1" ))
|
||||
StringConcat( uiInternetGames.gameDescription[i], "teamplay", TYPE_LENGTH );
|
||||
StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, TYPE_LENGTH );
|
||||
StringConcat( uiInternetGames.gameDescription[i], Info_ValueForKey( info, "numcl" ), MAXCL_LENGTH );
|
||||
StringConcat( uiInternetGames.gameDescription[i], "\\", MAXCL_LENGTH );
|
||||
StringConcat( uiInternetGames.gameDescription[i], Info_ValueForKey( info, "maxcl" ), MAXCL_LENGTH );
|
||||
StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, MAXCL_LENGTH );
|
||||
uiInternetGames.gameDescriptionPtr[i] = uiInternetGames.gameDescription[i];
|
||||
}
|
||||
|
||||
for( ; i < UI_MAX_SERVERS; i++ )
|
||||
uiInternetGames.gameDescriptionPtr[i] = NULL;
|
||||
|
||||
uiInternetGames.gameList.itemNames = (const char **)uiInternetGames.gameDescriptionPtr;
|
||||
uiInternetGames.gameList.numItems = 0; // reset it
|
||||
|
||||
if( !uiInternetGames.gameList.generic.charHeight )
|
||||
return; // to avoid divide integer by zero
|
||||
|
||||
// count number of items
|
||||
while( uiInternetGames.gameList.itemNames[uiInternetGames.gameList.numItems] )
|
||||
uiInternetGames.gameList.numItems++;
|
||||
|
||||
// calculate number of visible rows
|
||||
uiInternetGames.gameList.numRows = (uiInternetGames.gameList.generic.height2 / uiInternetGames.gameList.generic.charHeight) - 2;
|
||||
if( uiInternetGames.gameList.numRows > uiInternetGames.gameList.numItems ) uiInternetGames.gameList.numRows = uiInternetGames.gameList.numItems;
|
||||
|
||||
if( uiStatic.numServers )
|
||||
uiInternetGames.joinGame.generic.flags &= ~QMF_GRAYED;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
UI_InternetGames_JoinGame
|
||||
=================
|
||||
*/
|
||||
static void UI_InternetGames_JoinGame( void )
|
||||
{
|
||||
if( !strlen( uiInternetGames.gameDescription[uiInternetGames.gameList.curItem] ))
|
||||
return;
|
||||
|
||||
CLIENT_JOIN( uiStatic.serverAddresses[uiInternetGames.gameList.curItem] );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
UI_Background_Ownerdraw
|
||||
=================
|
||||
*/
|
||||
static void UI_Background_Ownerdraw( void *self )
|
||||
{
|
||||
menuCommon_s *item = (menuCommon_s *)self;
|
||||
|
||||
if( !CVAR_GET_FLOAT( "sv_background" ))
|
||||
UI_DrawPic(item->x, item->y, item->width, item->height, uiColorWhite, ((menuBitmap_s *)self)->pic);
|
||||
|
||||
if( uiStatic.realTime > uiInternetGames.refreshTime )
|
||||
{
|
||||
uiInternetGames.refreshTime = uiStatic.realTime + 10000; // refresh every 10 secs
|
||||
UI_RefreshInternetServerList();
|
||||
}
|
||||
|
||||
// serverinfo has been changed update display
|
||||
if( uiStatic.updateServers )
|
||||
{
|
||||
UI_InternetGames_GetGamesList ();
|
||||
uiStatic.updateServers = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
UI_MsgBox_Ownerdraw
|
||||
=================
|
||||
*/
|
||||
static void UI_MsgBox_Ownerdraw( void *self )
|
||||
{
|
||||
menuCommon_s *item = (menuCommon_s *)self;
|
||||
|
||||
UI_FillRect( item->x, item->y, item->width, item->height, uiPromptBgColor );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
UI_InternetGames_Callback
|
||||
=================
|
||||
*/
|
||||
static void UI_InternetGames_Callback( void *self, int event )
|
||||
{
|
||||
menuCommon_s *item = (menuCommon_s *)self;
|
||||
|
||||
if( event != QM_ACTIVATED )
|
||||
return;
|
||||
|
||||
switch( item->id )
|
||||
{
|
||||
case ID_JOINGAME:
|
||||
if( CL_IsActive( ))
|
||||
UI_PromptDialog();
|
||||
else UI_InternetGames_JoinGame();
|
||||
break;
|
||||
case ID_CREATEGAME:
|
||||
CVAR_SET_FLOAT( "public", 1.0f );
|
||||
UI_CreateGame_Menu();
|
||||
break;
|
||||
case ID_GAMEINFO:
|
||||
// UNDONE: not implemented
|
||||
break;
|
||||
case ID_REFRESH:
|
||||
UI_RefreshInternetServerList();
|
||||
break;
|
||||
case ID_DONE:
|
||||
UI_PopMenu();
|
||||
break;
|
||||
case ID_YES:
|
||||
UI_InternetGames_JoinGame();
|
||||
break;
|
||||
case ID_NO:
|
||||
UI_PromptDialog();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
UI_InternetGames_Init
|
||||
=================
|
||||
*/
|
||||
static void UI_InternetGames_Init( void )
|
||||
{
|
||||
memset( &uiInternetGames, 0, sizeof( uiInternetGames_t ));
|
||||
|
||||
uiInternetGames.menu.vidInitFunc = UI_InternetGames_Init;
|
||||
uiInternetGames.menu.keyFunc = UI_InternetGames_KeyFunc;
|
||||
|
||||
StringConcat( uiInternetGames.hintText, "Game", GAME_LENGTH );
|
||||
StringConcat( uiInternetGames.hintText, uiEmptyString, GAME_LENGTH );
|
||||
StringConcat( uiInternetGames.hintText, "Map", MAPNAME_LENGTH );
|
||||
StringConcat( uiInternetGames.hintText, uiEmptyString, MAPNAME_LENGTH );
|
||||
StringConcat( uiInternetGames.hintText, "Type", TYPE_LENGTH );
|
||||
StringConcat( uiInternetGames.hintText, uiEmptyString, TYPE_LENGTH );
|
||||
StringConcat( uiInternetGames.hintText, "Num/Max Clients", MAXCL_LENGTH );
|
||||
StringConcat( uiInternetGames.hintText, uiEmptyString, MAXCL_LENGTH );
|
||||
|
||||
uiInternetGames.background.generic.id = ID_BACKGROUND;
|
||||
uiInternetGames.background.generic.type = QMTYPE_BITMAP;
|
||||
uiInternetGames.background.generic.flags = QMF_INACTIVE;
|
||||
uiInternetGames.background.generic.x = 0;
|
||||
uiInternetGames.background.generic.y = 0;
|
||||
uiInternetGames.background.generic.width = 1024;
|
||||
uiInternetGames.background.generic.height = 768;
|
||||
uiInternetGames.background.pic = ART_BACKGROUND;
|
||||
uiInternetGames.background.generic.ownerdraw = UI_Background_Ownerdraw;
|
||||
|
||||
uiInternetGames.banner.generic.id = ID_BANNER;
|
||||
uiInternetGames.banner.generic.type = QMTYPE_BITMAP;
|
||||
uiInternetGames.banner.generic.flags = QMF_INACTIVE|QMF_DRAW_ADDITIVE;
|
||||
uiInternetGames.banner.generic.x = UI_BANNER_POSX;
|
||||
uiInternetGames.banner.generic.y = UI_BANNER_POSY;
|
||||
uiInternetGames.banner.generic.width = UI_BANNER_WIDTH;
|
||||
uiInternetGames.banner.generic.height = UI_BANNER_HEIGHT;
|
||||
uiInternetGames.banner.pic = ART_BANNER;
|
||||
|
||||
uiInternetGames.joinGame.generic.id = ID_JOINGAME;
|
||||
uiInternetGames.joinGame.generic.type = QMTYPE_BM_BUTTON;
|
||||
uiInternetGames.joinGame.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW|QMF_GRAYED;
|
||||
uiInternetGames.joinGame.generic.x = 72;
|
||||
uiInternetGames.joinGame.generic.y = 230;
|
||||
uiInternetGames.joinGame.generic.name = "Join game";
|
||||
uiInternetGames.joinGame.generic.statusText = "Join to selected game";
|
||||
uiInternetGames.joinGame.generic.callback = UI_InternetGames_Callback;
|
||||
|
||||
UI_UtilSetupPicButton( &uiInternetGames.joinGame, PC_JOIN_GAME );
|
||||
|
||||
uiInternetGames.createGame.generic.id = ID_CREATEGAME;
|
||||
uiInternetGames.createGame.generic.type = QMTYPE_BM_BUTTON;
|
||||
uiInternetGames.createGame.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW;
|
||||
uiInternetGames.createGame.generic.x = 72;
|
||||
uiInternetGames.createGame.generic.y = 280;
|
||||
uiInternetGames.createGame.generic.name = "Create game";
|
||||
uiInternetGames.createGame.generic.statusText = "Create new Internet game";
|
||||
uiInternetGames.createGame.generic.callback = UI_InternetGames_Callback;
|
||||
|
||||
UI_UtilSetupPicButton( &uiInternetGames.createGame, PC_CREATE_GAME );
|
||||
|
||||
uiInternetGames.gameInfo.generic.id = ID_GAMEINFO;
|
||||
uiInternetGames.gameInfo.generic.type = QMTYPE_BM_BUTTON;
|
||||
uiInternetGames.gameInfo.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW|QMF_GRAYED;
|
||||
uiInternetGames.gameInfo.generic.x = 72;
|
||||
uiInternetGames.gameInfo.generic.y = 330;
|
||||
uiInternetGames.gameInfo.generic.name = "View game info";
|
||||
uiInternetGames.gameInfo.generic.statusText = "Get detail game info";
|
||||
uiInternetGames.gameInfo.generic.callback = UI_InternetGames_Callback;
|
||||
|
||||
UI_UtilSetupPicButton( &uiInternetGames.gameInfo, PC_VIEW_GAME_INFO );
|
||||
|
||||
uiInternetGames.refresh.generic.id = ID_REFRESH;
|
||||
uiInternetGames.refresh.generic.type = QMTYPE_BM_BUTTON;
|
||||
uiInternetGames.refresh.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW;
|
||||
uiInternetGames.refresh.generic.x = 72;
|
||||
uiInternetGames.refresh.generic.y = 380;
|
||||
uiInternetGames.refresh.generic.name = "Refresh";
|
||||
uiInternetGames.refresh.generic.statusText = "Refresh servers list";
|
||||
uiInternetGames.refresh.generic.callback = UI_InternetGames_Callback;
|
||||
|
||||
UI_UtilSetupPicButton( &uiInternetGames.refresh, PC_REFRESH );
|
||||
|
||||
uiInternetGames.done.generic.id = ID_DONE;
|
||||
uiInternetGames.done.generic.type = QMTYPE_BM_BUTTON;
|
||||
uiInternetGames.done.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW;
|
||||
uiInternetGames.done.generic.x = 72;
|
||||
uiInternetGames.done.generic.y = 430;
|
||||
uiInternetGames.done.generic.name = "Done";
|
||||
uiInternetGames.done.generic.statusText = "Return to main menu";
|
||||
uiInternetGames.done.generic.callback = UI_InternetGames_Callback;
|
||||
|
||||
UI_UtilSetupPicButton( &uiInternetGames.done, PC_DONE );
|
||||
|
||||
uiInternetGames.msgBox.generic.id = ID_MSGBOX;
|
||||
uiInternetGames.msgBox.generic.type = QMTYPE_ACTION;
|
||||
uiInternetGames.msgBox.generic.flags = QMF_INACTIVE|QMF_HIDDEN;
|
||||
uiInternetGames.msgBox.generic.ownerdraw = UI_MsgBox_Ownerdraw; // just a fill rectangle
|
||||
uiInternetGames.msgBox.generic.x = 192;
|
||||
uiInternetGames.msgBox.generic.y = 256;
|
||||
uiInternetGames.msgBox.generic.width = 640;
|
||||
uiInternetGames.msgBox.generic.height = 256;
|
||||
|
||||
uiInternetGames.dlgMessage1.generic.id = ID_MSGTEXT;
|
||||
uiInternetGames.dlgMessage1.generic.type = QMTYPE_ACTION;
|
||||
uiInternetGames.dlgMessage1.generic.flags = QMF_INACTIVE|QMF_HIDDEN|QMF_DROPSHADOW;
|
||||
uiInternetGames.dlgMessage1.generic.name = "Join a network game will exit";
|
||||
uiInternetGames.dlgMessage1.generic.x = 248;
|
||||
uiInternetGames.dlgMessage1.generic.y = 280;
|
||||
|
||||
uiInternetGames.dlgMessage2.generic.id = ID_MSGTEXT;
|
||||
uiInternetGames.dlgMessage2.generic.type = QMTYPE_ACTION;
|
||||
uiInternetGames.dlgMessage2.generic.flags = QMF_INACTIVE|QMF_HIDDEN|QMF_DROPSHADOW;
|
||||
uiInternetGames.dlgMessage2.generic.name = "any current game, OK to exit?";
|
||||
uiInternetGames.dlgMessage2.generic.x = 248;
|
||||
uiInternetGames.dlgMessage2.generic.y = 310;
|
||||
|
||||
uiInternetGames.yes.generic.id = ID_YES;
|
||||
uiInternetGames.yes.generic.type = QMTYPE_BM_BUTTON;
|
||||
uiInternetGames.yes.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_HIDDEN|QMF_DROPSHADOW;
|
||||
uiInternetGames.yes.generic.name = "Ok";
|
||||
uiInternetGames.yes.generic.x = 380;
|
||||
uiInternetGames.yes.generic.y = 460;
|
||||
uiInternetGames.yes.generic.callback = UI_InternetGames_Callback;
|
||||
|
||||
UI_UtilSetupPicButton( &uiInternetGames.yes, PC_OK );
|
||||
|
||||
uiInternetGames.no.generic.id = ID_NO;
|
||||
uiInternetGames.no.generic.type = QMTYPE_BM_BUTTON;
|
||||
uiInternetGames.no.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_HIDDEN|QMF_DROPSHADOW;
|
||||
uiInternetGames.no.generic.name = "Cancel";
|
||||
uiInternetGames.no.generic.x = 530;
|
||||
uiInternetGames.no.generic.y = 460;
|
||||
uiInternetGames.no.generic.callback = UI_InternetGames_Callback;
|
||||
|
||||
UI_UtilSetupPicButton( &uiInternetGames.no, PC_CANCEL );
|
||||
|
||||
uiInternetGames.hintMessage.generic.id = ID_TABLEHINT;
|
||||
uiInternetGames.hintMessage.generic.type = QMTYPE_ACTION;
|
||||
uiInternetGames.hintMessage.generic.flags = QMF_INACTIVE|QMF_SMALLFONT;
|
||||
uiInternetGames.hintMessage.generic.color = uiColorHelp;
|
||||
uiInternetGames.hintMessage.generic.name = uiInternetGames.hintText;
|
||||
uiInternetGames.hintMessage.generic.x = 360;
|
||||
uiInternetGames.hintMessage.generic.y = 225;
|
||||
|
||||
uiInternetGames.gameList.generic.id = ID_SERVERSLIST;
|
||||
uiInternetGames.gameList.generic.type = QMTYPE_SCROLLLIST;
|
||||
uiInternetGames.gameList.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_SMALLFONT;
|
||||
uiInternetGames.gameList.generic.x = 360;
|
||||
uiInternetGames.gameList.generic.y = 255;
|
||||
uiInternetGames.gameList.generic.width = 640;
|
||||
uiInternetGames.gameList.generic.height = 440;
|
||||
uiInternetGames.gameList.generic.callback = UI_InternetGames_Callback;
|
||||
uiInternetGames.gameList.itemNames = (const char **)uiInternetGames.gameDescriptionPtr;
|
||||
|
||||
// server.dll needs for reading savefiles or startup newgame
|
||||
if( !CheckGameDll( ))
|
||||
uiInternetGames.createGame.generic.flags |= QMF_GRAYED; // server.dll is missed - remote servers only
|
||||
|
||||
UI_AddItem( &uiInternetGames.menu, (void *)&uiInternetGames.background );
|
||||
UI_AddItem( &uiInternetGames.menu, (void *)&uiInternetGames.banner );
|
||||
UI_AddItem( &uiInternetGames.menu, (void *)&uiInternetGames.joinGame );
|
||||
UI_AddItem( &uiInternetGames.menu, (void *)&uiInternetGames.createGame );
|
||||
UI_AddItem( &uiInternetGames.menu, (void *)&uiInternetGames.gameInfo );
|
||||
UI_AddItem( &uiInternetGames.menu, (void *)&uiInternetGames.refresh );
|
||||
UI_AddItem( &uiInternetGames.menu, (void *)&uiInternetGames.done );
|
||||
UI_AddItem( &uiInternetGames.menu, (void *)&uiInternetGames.hintMessage );
|
||||
UI_AddItem( &uiInternetGames.menu, (void *)&uiInternetGames.gameList );
|
||||
UI_AddItem( &uiInternetGames.menu, (void *)&uiInternetGames.msgBox );
|
||||
UI_AddItem( &uiInternetGames.menu, (void *)&uiInternetGames.dlgMessage1 );
|
||||
UI_AddItem( &uiInternetGames.menu, (void *)&uiInternetGames.dlgMessage2 );
|
||||
UI_AddItem( &uiInternetGames.menu, (void *)&uiInternetGames.no );
|
||||
UI_AddItem( &uiInternetGames.menu, (void *)&uiInternetGames.yes );
|
||||
|
||||
uiInternetGames.refreshTime = uiStatic.realTime + 500; // delay before update 0.5 sec
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
UI_InternetGames_Precache
|
||||
=================
|
||||
*/
|
||||
void UI_InternetGames_Precache( void )
|
||||
{
|
||||
PIC_Load( ART_BACKGROUND );
|
||||
PIC_Load( ART_BANNER );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
UI_InternetGames_Menu
|
||||
=================
|
||||
*/
|
||||
void UI_InternetGames_Menu( void )
|
||||
{
|
||||
if ( gMenu.m_gameinfo.gamemode == GAME_SINGLEPLAYER_ONLY )
|
||||
return;
|
||||
|
||||
UI_InternetGames_Precache();
|
||||
UI_InternetGames_Init();
|
||||
|
||||
UI_PushMenu( &uiInternetGames.menu );
|
||||
}
|
|
@ -240,6 +240,7 @@ static void UI_LanGame_Callback( void *self, int event )
|
|||
else UI_LanGame_JoinGame();
|
||||
break;
|
||||
case ID_CREATEGAME:
|
||||
CVAR_SET_FLOAT( "public", 0.0f );
|
||||
UI_CreateGame_Menu();
|
||||
break;
|
||||
case ID_GAMEINFO:
|
||||
|
|
|
@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "utils.h"
|
||||
#include "keydefs.h"
|
||||
#include "menu_btnsbmp_table.h"
|
||||
#include "menu_strings.h"
|
||||
|
||||
#define ART_MINIMIZE_N "gfx/shell/min_n"
|
||||
#define ART_MINIMIZE_F "gfx/shell/min_f"
|
||||
|
@ -40,7 +41,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#define ID_SAVERESTORE 6
|
||||
#define ID_MULTIPLAYER 7
|
||||
#define ID_CUSTOMGAME 8
|
||||
#define ID_CREDITS 9
|
||||
#define ID_PREVIEWS 9
|
||||
#define ID_QUIT 10
|
||||
#define ID_QUIT_BUTTON 11
|
||||
#define ID_MINIMIZE 12
|
||||
|
@ -62,7 +63,7 @@ typedef struct
|
|||
menuPicButton_s saveRestore;
|
||||
menuPicButton_s multiPlayer;
|
||||
menuPicButton_s customGame;
|
||||
menuPicButton_s credits;
|
||||
menuPicButton_s previews;
|
||||
menuPicButton_s quit;
|
||||
|
||||
menuBitmap_s minimizeBtn;
|
||||
|
@ -72,7 +73,6 @@ typedef struct
|
|||
menuAction_s msgBox;
|
||||
menuAction_s quitMessage;
|
||||
menuAction_s dlgMessage1;
|
||||
menuAction_s dlgMessage2;
|
||||
menuPicButton_s yes;
|
||||
menuPicButton_s no;
|
||||
} uiMain_t;
|
||||
|
@ -133,7 +133,7 @@ static void UI_QuitDialog( void )
|
|||
uiMain.configuration.generic.flags ^= QMF_INACTIVE;
|
||||
uiMain.multiPlayer.generic.flags ^= QMF_INACTIVE;
|
||||
uiMain.customGame.generic.flags ^= QMF_INACTIVE;
|
||||
uiMain.credits.generic.flags ^= QMF_INACTIVE;
|
||||
uiMain.previews.generic.flags ^= QMF_INACTIVE;
|
||||
uiMain.quit.generic.flags ^= QMF_INACTIVE;
|
||||
uiMain.minimizeBtn.generic.flags ^= QMF_INACTIVE;
|
||||
uiMain.quitButton.generic.flags ^= QMF_INACTIVE;
|
||||
|
@ -157,14 +157,13 @@ static void UI_PromptDialog( void )
|
|||
uiMain.configuration.generic.flags ^= QMF_INACTIVE;
|
||||
uiMain.multiPlayer.generic.flags ^= QMF_INACTIVE;
|
||||
uiMain.customGame.generic.flags ^= QMF_INACTIVE;
|
||||
uiMain.credits.generic.flags ^= QMF_INACTIVE;
|
||||
uiMain.previews.generic.flags ^= QMF_INACTIVE;
|
||||
uiMain.quit.generic.flags ^= QMF_INACTIVE;
|
||||
uiMain.minimizeBtn.generic.flags ^= QMF_INACTIVE;
|
||||
uiMain.quitButton.generic.flags ^= QMF_INACTIVE;
|
||||
|
||||
uiMain.msgBox.generic.flags ^= QMF_HIDDEN;
|
||||
uiMain.dlgMessage1.generic.flags ^= QMF_HIDDEN;
|
||||
uiMain.dlgMessage2.generic.flags ^= QMF_HIDDEN;
|
||||
uiMain.no.generic.flags ^= QMF_HIDDEN;
|
||||
uiMain.yes.generic.flags ^= QMF_HIDDEN;
|
||||
|
||||
|
@ -220,7 +219,7 @@ static void UI_Main_HazardCourse( void )
|
|||
if( CVAR_GET_FLOAT( "host_serverstate" ) && CVAR_GET_FLOAT( "maxplayers" ) > 1 )
|
||||
HOST_ENDGAME( "end of the game" );
|
||||
|
||||
CVAR_SET_FLOAT( "skill", 0.0f );
|
||||
CVAR_SET_FLOAT( "skill", 1.0f );
|
||||
CVAR_SET_FLOAT( "deathmatch", 0.0f );
|
||||
CVAR_SET_FLOAT( "teamplay", 0.0f );
|
||||
CVAR_SET_FLOAT( "pausable", 1.0f ); // singleplayer is always allowing pause
|
||||
|
@ -286,8 +285,8 @@ static void UI_Main_Callback( void *self, int event )
|
|||
case ID_CUSTOMGAME:
|
||||
UI_CustomGame_Menu();
|
||||
break;
|
||||
case ID_CREDITS:
|
||||
UI_Credits_Menu();
|
||||
case ID_PREVIEWS:
|
||||
SHELL_EXECUTE( MenuStrings[HINT_PREVIEWS_CMD], NULL, false );
|
||||
break;
|
||||
case ID_QUIT:
|
||||
case ID_QUIT_BUTTON:
|
||||
|
@ -361,7 +360,7 @@ static void UI_Main_Init( void )
|
|||
uiMain.resumeGame.generic.type = QMTYPE_BM_BUTTON;
|
||||
uiMain.resumeGame.generic.name = "Resume game";
|
||||
uiMain.resumeGame.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW|QMF_NOTIFY;
|
||||
uiMain.resumeGame.generic.statusText = "Return to game.";
|
||||
uiMain.resumeGame.generic.statusText = MenuStrings[HINT_RESUME_GAME];
|
||||
uiMain.resumeGame.generic.x = 72;
|
||||
uiMain.resumeGame.generic.y = 230;
|
||||
uiMain.resumeGame.generic.callback = UI_Main_Callback;
|
||||
|
@ -372,7 +371,7 @@ static void UI_Main_Init( void )
|
|||
uiMain.newGame.generic.type = QMTYPE_BM_BUTTON;
|
||||
uiMain.newGame.generic.name = "New game";
|
||||
uiMain.newGame.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW|QMF_NOTIFY;
|
||||
uiMain.newGame.generic.statusText = "Start a new game.";
|
||||
uiMain.newGame.generic.statusText = MenuStrings[HINT_NEWGAME];
|
||||
uiMain.newGame.generic.x = 72;
|
||||
uiMain.newGame.generic.y = 280;
|
||||
uiMain.newGame.generic.callback = UI_Main_Callback;
|
||||
|
@ -386,7 +385,7 @@ static void UI_Main_Init( void )
|
|||
uiMain.hazardCourse.generic.type = QMTYPE_BM_BUTTON;
|
||||
uiMain.hazardCourse.generic.name = "Hazard course";
|
||||
uiMain.hazardCourse.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW|QMF_NOTIFY;
|
||||
uiMain.hazardCourse.generic.statusText = "Learn how to play the game";
|
||||
uiMain.hazardCourse.generic.statusText = MenuStrings[HINT_HAZARD_COURSE];
|
||||
uiMain.hazardCourse.generic.x = 72;
|
||||
uiMain.hazardCourse.generic.y = 330;
|
||||
uiMain.hazardCourse.generic.callback = UI_Main_Callback;
|
||||
|
@ -408,13 +407,13 @@ static void UI_Main_Init( void )
|
|||
if( CL_IsActive( ))
|
||||
{
|
||||
uiMain.saveRestore.generic.name = "Save\\Load Game";
|
||||
uiMain.saveRestore.generic.statusText = "Load a saved game, save the current game.";
|
||||
uiMain.saveRestore.generic.statusText = MenuStrings[HINT_SAVELOADGAME];
|
||||
UI_UtilSetupPicButton(&uiMain.saveRestore,PC_SAVE_LOAD_GAME);
|
||||
}
|
||||
else
|
||||
{
|
||||
uiMain.saveRestore.generic.name = "Load Game";
|
||||
uiMain.saveRestore.generic.statusText = "Load a previously saved game.";
|
||||
uiMain.saveRestore.generic.statusText = MenuStrings[HINT_LOADGAME];
|
||||
uiMain.resumeGame.generic.flags |= QMF_HIDDEN;
|
||||
UI_UtilSetupPicButton( &uiMain.saveRestore, PC_LOAD_GAME );
|
||||
}
|
||||
|
@ -427,7 +426,7 @@ static void UI_Main_Init( void )
|
|||
uiMain.configuration.generic.type = QMTYPE_BM_BUTTON;
|
||||
uiMain.configuration.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW|QMF_NOTIFY;
|
||||
uiMain.configuration.generic.name = "Configuration";
|
||||
uiMain.configuration.generic.statusText = "Change game settings, configure controls";
|
||||
uiMain.configuration.generic.statusText = MenuStrings[HINT_CONFIGURATION];
|
||||
uiMain.configuration.generic.x = 72;
|
||||
uiMain.configuration.generic.y = bTrainMap ? 430 : 380;
|
||||
uiMain.configuration.generic.callback = UI_Main_Callback;
|
||||
|
@ -438,7 +437,7 @@ static void UI_Main_Init( void )
|
|||
uiMain.multiPlayer.generic.type = QMTYPE_BM_BUTTON;
|
||||
uiMain.multiPlayer.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW|QMF_NOTIFY;
|
||||
uiMain.multiPlayer.generic.name = "Multiplayer";
|
||||
uiMain.multiPlayer.generic.statusText = "Search for internet servers, configure character";
|
||||
uiMain.multiPlayer.generic.statusText = MenuStrings[HINT_MULTIPLAYER];
|
||||
uiMain.multiPlayer.generic.x = 72;
|
||||
uiMain.multiPlayer.generic.y = bTrainMap ? 480 : 430;
|
||||
uiMain.multiPlayer.generic.callback = UI_Main_Callback;
|
||||
|
@ -458,29 +457,33 @@ static void UI_Main_Init( void )
|
|||
uiMain.customGame.generic.type = QMTYPE_BM_BUTTON;
|
||||
uiMain.customGame.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW|QMF_NOTIFY;
|
||||
uiMain.customGame.generic.name = "Custom Game";
|
||||
uiMain.customGame.generic.statusText = "Select a custom game";
|
||||
uiMain.customGame.generic.statusText = MenuStrings[HINT_CUSTOM_GAME];
|
||||
uiMain.customGame.generic.x = 72;
|
||||
uiMain.customGame.generic.y = bTrainMap ? 530 : 480;
|
||||
uiMain.customGame.generic.callback = UI_Main_Callback;
|
||||
|
||||
UI_UtilSetupPicButton( &uiMain.customGame, PC_CUSTOM_GAME );
|
||||
|
||||
uiMain.credits.generic.id = ID_CREDITS;
|
||||
uiMain.credits.generic.type = QMTYPE_BM_BUTTON;
|
||||
uiMain.credits.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW|QMF_NOTIFY;
|
||||
uiMain.credits.generic.name = "About";
|
||||
uiMain.credits.generic.statusText = "Game credits";
|
||||
uiMain.credits.generic.x = 72;
|
||||
uiMain.credits.generic.y = (bCustomGame) ? (bTrainMap ? 580 : 530) : (bTrainMap ? 530 : 480);
|
||||
uiMain.credits.generic.callback = UI_Main_Callback;
|
||||
uiMain.previews.generic.id = ID_PREVIEWS;
|
||||
uiMain.previews.generic.type = QMTYPE_BM_BUTTON;
|
||||
uiMain.previews.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW|QMF_NOTIFY;
|
||||
uiMain.previews.generic.name = "Previews";
|
||||
uiMain.previews.generic.statusText = MenuStrings[HINT_PREVIEWS_TEXT];
|
||||
uiMain.previews.generic.x = 72;
|
||||
uiMain.previews.generic.y = (bCustomGame) ? (bTrainMap ? 580 : 530) : (bTrainMap ? 530 : 480);
|
||||
uiMain.previews.generic.callback = UI_Main_Callback;
|
||||
|
||||
UI_UtilSetupPicButton( &uiMain.credits, PC_VIEW_README );
|
||||
// too short execute string - not a real command
|
||||
if( strlen( MenuStrings[HINT_PREVIEWS_CMD] ) <= 3 )
|
||||
uiMain.previews.generic.flags |= QMF_GRAYED;
|
||||
|
||||
UI_UtilSetupPicButton( &uiMain.previews, PC_PREVIEWS );
|
||||
|
||||
uiMain.quit.generic.id = ID_QUIT;
|
||||
uiMain.quit.generic.type = QMTYPE_BM_BUTTON;
|
||||
uiMain.quit.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW|QMF_NOTIFY;
|
||||
uiMain.quit.generic.name = "Quit";
|
||||
uiMain.quit.generic.statusText = "Quit from game";
|
||||
uiMain.quit.generic.statusText = MenuStrings[HINT_QUIT_BUTTON];
|
||||
uiMain.quit.generic.x = 72;
|
||||
uiMain.quit.generic.y = (bCustomGame) ? (bTrainMap ? 630 : 580) : (bTrainMap ? 580 : 530);
|
||||
uiMain.quit.generic.callback = UI_Main_Callback;
|
||||
|
@ -520,24 +523,21 @@ static void UI_Main_Init( void )
|
|||
|
||||
uiMain.quitMessage.generic.id = ID_MSGBOX;
|
||||
uiMain.quitMessage.generic.type = QMTYPE_ACTION;
|
||||
uiMain.quitMessage.generic.flags = QMF_INACTIVE|QMF_DROPSHADOW|QMF_HIDDEN;
|
||||
uiMain.quitMessage.generic.name = "Are you sure you want to quit?";
|
||||
uiMain.quitMessage.generic.x = 248;
|
||||
uiMain.quitMessage.generic.flags = QMF_INACTIVE|QMF_DROPSHADOW|QMF_HIDDEN|QMF_CENTER_JUSTIFY;
|
||||
uiMain.quitMessage.generic.name = (CL_IsActive( )) ? MenuStrings[HINT_QUIT_ACTIVE] : MenuStrings[HINT_QUIT];
|
||||
uiMain.quitMessage.generic.x = 192;
|
||||
uiMain.quitMessage.generic.y = 280;
|
||||
uiMain.quitMessage.generic.width = 640;
|
||||
uiMain.quitMessage.generic.height = 256;
|
||||
|
||||
uiMain.dlgMessage1.generic.id = ID_MSGTEXT;
|
||||
uiMain.dlgMessage1.generic.type = QMTYPE_ACTION;
|
||||
uiMain.dlgMessage1.generic.flags = QMF_INACTIVE|QMF_DROPSHADOW|QMF_HIDDEN;
|
||||
uiMain.dlgMessage1.generic.name = "Starting a Hazard Course will exit";
|
||||
uiMain.dlgMessage1.generic.x = 212;
|
||||
uiMain.dlgMessage1.generic.flags = QMF_INACTIVE|QMF_DROPSHADOW|QMF_HIDDEN|QMF_CENTER_JUSTIFY;
|
||||
uiMain.dlgMessage1.generic.name = MenuStrings[HINT_RESTART_HZ];
|
||||
uiMain.dlgMessage1.generic.x = 192;
|
||||
uiMain.dlgMessage1.generic.y = 280;
|
||||
|
||||
uiMain.dlgMessage2.generic.id = ID_MSGTEXT;
|
||||
uiMain.dlgMessage2.generic.type = QMTYPE_ACTION;
|
||||
uiMain.dlgMessage2.generic.flags = QMF_INACTIVE|QMF_DROPSHADOW|QMF_HIDDEN;
|
||||
uiMain.dlgMessage2.generic.name = "any current game, OK to exit?";
|
||||
uiMain.dlgMessage2.generic.x = 256;
|
||||
uiMain.dlgMessage2.generic.y = 310;
|
||||
uiMain.dlgMessage1.generic.width = 640;
|
||||
uiMain.dlgMessage1.generic.height = 256;
|
||||
|
||||
uiMain.yes.generic.id = ID_YES;
|
||||
uiMain.yes.generic.type = QMTYPE_BM_BUTTON;
|
||||
|
@ -577,14 +577,13 @@ static void UI_Main_Init( void )
|
|||
if ( bCustomGame )
|
||||
UI_AddItem( &uiMain.menu, (void *)&uiMain.customGame );
|
||||
|
||||
UI_AddItem( &uiMain.menu, (void *)&uiMain.credits );
|
||||
UI_AddItem( &uiMain.menu, (void *)&uiMain.previews );
|
||||
UI_AddItem( &uiMain.menu, (void *)&uiMain.quit );
|
||||
UI_AddItem( &uiMain.menu, (void *)&uiMain.minimizeBtn );
|
||||
UI_AddItem( &uiMain.menu, (void *)&uiMain.quitButton );
|
||||
UI_AddItem( &uiMain.menu, (void *)&uiMain.msgBox );
|
||||
UI_AddItem( &uiMain.menu, (void *)&uiMain.quitMessage );
|
||||
UI_AddItem( &uiMain.menu, (void *)&uiMain.dlgMessage1 );
|
||||
UI_AddItem( &uiMain.menu, (void *)&uiMain.dlgMessage2 );
|
||||
UI_AddItem( &uiMain.menu, (void *)&uiMain.no );
|
||||
UI_AddItem( &uiMain.menu, (void *)&uiMain.yes );
|
||||
}
|
||||
|
|
|
@ -67,6 +67,8 @@ static void UI_MultiPlayer_Callback( void *self, int event )
|
|||
switch( item->id )
|
||||
{
|
||||
case ID_INTERNETGAMES:
|
||||
UI_InternetGames_Menu();
|
||||
break;
|
||||
case ID_SPECTATEGAMES:
|
||||
// UNDONE: write menus
|
||||
break;
|
||||
|
@ -116,7 +118,7 @@ static void UI_MultiPlayer_Init( void )
|
|||
|
||||
uiMultiPlayer.internetGames.generic.id = ID_INTERNETGAMES;
|
||||
uiMultiPlayer.internetGames.generic.type = QMTYPE_BM_BUTTON;
|
||||
uiMultiPlayer.internetGames.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW|QMF_NOTIFY|QMF_GRAYED;
|
||||
uiMultiPlayer.internetGames.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW|QMF_NOTIFY;
|
||||
uiMultiPlayer.internetGames.generic.x = 72;
|
||||
uiMultiPlayer.internetGames.generic.y = 230;
|
||||
uiMultiPlayer.internetGames.generic.name = "Internet games";
|
||||
|
|
|
@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "utils.h"
|
||||
#include "keydefs.h"
|
||||
#include "menu_btnsbmp_table.h"
|
||||
#include "menu_strings.h"
|
||||
|
||||
#define ART_BANNER "gfx/shell/head_newgame"
|
||||
|
||||
|
@ -54,7 +55,6 @@ typedef struct
|
|||
// newgame prompt dialog
|
||||
menuAction_s msgBox;
|
||||
menuAction_s dlgMessage1;
|
||||
menuAction_s dlgMessage2;
|
||||
menuPicButton_s yes;
|
||||
menuPicButton_s no;
|
||||
|
||||
|
@ -103,7 +103,6 @@ static void UI_PromptDialog( float skill )
|
|||
|
||||
uiNewGame.msgBox.generic.flags ^= QMF_HIDDEN;
|
||||
uiNewGame.dlgMessage1.generic.flags ^= QMF_HIDDEN;
|
||||
uiNewGame.dlgMessage2.generic.flags ^= QMF_HIDDEN;
|
||||
uiNewGame.no.generic.flags ^= QMF_HIDDEN;
|
||||
uiNewGame.yes.generic.flags ^= QMF_HIDDEN;
|
||||
|
||||
|
@ -139,14 +138,14 @@ static void UI_NewGame_Callback( void *self, int event )
|
|||
switch( item->id )
|
||||
{
|
||||
case ID_EASY:
|
||||
UI_PromptDialog( 0.0f );
|
||||
break;
|
||||
case ID_MEDIUM:
|
||||
UI_PromptDialog( 1.0f );
|
||||
break;
|
||||
case ID_DIFFICULT:
|
||||
case ID_MEDIUM:
|
||||
UI_PromptDialog( 2.0f );
|
||||
break;
|
||||
case ID_DIFFICULT:
|
||||
UI_PromptDialog( 3.0f );
|
||||
break;
|
||||
case ID_CANCEL:
|
||||
UI_PopMenu();
|
||||
break;
|
||||
|
@ -154,7 +153,7 @@ static void UI_NewGame_Callback( void *self, int event )
|
|||
UI_NewGame_StartGame( uiNewGame.skill );
|
||||
break;
|
||||
case ID_NO:
|
||||
UI_PromptDialog( 0.0f ); // clear skill
|
||||
UI_PromptDialog( 1.0f ); // clear skill
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -205,7 +204,7 @@ static void UI_NewGame_Init( void )
|
|||
uiNewGame.easy.generic.type = QMTYPE_BM_BUTTON;
|
||||
uiNewGame.easy.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW|QMF_NOTIFY;
|
||||
uiNewGame.easy.generic.name = "Easy";
|
||||
uiNewGame.easy.generic.statusText = "Play the game on the 'easy' skill setting";
|
||||
uiNewGame.easy.generic.statusText = MenuStrings[HINT_SKILL_EASY];
|
||||
uiNewGame.easy.generic.x = 72;
|
||||
uiNewGame.easy.generic.y = 230;
|
||||
uiNewGame.easy.generic.callback = UI_NewGame_Callback;
|
||||
|
@ -216,7 +215,7 @@ static void UI_NewGame_Init( void )
|
|||
uiNewGame.medium.generic.type = QMTYPE_BM_BUTTON;
|
||||
uiNewGame.medium.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW|QMF_NOTIFY;
|
||||
uiNewGame.medium.generic.name = "Medium";
|
||||
uiNewGame.medium.generic.statusText = "Play the game on the 'medium' skill setting";
|
||||
uiNewGame.medium.generic.statusText = MenuStrings[HINT_SKILL_NORMAL];
|
||||
uiNewGame.medium.generic.x = 72;
|
||||
uiNewGame.medium.generic.y = 280;
|
||||
uiNewGame.medium.generic.callback = UI_NewGame_Callback;
|
||||
|
@ -227,7 +226,7 @@ static void UI_NewGame_Init( void )
|
|||
uiNewGame.hard.generic.type = QMTYPE_BM_BUTTON;
|
||||
uiNewGame.hard.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW|QMF_NOTIFY;
|
||||
uiNewGame.hard.generic.name = "Difficult";
|
||||
uiNewGame.hard.generic.statusText = "Play the game on the 'difficult' skill setting";
|
||||
uiNewGame.hard.generic.statusText = MenuStrings[HINT_SKILL_HARD];
|
||||
uiNewGame.hard.generic.x = 72;
|
||||
uiNewGame.hard.generic.y = 330;
|
||||
uiNewGame.hard.generic.callback = UI_NewGame_Callback;
|
||||
|
@ -256,17 +255,12 @@ static void UI_NewGame_Init( void )
|
|||
|
||||
uiNewGame.dlgMessage1.generic.id = ID_MSGTEXT;
|
||||
uiNewGame.dlgMessage1.generic.type = QMTYPE_ACTION;
|
||||
uiNewGame.dlgMessage1.generic.flags = QMF_INACTIVE|QMF_HIDDEN|QMF_DROPSHADOW;
|
||||
uiNewGame.dlgMessage1.generic.name = "Starting a new game will exit";
|
||||
uiNewGame.dlgMessage1.generic.x = 248;
|
||||
uiNewGame.dlgMessage1.generic.flags = QMF_INACTIVE|QMF_HIDDEN|QMF_DROPSHADOW|QMF_CENTER_JUSTIFY;
|
||||
uiNewGame.dlgMessage1.generic.name = MenuStrings[HINT_RESTART_GAME];
|
||||
uiNewGame.dlgMessage1.generic.x = 192;
|
||||
uiNewGame.dlgMessage1.generic.y = 280;
|
||||
|
||||
uiNewGame.dlgMessage2.generic.id = ID_MSGTEXT;
|
||||
uiNewGame.dlgMessage2.generic.type = QMTYPE_ACTION;
|
||||
uiNewGame.dlgMessage2.generic.flags = QMF_INACTIVE|QMF_HIDDEN|QMF_DROPSHADOW;
|
||||
uiNewGame.dlgMessage2.generic.name = "any current game, OK to exit?";
|
||||
uiNewGame.dlgMessage2.generic.x = 248;
|
||||
uiNewGame.dlgMessage2.generic.y = 310;
|
||||
uiNewGame.dlgMessage1.generic.width = 640;
|
||||
uiNewGame.dlgMessage1.generic.height = 256;
|
||||
|
||||
uiNewGame.yes.generic.id = ID_YES;
|
||||
uiNewGame.yes.generic.type = QMTYPE_BM_BUTTON;
|
||||
|
@ -296,7 +290,6 @@ static void UI_NewGame_Init( void )
|
|||
UI_AddItem( &uiNewGame.menu, (void *)&uiNewGame.cancel );
|
||||
UI_AddItem( &uiNewGame.menu, (void *)&uiNewGame.msgBox );
|
||||
UI_AddItem( &uiNewGame.menu, (void *)&uiNewGame.dlgMessage1 );
|
||||
UI_AddItem( &uiNewGame.menu, (void *)&uiNewGame.dlgMessage2 );
|
||||
UI_AddItem( &uiNewGame.menu, (void *)&uiNewGame.no );
|
||||
UI_AddItem( &uiNewGame.menu, (void *)&uiNewGame.yes );
|
||||
}
|
||||
|
|
|
@ -0,0 +1,634 @@
|
|||
/*
|
||||
menu_strings.cpp - custom menu strings
|
||||
Copyright (C) 2011 Uncle Mike
|
||||
|
||||
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 3 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.
|
||||
*/
|
||||
|
||||
#include "extdll.h"
|
||||
#include "basemenu.h"
|
||||
#include "utils.h"
|
||||
#include "menu_strings.h"
|
||||
|
||||
char *MenuStrings[HINT_MAXSTRINGS] =
|
||||
{
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 10
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 20
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 30
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 40
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 50
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 60
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 70
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 80
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 90
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 100
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 110
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 120
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 130
|
||||
"",
|
||||
"Display mode",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 140
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 150
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 160
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 170
|
||||
"Reverse mouse",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 180
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Mouse sensitivity",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Return to game.",
|
||||
"Start a new game.",
|
||||
"", // 190
|
||||
"Load a previously saved game.",
|
||||
"Load a saved game, save the current game.",
|
||||
"Change game settings, configure controls",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 200
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 210
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 220
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 230
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Starting a Hazard Course will exit\nany current game, OK to exit?",
|
||||
"", // filled in UI_LoadCustomStrings
|
||||
"Are you sure you want to quit?",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Starting a new game will exit\nany current game, OK to exit?", // 240
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 250
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 260
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 270
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 280
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 290
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 300
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 310
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 320
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 330
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 340
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 350
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 360
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 370
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 380
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 390
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Find more about Valve's product lineup", // 400
|
||||
"",
|
||||
"http://www.valvesoftware.com/projects.htm",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 410
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 420
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 430
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 440
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 450
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 460
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 470
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 480
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 490
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 500
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 510
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 520
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Select a custom game", // 530
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 540
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // 550
|
||||
};
|
||||
|
||||
void UI_InitAliasStrings( void )
|
||||
{
|
||||
char token[1024];
|
||||
|
||||
// some strings needs to be initialized here
|
||||
sprintf( token, "Quit %s without\nsaving current game?", gMenu.m_gameinfo.title );
|
||||
MenuStrings[HINT_QUIT_ACTIVE] = StringCopy( token );
|
||||
|
||||
sprintf( token, "Learn how to play %s", gMenu.m_gameinfo.title );
|
||||
MenuStrings[HINT_HAZARD_COURSE] = StringCopy( token );
|
||||
|
||||
sprintf( token, "Play %s on the 'easy' skill setting", gMenu.m_gameinfo.title );
|
||||
MenuStrings[HINT_SKILL_EASY] = StringCopy( token );
|
||||
|
||||
sprintf( token, "Play %s on the 'medium' skill setting", gMenu.m_gameinfo.title );
|
||||
MenuStrings[HINT_SKILL_NORMAL] = StringCopy( token );
|
||||
|
||||
sprintf( token, "Play %s on the 'difficult' skill setting", gMenu.m_gameinfo.title );
|
||||
MenuStrings[HINT_SKILL_HARD] = StringCopy( token );
|
||||
|
||||
sprintf( token, "Quit playing %s", gMenu.m_gameinfo.title );
|
||||
MenuStrings[HINT_QUIT_BUTTON] = StringCopy( token );
|
||||
|
||||
sprintf( token, "Search for %s servers, configure character", gMenu.m_gameinfo.title );
|
||||
MenuStrings[HINT_MULTIPLAYER] = StringCopy( token );
|
||||
}
|
||||
|
||||
void UI_LoadCustomStrings( void )
|
||||
{
|
||||
char *afile = (char *)LOAD_FILE( "gfx/shell/strings.lst", NULL );
|
||||
char *pfile = afile;
|
||||
char token[1024];
|
||||
int string_num;
|
||||
|
||||
UI_InitAliasStrings ();
|
||||
|
||||
if( !afile )
|
||||
return;
|
||||
|
||||
while(( pfile = COM_ParseFile( pfile, token )) != NULL )
|
||||
{
|
||||
if( isdigit( token[0] ))
|
||||
{
|
||||
string_num = atoi( token );
|
||||
|
||||
// check for bad stiringnum
|
||||
if( string_num < 0 ) continue;
|
||||
if( string_num > ( HINT_MAXSTRINGS - 1 ))
|
||||
continue;
|
||||
}
|
||||
else continue; // invalid declaration ?
|
||||
|
||||
// parse new string
|
||||
pfile = COM_ParseFile( pfile, token );
|
||||
MenuStrings[string_num] = StringCopy( token ); // replace default string with custom
|
||||
}
|
||||
|
||||
FREE_FILE( afile );
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
menu_strings.h - custom menu strings
|
||||
Copyright (C) 2011 Uncle Mike
|
||||
|
||||
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 3 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.
|
||||
*/
|
||||
|
||||
#define HINT_DISPLAYMODE 132
|
||||
#define HINT_REVERSE_MOUSE 171
|
||||
#define HINT_MOUSE_SENSE 184
|
||||
#define HINT_RESUME_GAME 188
|
||||
#define HINT_NEWGAME 189
|
||||
#define HINT_HAZARD_COURSE 190
|
||||
#define HINT_LOADGAME 191
|
||||
#define HINT_SAVELOADGAME 192
|
||||
#define HINT_CONFIGURATION 193
|
||||
#define HINT_QUIT_BUTTON 196
|
||||
#define HINT_MULTIPLAYER 198
|
||||
#define HINT_SKILL_EASY 200
|
||||
#define HINT_SKILL_NORMAL 201
|
||||
#define HINT_SKILL_HARD 202
|
||||
#define HINT_RESTART_HZ 234
|
||||
#define HINT_QUIT_ACTIVE 235
|
||||
#define HINT_QUIT 236
|
||||
#define HINT_RESTART_GAME 240
|
||||
#define HINT_PREVIEWS_TEXT 400
|
||||
#define HINT_PREVIEWS_CMD 402 // this buton will execute program or open HTML-window
|
||||
#define HINT_CUSTOM_GAME 530
|
||||
#define HINT_MAXSTRINGS 551 // 550 strings allowed
|
||||
|
||||
extern char *MenuStrings[HINT_MAXSTRINGS];
|
|
@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "basemenu.h"
|
||||
#include "utils.h"
|
||||
#include "menu_btnsbmp_table.h"
|
||||
#include "menu_strings.h"
|
||||
|
||||
#define ART_BANNER "gfx/shell/head_vidmodes"
|
||||
|
||||
|
@ -54,6 +55,7 @@ static const char *uiVideoModes[] =
|
|||
"1024 x 600 (wide)",
|
||||
"1280 x 720 (wide)",
|
||||
"1360 x 768 (wide)",
|
||||
"1366 x 768 (wide)",
|
||||
"1440 x 900 (wide)",
|
||||
"1680 x 1050 (wide)",
|
||||
"1920 x 1200 (wide)",
|
||||
|
@ -216,7 +218,7 @@ static void UI_VidModes_Init( void )
|
|||
uiVidModes.listCaption.generic.type = QMTYPE_BM_BUTTON;
|
||||
uiVidModes.listCaption.generic.flags = QMF_INACTIVE|QMF_SMALLFONT;
|
||||
uiVidModes.listCaption.generic.color = uiColorHelp;
|
||||
uiVidModes.listCaption.generic.name = "Display mode";
|
||||
uiVidModes.listCaption.generic.name = MenuStrings[HINT_DISPLAYMODE];
|
||||
uiVidModes.listCaption.generic.x = 400;
|
||||
uiVidModes.listCaption.generic.y = 270;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -97,6 +97,16 @@ void StringConcat( char *dst, const char *src, size_t size )
|
|||
return;
|
||||
}
|
||||
|
||||
char *StringCopy( const char *input )
|
||||
{
|
||||
if( !input ) return NULL;
|
||||
|
||||
char *out = (char *)MALLOC( strlen( input ) + 1 );
|
||||
strcpy( out, input );
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
COM_FileBase
|
||||
|
|
|
@ -117,5 +117,8 @@ extern int UI_FadeAlpha( int starttime, int endtime );
|
|||
extern void StringConcat( char *dst, const char *src, size_t size ); // strncat safe prototype
|
||||
extern char *Info_ValueForKey( const char *s, const char *key );
|
||||
extern int KEY_GetKey( const char *binding ); // ripped out from engine
|
||||
extern char *StringCopy( const char *input ); // copy string into new memory
|
||||
|
||||
extern void UI_LoadCustomStrings( void );
|
||||
|
||||
#endif//UTILS_H
|
Reference in New Issue