Merge branch 'master' into new-menus

This commit is contained in:
Sally Coolatta 2022-08-27 22:36:58 -04:00
commit 107622968e
250 changed files with 2531 additions and 47145 deletions

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<IncludePath>$(SolutionDir)libs\fmodex\inc;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)libs\fmodex\lib;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup />
<ItemDefinitionGroup Condition="'$(PlatformTarget)'=='x64'">
<Link>
<AdditionalDependencies>fmodexL64_vc.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(PlatformTarget)'=='x86'">
<Link>
<AdditionalDependencies>fmodexL_vc.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup />
</Project>

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -1,159 +0,0 @@
/* ==================================================================================================== */
/* FMOD Ex - codec development header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2011. */
/* */
/* Use this header if you are wanting to develop your own file format plugin to use with */
/* FMOD's codec system. With this header you can make your own fileformat plugin that FMOD */
/* can register and use. See the documentation and examples on how to make a working plugin. */
/* */
/* ==================================================================================================== */
#ifndef _FMOD_CODEC_H
#define _FMOD_CODEC_H
typedef struct FMOD_CODEC_STATE FMOD_CODEC_STATE;
typedef struct FMOD_CODEC_WAVEFORMAT FMOD_CODEC_WAVEFORMAT;
/*
Codec callbacks
*/
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_OPENCALLBACK) (FMOD_CODEC_STATE *codec_state, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_CLOSECALLBACK) (FMOD_CODEC_STATE *codec_state);
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_READCALLBACK) (FMOD_CODEC_STATE *codec_state, void *buffer, unsigned int sizebytes, unsigned int *bytesread);
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETLENGTHCALLBACK) (FMOD_CODEC_STATE *codec_state, unsigned int *length, FMOD_TIMEUNIT lengthtype);
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_SETPOSITIONCALLBACK) (FMOD_CODEC_STATE *codec_state, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETPOSITIONCALLBACK) (FMOD_CODEC_STATE *codec_state, unsigned int *position, FMOD_TIMEUNIT postype);
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_SOUNDCREATECALLBACK) (FMOD_CODEC_STATE *codec_state, int subsound, FMOD_SOUND *sound);
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_METADATACALLBACK) (FMOD_CODEC_STATE *codec_state, FMOD_TAGTYPE tagtype, char *name, void *data, unsigned int datalen, FMOD_TAGDATATYPE datatype, int unique);
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETWAVEFORMAT) (FMOD_CODEC_STATE *codec_state, int index, FMOD_CODEC_WAVEFORMAT *waveformat);
/*
[STRUCTURE]
[
[DESCRIPTION]
When creating a codec, declare one of these and provide the relevant callbacks and name for FMOD to use when it opens and reads a file.
[REMARKS]
Members marked with [in] mean the variable can be written to. The user can set the value.
Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
FMOD_CODEC_STATE
]
*/
typedef struct FMOD_CODEC_DESCRIPTION
{
const char *name; /* [in] Name of the codec. */
unsigned int version; /* [in] Plugin writer's version number. */
int defaultasstream; /* [in] Tells FMOD to open the file as a stream when calling System::createSound, and not a static sample. Should normally be 0 (FALSE), because generally the user wants to decode the file into memory when using System::createSound. Mainly used for formats that decode for a very long time, or could use large amounts of memory when decoded. Usually sequenced formats such as mod/s3m/xm/it/midi fall into this category. It is mainly to stop users that don't know what they're doing from getting FMOD_ERR_MEMORY returned from createSound when they should have in fact called System::createStream or used FMOD_CREATESTREAM in System::createSound. */
FMOD_TIMEUNIT timeunits; /* [in] When setposition codec is called, only these time formats will be passed to the codec. Use bitwise OR to accumulate different types. */
FMOD_CODEC_OPENCALLBACK open; /* [in] Open callback for the codec for when FMOD tries to open a sound using this codec. */
FMOD_CODEC_CLOSECALLBACK close; /* [in] Close callback for the codec for when FMOD tries to close a sound using this codec. */
FMOD_CODEC_READCALLBACK read; /* [in] Read callback for the codec for when FMOD tries to read some data from the file to the destination format (specified in the open callback). */
FMOD_CODEC_GETLENGTHCALLBACK getlength; /* [in] Callback to return the length of the song in whatever format required when Sound::getLength is called. */
FMOD_CODEC_SETPOSITIONCALLBACK setposition; /* [in] Seek callback for the codec for when FMOD tries to seek within the file with Channel::setPosition. */
FMOD_CODEC_GETPOSITIONCALLBACK getposition; /* [in] Tell callback for the codec for when FMOD tries to get the current position within the with Channel::getPosition. */
FMOD_CODEC_SOUNDCREATECALLBACK soundcreate; /* [in] Sound creation callback for the codec when FMOD finishes creating the sound. (So the codec can set more parameters for the related created sound, ie loop points/mode or 3D attributes etc). */
FMOD_CODEC_GETWAVEFORMAT getwaveformat; /* [in] Callback to tell FMOD about the waveformat of a particular subsound. This is to save memory, rather than saving 1000 FMOD_CODEC_WAVEFORMAT structures in the codec, the codec might have a more optimal way of storing this information. */
} FMOD_CODEC_DESCRIPTION;
/*
[STRUCTURE]
[
[DESCRIPTION]
Set these values marked 'in' to tell fmod what sort of sound to create.
The format, channels and frequency tell FMOD what sort of hardware buffer to create when you initialize your code. So if you wrote an MP3 codec that decoded to stereo 16bit integer PCM, you would specify FMOD_SOUND_FORMAT_PCM16, and channels would be equal to 2.
Members marked as 'out' are set by fmod. Do not modify these. Simply specify 0 for these values when declaring the structure, FMOD will fill in the values for you after creation with the correct function pointers.
[REMARKS]
Members marked with [in] mean the variable can be written to. The user can set the value.
Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
An FMOD file might be from disk, memory or network, however the file may be opened by the user.
'numsubsounds' should be 0 if the file is a normal single sound stream or sound. Examples of this would be .WAV, .WMA, .MP3, .AIFF.
'numsubsounds' should be 1+ if the file is a container format, and does not contain wav data itself. Examples of these types would be CDDA (multiple CD tracks), FSB (contains multiple sounds), MIDI/MOD/S3M/XM/IT (contain instruments).
The arrays of format, channel, frequency, length and blockalign should point to arrays of information based on how many subsounds are in the format. If the number of subsounds is 0 then it should point to 1 of each attribute, the same as if the number of subsounds was 1. If subsounds was 100 for example, each pointer should point to an array of 100 of each attribute.
When a sound has 1 or more subsounds, you must play the individual sounds specified by first obtaining the subsound with Sound::getSubSound.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
FMOD_SOUND_FORMAT
FMOD_FILE_READCALLBACK
FMOD_FILE_SEEKCALLBACK
FMOD_CODEC_METADATACALLBACK
Sound::getSubSound
Sound::getNumSubSounds
]
*/
struct FMOD_CODEC_WAVEFORMAT
{
char name[256]; /* [in] Name of sound.*/
FMOD_SOUND_FORMAT format; /* [in] Format for (decompressed) codec output, ie FMOD_SOUND_FORMAT_PCM8, FMOD_SOUND_FORMAT_PCM16.*/
int channels; /* [in] Number of channels used by codec, ie mono = 1, stereo = 2. */
int frequency; /* [in] Default frequency in hz of the codec, ie 44100. */
unsigned int lengthbytes; /* [in] Length in bytes of the source data. */
unsigned int lengthpcm; /* [in] Length in decompressed, PCM samples of the file, ie length in seconds * frequency. Used for Sound::getLength and for memory allocation of static decompressed sample data. */
int blockalign; /* [in] Blockalign in decompressed, PCM samples of the optimal decode chunk size for this format. The codec read callback will be called in multiples of this value. */
int loopstart; /* [in] Loopstart in decompressed, PCM samples of file. */
int loopend; /* [in] Loopend in decompressed, PCM samples of file. */
FMOD_MODE mode; /* [in] Mode to determine whether the sound should by default load as looping, non looping, 2d or 3d. */
unsigned int channelmask; /* [in] Microsoft speaker channel mask, as defined for WAVEFORMATEXTENSIBLE and is found in ksmedia.h. Leave at 0 to play in natural speaker order. */
};
/*
[STRUCTURE]
[
[DESCRIPTION]
Codec plugin structure that is passed into each callback.
Set these numsubsounds and waveformat members when called in FMOD_CODEC_OPENCALLBACK to tell fmod what sort of sound to create.
The format, channels and frequency tell FMOD what sort of hardware buffer to create when you initialize your code. So if you wrote an MP3 codec that decoded to stereo 16bit integer PCM, you would specify FMOD_SOUND_FORMAT_PCM16, and channels would be equal to 2.
[REMARKS]
Members marked with [in] mean the variable can be written to. The user can set the value.
Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
An FMOD file might be from disk, memory or internet, however the file may be opened by the user.
'numsubsounds' should be 0 if the file is a normal single sound stream or sound. Examples of this would be .WAV, .WMA, .MP3, .AIFF.
'numsubsounds' should be 1+ if the file is a container format, and does not contain wav data itself. Examples of these types would be CDDA (multiple CD tracks), FSB (contains multiple sounds), DLS (contain instruments).
The arrays of format, channel, frequency, length and blockalign should point to arrays of information based on how many subsounds are in the format. If the number of subsounds is 0 then it should point to 1 of each attribute, the same as if the number of subsounds was 1. If subsounds was 100 for example, each pointer should point to an array of 100 of each attribute.
When a sound has 1 or more subsounds, you must play the individual sounds specified by first obtaining the subsound with Sound::getSubSound.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
FMOD_SOUND_FORMAT
FMOD_FILE_READCALLBACK
FMOD_FILE_SEEKCALLBACK
FMOD_CODEC_METADATACALLBACK
Sound::getSubSound
Sound::getNumSubSounds
]
*/
struct FMOD_CODEC_STATE
{
int numsubsounds; /* [in] Number of 'subsounds' in this sound. Anything other than 0 makes it a 'container' format (ie CDDA/DLS/FSB etc which contain 1 or more su bsounds). For most normal, single sound codec such as WAV/AIFF/MP3, this should be 0 as they are not a container for subsounds, they are the sound by itself. */
FMOD_CODEC_WAVEFORMAT *waveformat; /* [in] Pointer to an array of format structures containing information about each sample. Can be 0 or NULL if FMOD_CODEC_GETWAVEFORMAT callback is preferred. The number of entries here must equal the number of subsounds defined in the subsound parameter. If numsubsounds = 0 then there should be 1 instance of this structure. */
void *plugindata; /* [in] Plugin writer created data the codec author wants to attach to this object. */
void *filehandle; /* [out] This will return an internal FMOD file handle to use with the callbacks provided. */
unsigned int filesize; /* [out] This will contain the size of the file in bytes. */
FMOD_FILE_READCALLBACK fileread; /* [out] This will return a callable FMOD file function to use from codec. */
FMOD_FILE_SEEKCALLBACK fileseek; /* [out] This will return a callable FMOD file function to use from codec. */
FMOD_CODEC_METADATACALLBACK metadata; /* [out] This will return a callable FMOD metadata function to use from codec. */
};
#endif

View file

@ -1,743 +0,0 @@
/* ========================================================================================== */
/* FMOD Ex - DSP header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2011. */
/* */
/* Use this header if you are interested in delving deeper into the FMOD software mixing / */
/* DSP engine. In this header you can find parameter structures for FMOD system reigstered */
/* DSP effects and generators. */
/* Also use this header if you are wanting to develop your own DSP plugin to use with FMOD's */
/* dsp system. With this header you can make your own DSP plugin that FMOD can */
/* register and use. See the documentation and examples on how to make a working plugin. */
/* */
/* ========================================================================================== */
#ifndef _FMOD_DSP_H
#define _FMOD_DSP_H
typedef struct FMOD_DSP_STATE FMOD_DSP_STATE;
/*
DSP callbacks
*/
typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_CREATECALLBACK) (FMOD_DSP_STATE *dsp_state);
typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_RELEASECALLBACK) (FMOD_DSP_STATE *dsp_state);
typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_RESETCALLBACK) (FMOD_DSP_STATE *dsp_state);
typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_READCALLBACK) (FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_SETPOSITIONCALLBACK)(FMOD_DSP_STATE *dsp_state, unsigned int pos);
typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_SETPARAMCALLBACK) (FMOD_DSP_STATE *dsp_state, int index, float value);
typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_GETPARAMCALLBACK) (FMOD_DSP_STATE *dsp_state, int index, float *value, char *valuestr);
typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_DIALOGCALLBACK) (FMOD_DSP_STATE *dsp_state, void *hwnd, int show);
/*
[ENUM]
[
[DESCRIPTION]
These definitions can be used for creating FMOD defined special effects or DSP units.
[REMARKS]
To get them to be active, first create the unit, then add it somewhere into the DSP network, either at the front of the network near the soundcard unit to affect the global output (by using System::getDSPHead), or on a single channel (using Channel::getDSPHead).
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
System::createDSPByType
]
*/
typedef enum
{
FMOD_DSP_TYPE_UNKNOWN, /* This unit was created via a non FMOD plugin so has an unknown purpose. */
FMOD_DSP_TYPE_MIXER, /* This unit does nothing but take inputs and mix them together then feed the result to the soundcard unit. */
FMOD_DSP_TYPE_OSCILLATOR, /* This unit generates sine/square/saw/triangle or noise tones. */
FMOD_DSP_TYPE_LOWPASS, /* This unit filters sound using a high quality, resonant lowpass filter algorithm but consumes more CPU time. */
FMOD_DSP_TYPE_ITLOWPASS, /* This unit filters sound using a resonant lowpass filter algorithm that is used in Impulse Tracker, but with limited cutoff range (0 to 8060hz). */
FMOD_DSP_TYPE_HIGHPASS, /* This unit filters sound using a resonant highpass filter algorithm. */
FMOD_DSP_TYPE_ECHO, /* This unit produces an echo on the sound and fades out at the desired rate. */
FMOD_DSP_TYPE_FLANGE, /* This unit produces a flange effect on the sound. */
FMOD_DSP_TYPE_DISTORTION, /* This unit distorts the sound. */
FMOD_DSP_TYPE_NORMALIZE, /* This unit normalizes or amplifies the sound to a certain level. */
FMOD_DSP_TYPE_PARAMEQ, /* This unit attenuates or amplifies a selected frequency range. */
FMOD_DSP_TYPE_PITCHSHIFT, /* This unit bends the pitch of a sound without changing the speed of playback. */
FMOD_DSP_TYPE_CHORUS, /* This unit produces a chorus effect on the sound. */
FMOD_DSP_TYPE_VSTPLUGIN, /* This unit allows the use of Steinberg VST plugins */
FMOD_DSP_TYPE_WINAMPPLUGIN, /* This unit allows the use of Nullsoft Winamp plugins */
FMOD_DSP_TYPE_ITECHO, /* This unit produces an echo on the sound and fades out at the desired rate as is used in Impulse Tracker. */
FMOD_DSP_TYPE_COMPRESSOR, /* This unit implements dynamic compression (linked multichannel, wideband) */
FMOD_DSP_TYPE_SFXREVERB, /* This unit implements SFX reverb */
FMOD_DSP_TYPE_LOWPASS_SIMPLE, /* This unit filters sound using a simple lowpass with no resonance, but has flexible cutoff and is fast. */
FMOD_DSP_TYPE_DELAY, /* This unit produces different delays on individual channels of the sound. */
FMOD_DSP_TYPE_TREMOLO, /* This unit produces a tremolo / chopper effect on the sound. */
FMOD_DSP_TYPE_LADSPAPLUGIN, /* This unit allows the use of LADSPA standard plugins. */
FMOD_DSP_TYPE_HIGHPASS_SIMPLE, /* This unit filters sound using a simple highpass with no resonance, but has flexible cutoff and is fast. */
FMOD_DSP_TYPE_HARDWARE = 1000, /* Offset that platform specific FMOD_HARDWARE DSPs will start at. */
FMOD_DSP_TYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */
} FMOD_DSP_TYPE;
/*
[STRUCTURE]
[
[DESCRIPTION]
Structure to define a parameter for a DSP unit.
[REMARKS]
Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
Members marked with [w] mean the variable can be written to. The user can set the value.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
System::createDSP
DSP::setParameter
]
*/
typedef struct FMOD_DSP_PARAMETERDESC
{
float min; /* [w] Minimum value of the parameter (ie 100.0). */
float max; /* [w] Maximum value of the parameter (ie 22050.0). */
float defaultval; /* [w] Default value of parameter. */
char name[16]; /* [w] Name of the parameter to be displayed (ie "Cutoff frequency"). */
char label[16]; /* [w] Short string to be put next to value to denote the unit type (ie "hz"). */
const char *description; /* [w] Description of the parameter to be displayed as a help item / tooltip for this parameter. */
} FMOD_DSP_PARAMETERDESC;
/*
[STRUCTURE]
[
[DESCRIPTION]
When creating a DSP unit, declare one of these and provide the relevant callbacks and name for FMOD to use when it creates and uses a DSP unit of this type.
[REMARKS]
Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
Members marked with [w] mean the variable can be written to. The user can set the value.
There are 2 different ways to change a parameter in this architecture.
One is to use DSP::setParameter / DSP::getParameter. This is platform independant and is dynamic, so new unknown plugins can have their parameters enumerated and used.
The other is to use DSP::showConfigDialog. This is platform specific and requires a GUI, and will display a dialog box to configure the plugin.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
System::createDSP
FMOD_DSP_STATE
]
*/
typedef struct FMOD_DSP_DESCRIPTION
{
char name[32]; /* [w] Name of the unit to be displayed in the network. */
unsigned int version; /* [w] Plugin writer's version number. */
int channels; /* [w] Number of channels. Use 0 to process whatever number of channels is currently in the network. >0 would be mostly used if the unit is a unit that only generates sound. */
FMOD_DSP_CREATECALLBACK create; /* [w] Create callback. This is called when DSP unit is created. Can be null. */
FMOD_DSP_RELEASECALLBACK release; /* [w] Release callback. This is called just before the unit is freed so the user can do any cleanup needed for the unit. Can be null. */
FMOD_DSP_RESETCALLBACK reset; /* [w] Reset callback. This is called by the user to reset any history buffers that may need resetting for a filter, when it is to be used or re-used for the first time to its initial clean state. Use to avoid clicks or artifacts. */
FMOD_DSP_READCALLBACK read; /* [w] Read callback. Processing is done here. Can be null. */
FMOD_DSP_SETPOSITIONCALLBACK setposition; /* [w] Set position callback. This is called if the unit wants to update its position info but not process data, or reset a cursor position internally if it is reading data from a certain source. Can be null. */
int numparameters; /* [w] Number of parameters used in this filter. The user finds this with DSP::getNumParameters */
FMOD_DSP_PARAMETERDESC *paramdesc; /* [w] Variable number of parameter structures. */
FMOD_DSP_SETPARAMCALLBACK setparameter; /* [w] This is called when the user calls DSP::setParameter. Can be null. */
FMOD_DSP_GETPARAMCALLBACK getparameter; /* [w] This is called when the user calls DSP::getParameter. Can be null. */
FMOD_DSP_DIALOGCALLBACK config; /* [w] This is called when the user calls DSP::showConfigDialog. Can be used to display a dialog to configure the filter. Can be null. */
int configwidth; /* [w] Width of config dialog graphic if there is one. 0 otherwise.*/
int configheight; /* [w] Height of config dialog graphic if there is one. 0 otherwise.*/
void *userdata; /* [w] Optional. Specify 0 to ignore. This is user data to be attached to the DSP unit during creation. Access via DSP::getUserData. */
} FMOD_DSP_DESCRIPTION;
/*
[STRUCTURE]
[
[DESCRIPTION]
DSP plugin structure that is passed into each callback.
[REMARKS]
Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
Members marked with [w] mean the variable can be written to. The user can set the value.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
FMOD_DSP_DESCRIPTION
]
*/
struct FMOD_DSP_STATE
{
FMOD_DSP *instance; /* [r] Handle to the DSP hand the user created. Not to be modified. C++ users cast to FMOD::DSP to use. */
void *plugindata; /* [w] Plugin writer created data the output author wants to attach to this object. */
unsigned short speakermask; /* [w] Specifies which speakers the DSP effect is active on */
};
/*
===================================================================================================
FMOD built in effect parameters.
Use DSP::setParameter with these enums for the 'index' parameter.
===================================================================================================
*/
/*
[ENUM]
[
[DESCRIPTION]
Parameter types for the FMOD_DSP_TYPE_OSCILLATOR filter.
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
DSP::setParameter
DSP::getParameter
FMOD_DSP_TYPE
]
*/
typedef enum
{
FMOD_DSP_OSCILLATOR_TYPE, /* Waveform type. 0 = sine. 1 = square. 2 = sawup. 3 = sawdown. 4 = triangle. 5 = noise. */
FMOD_DSP_OSCILLATOR_RATE /* Frequency of the sinewave in hz. 1.0 to 22000.0. Default = 220.0. */
} FMOD_DSP_OSCILLATOR;
/*
[ENUM]
[
[DESCRIPTION]
Parameter types for the FMOD_DSP_TYPE_LOWPASS filter.
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
DSP::setParameter
DSP::getParameter
FMOD_DSP_TYPE
]
*/
typedef enum
{
FMOD_DSP_LOWPASS_CUTOFF, /* Lowpass cutoff frequency in hz. 10.0 to 22000.0. Default = 5000.0. */
FMOD_DSP_LOWPASS_RESONANCE /* Lowpass resonance Q value. 1.0 to 10.0. Default = 1.0. */
} FMOD_DSP_LOWPASS;
/*
[ENUM]
[
[DESCRIPTION]
Parameter types for the FMOD_DSP_TYPE_ITLOWPASS filter.
This is different to the default FMOD_DSP_TYPE_ITLOWPASS filter in that it uses a different quality algorithm and is
the filter used to produce the correct sounding playback in .IT files.
FMOD Ex's .IT playback uses this filter.
[REMARKS]
Note! This filter actually has a limited cutoff frequency below the specified maximum, due to its limited design,
so for a more open range filter use FMOD_DSP_LOWPASS or if you don't mind not having resonance,
FMOD_DSP_LOWPASS_SIMPLE.
The effective maximum cutoff is about 8060hz.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
DSP::setParameter
DSP::getParameter
FMOD_DSP_TYPE
]
*/
typedef enum
{
FMOD_DSP_ITLOWPASS_CUTOFF, /* Lowpass cutoff frequency in hz. 1.0 to 22000.0. Default = 5000.0/ */
FMOD_DSP_ITLOWPASS_RESONANCE /* Lowpass resonance Q value. 0.0 to 127.0. Default = 1.0. */
} FMOD_DSP_ITLOWPASS;
/*
[ENUM]
[
[DESCRIPTION]
Parameter types for the FMOD_DSP_TYPE_HIGHPASS filter.
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
DSP::setParameter
DSP::getParameter
FMOD_DSP_TYPE
]
*/
typedef enum
{
FMOD_DSP_HIGHPASS_CUTOFF, /* Highpass cutoff frequency in hz. 1.0 to output 22000.0. Default = 5000.0. */
FMOD_DSP_HIGHPASS_RESONANCE /* Highpass resonance Q value. 1.0 to 10.0. Default = 1.0. */
} FMOD_DSP_HIGHPASS;
/*
[ENUM]
[
[DESCRIPTION]
Parameter types for the FMOD_DSP_TYPE_ECHO filter.
[REMARKS]
Note. Every time the delay is changed, the plugin re-allocates the echo buffer. This means the echo will dissapear at that time while it refills its new buffer.
Larger echo delays result in larger amounts of memory allocated.
'<i>maxchannels</i>' also dictates the amount of memory allocated. By default, the maxchannels value is 0. If FMOD is set to stereo, the echo unit will allocate enough memory for 2 channels. If it is 5.1, it will allocate enough memory for a 6 channel echo, etc.
If the echo effect is only ever applied to the global mix (ie it was added with System::addDSP), then 0 is the value to set as it will be enough to handle all speaker modes.
When the echo is added to a channel (ie Channel::addDSP) then the channel count that comes in could be anything from 1 to 8 possibly. It is only in this case where you might want to increase the channel count above the output's channel count.
If a channel echo is set to a lower number than the sound's channel count that is coming in, it will not echo the sound.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
DSP::setParameter
DSP::getParameter
FMOD_DSP_TYPE
]
*/
typedef enum
{
FMOD_DSP_ECHO_DELAY, /* Echo delay in ms. 10 to 5000. Default = 500. */
FMOD_DSP_ECHO_DECAYRATIO, /* Echo decay per delay. 0 to 1. 1.0 = No decay, 0.0 = total decay (ie simple 1 line delay). Default = 0.5. */
FMOD_DSP_ECHO_MAXCHANNELS, /* Maximum channels supported. 0 to 16. 0 = same as fmod's default output polyphony, 1 = mono, 2 = stereo etc. See remarks for more. Default = 0. It is suggested to leave at 0! */
FMOD_DSP_ECHO_DRYMIX, /* Volume of original signal to pass to output. 0.0 to 1.0. Default = 1.0. */
FMOD_DSP_ECHO_WETMIX /* Volume of echo signal to pass to output. 0.0 to 1.0. Default = 1.0. */
} FMOD_DSP_ECHO;
/*
[ENUM]
[
[DESCRIPTION]
Parameter types for the FMOD_DSP_TYPE_DELAY filter.
[REMARKS]
Note. Every time MaxDelay is changed, the plugin re-allocates the delay buffer. This means the delay will dissapear at that time while it refills its new buffer.
A larger MaxDelay results in larger amounts of memory allocated.
Channel delays above MaxDelay will be clipped to MaxDelay and the delay buffer will not be resized.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
DSP::setParameter
DSP::getParameter
FMOD_DSP_TYPE
]
*/
typedef enum
{
FMOD_DSP_DELAY_CH0, /* Channel #0 Delay in ms. 0 to 10000. Default = 0. */
FMOD_DSP_DELAY_CH1, /* Channel #1 Delay in ms. 0 to 10000. Default = 0. */
FMOD_DSP_DELAY_CH2, /* Channel #2 Delay in ms. 0 to 10000. Default = 0. */
FMOD_DSP_DELAY_CH3, /* Channel #3 Delay in ms. 0 to 10000. Default = 0. */
FMOD_DSP_DELAY_CH4, /* Channel #4 Delay in ms. 0 to 10000. Default = 0. */
FMOD_DSP_DELAY_CH5, /* Channel #5 Delay in ms. 0 to 10000. Default = 0. */
FMOD_DSP_DELAY_CH6, /* Channel #6 Delay in ms. 0 to 10000. Default = 0. */
FMOD_DSP_DELAY_CH7, /* Channel #7 Delay in ms. 0 to 10000. Default = 0. */
FMOD_DSP_DELAY_CH8, /* Channel #8 Delay in ms. 0 to 10000. Default = 0. */
FMOD_DSP_DELAY_CH9, /* Channel #9 Delay in ms. 0 to 10000. Default = 0. */
FMOD_DSP_DELAY_CH10, /* Channel #10 Delay in ms. 0 to 10000. Default = 0. */
FMOD_DSP_DELAY_CH11, /* Channel #11 Delay in ms. 0 to 10000. Default = 0. */
FMOD_DSP_DELAY_CH12, /* Channel #12 Delay in ms. 0 to 10000. Default = 0. */
FMOD_DSP_DELAY_CH13, /* Channel #13 Delay in ms. 0 to 10000. Default = 0. */
FMOD_DSP_DELAY_CH14, /* Channel #14 Delay in ms. 0 to 10000. Default = 0. */
FMOD_DSP_DELAY_CH15, /* Channel #15 Delay in ms. 0 to 10000. Default = 0. */
FMOD_DSP_DELAY_MAXDELAY /* Maximum delay in ms. 0 to 10000. Default = 10. */
} FMOD_DSP_DELAY;
/*
[ENUM]
[
[DESCRIPTION]
Parameter types for the FMOD_DSP_TYPE_FLANGE filter.
[REMARKS]
Flange is an effect where the signal is played twice at the same time, and one copy slides back and forth creating a whooshing or flanging effect.
As there are 2 copies of the same signal, by default each signal is given 50% mix, so that the total is not louder than the original unaffected signal.
Flange depth is a percentage of a 10ms shift from the original signal. Anything above 10ms is not considered flange because to the ear it begins to 'echo' so 10ms is the highest value possible.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
DSP::setParameter
DSP::getParameter
FMOD_DSP_TYPE
]
*/
typedef enum
{
FMOD_DSP_FLANGE_DRYMIX, /* Volume of original signal to pass to output. 0.0 to 1.0. Default = 0.45. */
FMOD_DSP_FLANGE_WETMIX, /* Volume of flange signal to pass to output. 0.0 to 1.0. Default = 0.55. */
FMOD_DSP_FLANGE_DEPTH, /* Flange depth (percentage of 40ms delay). 0.01 to 1.0. Default = 1.0. */
FMOD_DSP_FLANGE_RATE /* Flange speed in hz. 0.0 to 20.0. Default = 0.1. */
} FMOD_DSP_FLANGE;
/*
[ENUM]
[
[DESCRIPTION]
Parameter types for the FMOD_DSP_TYPE_TREMOLO filter.
[REMARKS]
The tremolo effect varies the amplitude of a sound. Depending on the settings, this unit can produce a tremolo, chopper or auto-pan effect.
The shape of the LFO (low freq. oscillator) can morphed between sine, triangle and sawtooth waves using the FMOD_DSP_TREMOLO_SHAPE and FMOD_DSP_TREMOLO_SKEW parameters.
FMOD_DSP_TREMOLO_DUTY and FMOD_DSP_TREMOLO_SQUARE are useful for a chopper-type effect where the first controls the on-time duration and second controls the flatness of the envelope.
FMOD_DSP_TREMOLO_SPREAD varies the LFO phase between channels to get an auto-pan effect. This works best with a sine shape LFO.
The LFO can be synchronized using the FMOD_DSP_TREMOLO_PHASE parameter which sets its instantaneous phase.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
DSP::setParameter
DSP::getParameter
FMOD_DSP_TYPE
]
*/
typedef enum
{
FMOD_DSP_TREMOLO_FREQUENCY, /* LFO frequency in Hz. 0.1 to 20. Default = 4. */
FMOD_DSP_TREMOLO_DEPTH, /* Tremolo depth. 0 to 1. Default = 0. */
FMOD_DSP_TREMOLO_SHAPE, /* LFO shape morph between triangle and sine. 0 to 1. Default = 0. */
FMOD_DSP_TREMOLO_SKEW, /* Time-skewing of LFO cycle. -1 to 1. Default = 0. */
FMOD_DSP_TREMOLO_DUTY, /* LFO on-time. 0 to 1. Default = 0.5. */
FMOD_DSP_TREMOLO_SQUARE, /* Flatness of the LFO shape. 0 to 1. Default = 0. */
FMOD_DSP_TREMOLO_PHASE, /* Instantaneous LFO phase. 0 to 1. Default = 0. */
FMOD_DSP_TREMOLO_SPREAD /* Rotation / auto-pan effect. -1 to 1. Default = 0. */
} FMOD_DSP_TREMOLO;
/*
[ENUM]
[
[DESCRIPTION]
Parameter types for the FMOD_DSP_TYPE_DISTORTION filter.
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
DSP::setParameter
DSP::getParameter
FMOD_DSP_TYPE
]
*/
typedef enum
{
FMOD_DSP_DISTORTION_LEVEL /* Distortion value. 0.0 to 1.0. Default = 0.5. */
} FMOD_DSP_DISTORTION;
/*
[ENUM]
[
[DESCRIPTION]
Parameter types for the FMOD_DSP_TYPE_NORMALIZE filter.
[REMARKS]
Normalize amplifies the sound based on the maximum peaks within the signal.
For example if the maximum peaks in the signal were 50% of the bandwidth, it would scale the whole sound by 2.
The lower threshold value makes the normalizer ignores peaks below a certain point, to avoid over-amplification if a loud signal suddenly came in, and also to avoid amplifying to maximum things like background hiss.
Because FMOD is a realtime audio processor, it doesn't have the luxury of knowing the peak for the whole sound (ie it can't see into the future), so it has to process data as it comes in.
To avoid very sudden changes in volume level based on small samples of new data, fmod fades towards the desired amplification which makes for smooth gain control. The fadetime parameter can control this.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
DSP::setParameter
DSP::getParameter
FMOD_DSP_TYPE
]
*/
typedef enum
{
FMOD_DSP_NORMALIZE_FADETIME, /* Time to ramp the silence to full in ms. 0.0 to 20000.0. Default = 5000.0. */
FMOD_DSP_NORMALIZE_THRESHHOLD, /* Lower volume range threshold to ignore. 0.0 to 1.0. Default = 0.1. Raise higher to stop amplification of very quiet signals. */
FMOD_DSP_NORMALIZE_MAXAMP /* Maximum amplification allowed. 1.0 to 100000.0. Default = 20.0. 1.0 = no amplifaction, higher values allow more boost. */
} FMOD_DSP_NORMALIZE;
/*
[ENUM]
[
[DESCRIPTION]
Parameter types for the FMOD_DSP_TYPE_PARAMEQ filter.
[REMARKS]
Parametric EQ is a bandpass filter that attenuates or amplifies a selected frequency and its neighbouring frequencies.
To create a multi-band EQ create multiple FMOD_DSP_TYPE_PARAMEQ units and set each unit to different frequencies, for example 1000hz, 2000hz, 4000hz, 8000hz, 16000hz with a range of 1 octave each.
When a frequency has its gain set to 1.0, the sound will be unaffected and represents the original signal exactly.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
DSP::setParameter
DSP::getParameter
FMOD_DSP_TYPE
]
*/
typedef enum
{
FMOD_DSP_PARAMEQ_CENTER, /* Frequency center. 20.0 to 22000.0. Default = 8000.0. */
FMOD_DSP_PARAMEQ_BANDWIDTH, /* Octave range around the center frequency to filter. 0.2 to 5.0. Default = 1.0. */
FMOD_DSP_PARAMEQ_GAIN /* Frequency Gain. 0.05 to 3.0. Default = 1.0. */
} FMOD_DSP_PARAMEQ;
/*
[ENUM]
[
[DESCRIPTION]
Parameter types for the FMOD_DSP_TYPE_PITCHSHIFT filter.
[REMARKS]
This pitch shifting unit can be used to change the pitch of a sound without speeding it up or slowing it down.
It can also be used for time stretching or scaling, for example if the pitch was doubled, and the frequency of the sound was halved, the pitch of the sound would sound correct but it would be twice as slow.
<b>Warning!</b> This filter is very computationally expensive! Similar to a vocoder, it requires several overlapping FFT and IFFT's to produce smooth output, and can require around 440mhz for 1 stereo 48khz signal using the default settings.
Reducing the signal to mono will half the cpu usage.
Reducing this will lower audio quality, but what settings to use are largely dependant on the sound being played. A noisy polyphonic signal will need higher fft size compared to a speaking voice for example.
This pitch shifter is based on the pitch shifter code at http://www.dspdimension.com, written by Stephan M. Bernsee.
The original code is COPYRIGHT 1999-2003 Stephan M. Bernsee <smb@dspdimension.com>.
'<i>maxchannels</i>' dictates the amount of memory allocated. By default, the maxchannels value is 0. If FMOD is set to stereo, the pitch shift unit will allocate enough memory for 2 channels. If it is 5.1, it will allocate enough memory for a 6 channel pitch shift, etc.
If the pitch shift effect is only ever applied to the global mix (ie it was added with System::addDSP), then 0 is the value to set as it will be enough to handle all speaker modes.
When the pitch shift is added to a channel (ie Channel::addDSP) then the channel count that comes in could be anything from 1 to 8 possibly. It is only in this case where you might want to increase the channel count above the output's channel count.
If a channel pitch shift is set to a lower number than the sound's channel count that is coming in, it will not pitch shift the sound.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
DSP::setParameter
DSP::getParameter
FMOD_DSP_TYPE
]
*/
typedef enum
{
FMOD_DSP_PITCHSHIFT_PITCH, /* Pitch value. 0.5 to 2.0. Default = 1.0. 0.5 = one octave down, 2.0 = one octave up. 1.0 does not change the pitch. */
FMOD_DSP_PITCHSHIFT_FFTSIZE, /* FFT window size. 256, 512, 1024, 2048, 4096. Default = 1024. Increase this to reduce 'smearing'. This effect is a warbling sound similar to when an mp3 is encoded at very low bitrates. */
FMOD_DSP_PITCHSHIFT_OVERLAP, /* Removed. Do not use. FMOD now uses 4 overlaps and cannot be changed. */
FMOD_DSP_PITCHSHIFT_MAXCHANNELS /* Maximum channels supported. 0 to 16. 0 = same as fmod's default output polyphony, 1 = mono, 2 = stereo etc. See remarks for more. Default = 0. It is suggested to leave at 0! */
} FMOD_DSP_PITCHSHIFT;
/*
[ENUM]
[
[DESCRIPTION]
Parameter types for the FMOD_DSP_TYPE_CHORUS filter.
[REMARKS]
Chrous is an effect where the sound is more 'spacious' due to 1 to 3 versions of the sound being played along side the original signal but with the pitch of each copy modulating on a sine wave.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
DSP::setParameter
DSP::getParameter
FMOD_DSP_TYPE
]
*/
typedef enum
{
FMOD_DSP_CHORUS_DRYMIX, /* Volume of original signal to pass to output. 0.0 to 1.0. Default = 0.5. */
FMOD_DSP_CHORUS_WETMIX1, /* Volume of 1st chorus tap. 0.0 to 1.0. Default = 0.5. */
FMOD_DSP_CHORUS_WETMIX2, /* Volume of 2nd chorus tap. This tap is 90 degrees out of phase of the first tap. 0.0 to 1.0. Default = 0.5. */
FMOD_DSP_CHORUS_WETMIX3, /* Volume of 3rd chorus tap. This tap is 90 degrees out of phase of the second tap. 0.0 to 1.0. Default = 0.5. */
FMOD_DSP_CHORUS_DELAY, /* Chorus delay in ms. 0.1 to 100.0. Default = 40.0 ms. */
FMOD_DSP_CHORUS_RATE, /* Chorus modulation rate in hz. 0.0 to 20.0. Default = 0.8 hz. */
FMOD_DSP_CHORUS_DEPTH /* Chorus modulation depth. 0.0 to 1.0. Default = 0.03. */
} FMOD_DSP_CHORUS;
/*
[ENUM]
[
[DESCRIPTION]
Parameter types for the FMOD_DSP_TYPE_ITECHO filter.
This is effectively a software based echo filter that emulates the DirectX DMO echo effect. Impulse tracker files can support this, and FMOD will produce the effect on ANY platform, not just those that support DirectX effects!
[REMARKS]
Note. Every time the delay is changed, the plugin re-allocates the echo buffer. This means the echo will dissapear at that time while it refills its new buffer.
Larger echo delays result in larger amounts of memory allocated.
As this is a stereo filter made mainly for IT playback, it is targeted for stereo signals.
With mono signals only the FMOD_DSP_ITECHO_LEFTDELAY is used.
For multichannel signals (>2) there will be no echo on those channels.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
DSP::SetParameter
DSP::GetParameter
FMOD_DSP_TYPE
System::addDSP
]
*/
typedef enum
{
FMOD_DSP_ITECHO_WETDRYMIX, /* Ratio of wet (processed) signal to dry (unprocessed) signal. Must be in the range from 0.0 through 100.0 (all wet). The default value is 50. */
FMOD_DSP_ITECHO_FEEDBACK, /* Percentage of output fed back into input, in the range from 0.0 through 100.0. The default value is 50. */
FMOD_DSP_ITECHO_LEFTDELAY, /* Delay for left channel, in milliseconds, in the range from 1.0 through 2000.0. The default value is 500 ms. */
FMOD_DSP_ITECHO_RIGHTDELAY, /* Delay for right channel, in milliseconds, in the range from 1.0 through 2000.0. The default value is 500 ms. */
FMOD_DSP_ITECHO_PANDELAY /* Value that specifies whether to swap left and right delays with each successive echo. The default value is zero, meaning no swap. Possible values are defined as 0.0 (equivalent to FALSE) and 1.0 (equivalent to TRUE). CURRENTLY NOT SUPPORTED. */
} FMOD_DSP_ITECHO;
/*
[ENUM]
[
[DESCRIPTION]
Parameter types for the FMOD_DSP_TYPE_COMPRESSOR unit.
This is a simple linked multichannel software limiter that is uniform across the whole spectrum.
[REMARKS]
The limiter is not guaranteed to catch every peak above the threshold level,
because it cannot apply gain reduction instantaneously - the time delay is
determined by the attack time. However setting the attack time too short will
distort the sound, so it is a compromise. High level peaks can be avoided by
using a short attack time - but not too short, and setting the threshold a few
decibels below the critical level.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
DSP::SetParameter
DSP::GetParameter
FMOD_DSP_TYPE
System::addDSP
]
*/
typedef enum
{
FMOD_DSP_COMPRESSOR_THRESHOLD, /* Threshold level (dB) in the range from -60 through 0. The default value is 0. */
FMOD_DSP_COMPRESSOR_ATTACK, /* Gain reduction attack time (milliseconds), in the range from 10 through 200. The default value is 50. */
FMOD_DSP_COMPRESSOR_RELEASE, /* Gain reduction release time (milliseconds), in the range from 20 through 1000. The default value is 50. */
FMOD_DSP_COMPRESSOR_GAINMAKEUP /* Make-up gain (dB) applied after limiting, in the range from 0 through 30. The default value is 0. */
} FMOD_DSP_COMPRESSOR;
/*
[ENUM]
[
[DESCRIPTION]
Parameter types for the FMOD_DSP_TYPE_SFXREVERB unit.
[REMARKS]
This is a high quality I3DL2 based reverb.
On top of the I3DL2 property set, "Dry Level" is also included to allow the dry mix to be changed.
These properties can be set with presets in FMOD_REVERB_PRESETS.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
DSP::SetParameter
DSP::GetParameter
FMOD_DSP_TYPE
System::addDSP
FMOD_REVERB_PRESETS
]
*/
typedef enum
{
FMOD_DSP_SFXREVERB_DRYLEVEL, /* Dry Level : Mix level of dry signal in output in mB. Ranges from -10000.0 to 0.0. Default is 0. */
FMOD_DSP_SFXREVERB_ROOM, /* Room : Room effect level at low frequencies in mB. Ranges from -10000.0 to 0.0. Default is -10000.0. */
FMOD_DSP_SFXREVERB_ROOMHF, /* Room HF : Room effect high-frequency level re. low frequency level in mB. Ranges from -10000.0 to 0.0. Default is 0.0. */
FMOD_DSP_SFXREVERB_DECAYTIME, /* Decay Time : Reverberation decay time at low-frequencies in seconds. Ranges from 0.1 to 20.0. Default is 1.0. */
FMOD_DSP_SFXREVERB_DECAYHFRATIO, /* Decay HF Ratio : High-frequency to low-frequency decay time ratio. Ranges from 0.1 to 2.0. Default is 0.5. */
FMOD_DSP_SFXREVERB_REFLECTIONSLEVEL, /* Reflections : Early reflections level relative to room effect in mB. Ranges from -10000.0 to 1000.0. Default is -10000.0. */
FMOD_DSP_SFXREVERB_REFLECTIONSDELAY, /* Reflect Delay : Delay time of first reflection in seconds. Ranges from 0.0 to 0.3. Default is 0.02. */
FMOD_DSP_SFXREVERB_REVERBLEVEL, /* Reverb : Late reverberation level relative to room effect in mB. Ranges from -10000.0 to 2000.0. Default is 0.0. */
FMOD_DSP_SFXREVERB_REVERBDELAY, /* Reverb Delay : Late reverberation delay time relative to first reflection in seconds. Ranges from 0.0 to 0.1. Default is 0.04. */
FMOD_DSP_SFXREVERB_DIFFUSION, /* Diffusion : Reverberation diffusion (echo density) in percent. Ranges from 0.0 to 100.0. Default is 100.0. */
FMOD_DSP_SFXREVERB_DENSITY, /* Density : Reverberation density (modal density) in percent. Ranges from 0.0 to 100.0. Default is 100.0. */
FMOD_DSP_SFXREVERB_HFREFERENCE, /* HF Reference : Reference high frequency in Hz. Ranges from 20.0 to 20000.0. Default is 5000.0. */
FMOD_DSP_SFXREVERB_ROOMLF, /* Room LF : Room effect low-frequency level in mB. Ranges from -10000.0 to 0.0. Default is 0.0. */
FMOD_DSP_SFXREVERB_LFREFERENCE /* LF Reference : Reference low-frequency in Hz. Ranges from 20.0 to 1000.0. Default is 250.0. */
} FMOD_DSP_SFXREVERB;
/*
[ENUM]
[
[DESCRIPTION]
Parameter types for the FMOD_DSP_TYPE_LOWPASS_SIMPLE filter.
This is a very simple low pass filter, based on two single-pole RC time-constant modules.
The emphasis is on speed rather than accuracy, so this should not be used for task requiring critical filtering.
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
DSP::setParameter
DSP::getParameter
FMOD_DSP_TYPE
]
*/
typedef enum
{
FMOD_DSP_LOWPASS_SIMPLE_CUTOFF /* Lowpass cutoff frequency in hz. 10.0 to 22000.0. Default = 5000.0 */
} FMOD_DSP_LOWPASS_SIMPLE;
/*
[ENUM]
[
[DESCRIPTION]
Parameter types for the FMOD_DSP_TYPE_HIGHPASS_SIMPLE filter.
This is a very simple single-order high pass filter.
The emphasis is on speed rather than accuracy, so this should not be used for task requiring critical filtering.
[REMARKS]
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
DSP::setParameter
DSP::getParameter
FMOD_DSP_TYPE
]
*/
typedef enum
{
FMOD_DSP_HIGHPASS_SIMPLE_CUTOFF /* Highpass cutoff frequency in hz. 10.0 to 22000.0. Default = 1000.0 */
} FMOD_DSP_HIGHPASS_SIMPLE;
#endif

View file

@ -1,123 +0,0 @@
/* ============================================================================================== */
/* FMOD Ex - Error string header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2011. */
/* */
/* Use this header if you want to store or display a string version / english explanation of */
/* the FMOD error codes. */
/* */
/* ============================================================================================== */
#ifndef _FMOD_ERRORS_H
#define _FMOD_ERRORS_H
#include "fmod.h"
#ifdef __GNUC__
static const char *FMOD_ErrorString(FMOD_RESULT errcode) __attribute__((unused));
#endif
static const char *FMOD_ErrorString(FMOD_RESULT errcode)
{
switch (errcode)
{
case FMOD_ERR_ALREADYLOCKED: return "Tried to call lock a second time before unlock was called. ";
case FMOD_ERR_BADCOMMAND: return "Tried to call a function on a data type that does not allow this type of functionality (ie calling Sound::lock on a streaming sound). ";
case FMOD_ERR_CDDA_DRIVERS: return "Neither NTSCSI nor ASPI could be initialised. ";
case FMOD_ERR_CDDA_INIT: return "An error occurred while initialising the CDDA subsystem. ";
case FMOD_ERR_CDDA_INVALID_DEVICE: return "Couldn't find the specified device. ";
case FMOD_ERR_CDDA_NOAUDIO: return "No audio tracks on the specified disc. ";
case FMOD_ERR_CDDA_NODEVICES: return "No CD/DVD devices were found. ";
case FMOD_ERR_CDDA_NODISC: return "No disc present in the specified drive. ";
case FMOD_ERR_CDDA_READ: return "A CDDA read error occurred. ";
case FMOD_ERR_CHANNEL_ALLOC: return "Error trying to allocate a channel. ";
case FMOD_ERR_CHANNEL_STOLEN: return "The specified channel has been reused to play another sound. ";
case FMOD_ERR_COM: return "A Win32 COM related error occured. COM failed to initialize or a QueryInterface failed meaning a Windows codec or driver was not installed properly. ";
case FMOD_ERR_DMA: return "DMA Failure. See debug output for more information. ";
case FMOD_ERR_DSP_CONNECTION: return "DSP connection error. Connection possibly caused a cyclic dependancy. Or tried to connect a tree too many units deep (more than 128). ";
case FMOD_ERR_DSP_FORMAT: return "DSP Format error. A DSP unit may have attempted to connect to this network with the wrong format. ";
case FMOD_ERR_DSP_NOTFOUND: return "DSP connection error. Couldn't find the DSP unit specified. ";
case FMOD_ERR_DSP_RUNNING: return "DSP error. Cannot perform this operation while the network is in the middle of running. This will most likely happen if a connection or disconnection is attempted in a DSP callback. ";
case FMOD_ERR_DSP_TOOMANYCONNECTIONS: return "DSP connection error. The unit being connected to or disconnected should only have 1 input or output. ";
case FMOD_ERR_EVENT_ALREADY_LOADED: return "The specified project or bank has already been loaded. Having multiple copies of the same project loaded simultaneously is forbidden. ";
case FMOD_ERR_EVENT_FAILED: return "An Event failed to be retrieved, most likely due to 'just fail' being specified as the max playbacks behavior. ";
case FMOD_ERR_EVENT_GUIDCONFLICT: return "An event with the same GUID already exists. ";
case FMOD_ERR_EVENT_INFOONLY: return "Can't execute this command on an EVENT_INFOONLY event. ";
case FMOD_ERR_EVENT_INTERNAL: return "An error occured that wasn't supposed to. See debug log for reason. ";
case FMOD_ERR_EVENT_MAXSTREAMS: return "Event failed because 'Max streams' was hit when FMOD_EVENT_INIT_FAIL_ON_MAXSTREAMS was specified. ";
case FMOD_ERR_EVENT_MISMATCH: return "FSB mismatches the FEV it was compiled with, the stream/sample mode it was meant to be created with was different, or the FEV was built for a different platform. ";
case FMOD_ERR_EVENT_NAMECONFLICT: return "A category with the same name already exists. ";
case FMOD_ERR_EVENT_NEEDSSIMPLE: return "Tried to call a function on a complex event that's only supported by simple events. ";
case FMOD_ERR_EVENT_NOTFOUND: return "The requested event, event group, event category or event property could not be found. ";
case FMOD_ERR_FILE_BAD: return "Error loading file. ";
case FMOD_ERR_FILE_COULDNOTSEEK: return "Couldn't perform seek operation. This is a limitation of the medium (ie netstreams) or the file format. ";
case FMOD_ERR_FILE_DISKEJECTED: return "Media was ejected while reading. ";
case FMOD_ERR_FILE_EOF: return "End of file unexpectedly reached while trying to read essential data (truncated data?). ";
case FMOD_ERR_FILE_NOTFOUND: return "File not found. ";
case FMOD_ERR_FILE_UNWANTED: return "Unwanted file access occured. ";
case FMOD_ERR_FORMAT: return "Unsupported file or audio format. ";
case FMOD_ERR_HTTP: return "A HTTP error occurred. This is a catch-all for HTTP errors not listed elsewhere. ";
case FMOD_ERR_HTTP_ACCESS: return "The specified resource requires authentication or is forbidden. ";
case FMOD_ERR_HTTP_PROXY_AUTH: return "Proxy authentication is required to access the specified resource. ";
case FMOD_ERR_HTTP_SERVER_ERROR: return "A HTTP server error occurred. ";
case FMOD_ERR_HTTP_TIMEOUT: return "The HTTP request timed out. ";
case FMOD_ERR_INITIALIZATION: return "FMOD was not initialized correctly to support this function. ";
case FMOD_ERR_INITIALIZED: return "Cannot call this command after System::init. ";
case FMOD_ERR_INTERNAL: return "An error occured that wasn't supposed to. Contact support. ";
case FMOD_ERR_INVALID_ADDRESS: return "On Xbox 360, this memory address passed to FMOD must be physical, (ie allocated with XPhysicalAlloc.) ";
case FMOD_ERR_INVALID_FLOAT: return "Value passed in was a NaN, Inf or denormalized float. ";
case FMOD_ERR_INVALID_HANDLE: return "An invalid object handle was used. ";
case FMOD_ERR_INVALID_PARAM: return "An invalid parameter was passed to this function. ";
case FMOD_ERR_INVALID_POSITION: return "An invalid seek position was passed to this function. ";
case FMOD_ERR_INVALID_SPEAKER: return "An invalid speaker was passed to this function based on the current speaker mode. ";
case FMOD_ERR_INVALID_SYNCPOINT: return "The syncpoint did not come from this sound handle. ";
case FMOD_ERR_INVALID_VECTOR: return "The vectors passed in are not unit length, or perpendicular. ";
case FMOD_ERR_MAXAUDIBLE: return "Reached maximum audible playback count for this sound's soundgroup. ";
case FMOD_ERR_MEMORY: return "Not enough memory or resources. ";
case FMOD_ERR_MEMORY_CANTPOINT: return "Can't use FMOD_OPENMEMORY_POINT on non PCM source data, or non mp3/xma/adpcm data if FMOD_CREATECOMPRESSEDSAMPLE was used. ";
case FMOD_ERR_MEMORY_SRAM: return "Not enough memory or resources on console sound ram. ";
case FMOD_ERR_MUSIC_NOCALLBACK: return "The music callback is required, but it has not been set. ";
case FMOD_ERR_MUSIC_NOTFOUND: return "The requested music entity could not be found. ";
case FMOD_ERR_MUSIC_UNINITIALIZED: return "Music system is not initialized probably because no music data is loaded. ";
case FMOD_ERR_NEEDS2D: return "Tried to call a command on a 3d sound when the command was meant for 2d sound. ";
case FMOD_ERR_NEEDS3D: return "Tried to call a command on a 2d sound when the command was meant for 3d sound. ";
case FMOD_ERR_NEEDSHARDWARE: return "Tried to use a feature that requires hardware support. (ie trying to play a GCADPCM compressed sound in software on Wii). ";
case FMOD_ERR_NEEDSSOFTWARE: return "Tried to use a feature that requires the software engine. Software engine has either been turned off, or command was executed on a hardware channel which does not support this feature. ";
case FMOD_ERR_NET_CONNECT: return "Couldn't connect to the specified host. ";
case FMOD_ERR_NET_SOCKET_ERROR: return "A socket error occurred. This is a catch-all for socket-related errors not listed elsewhere. ";
case FMOD_ERR_NET_URL: return "The specified URL couldn't be resolved. ";
case FMOD_ERR_NET_WOULD_BLOCK: return "Operation on a non-blocking socket could not complete immediately. ";
case FMOD_ERR_NOTREADY: return "Operation could not be performed because specified sound/DSP connection is not ready. ";
case FMOD_ERR_OUTPUT_ALLOCATED: return "Error initializing output device, but more specifically, the output device is already in use and cannot be reused. ";
case FMOD_ERR_OUTPUT_CREATEBUFFER: return "Error creating hardware sound buffer. ";
case FMOD_ERR_OUTPUT_DRIVERCALL: return "A call to a standard soundcard driver failed, which could possibly mean a bug in the driver or resources were missing or exhausted. ";
case FMOD_ERR_OUTPUT_ENUMERATION: return "Error enumerating the available driver list. List may be inconsistent due to a recent device addition or removal. ";
case FMOD_ERR_OUTPUT_FORMAT: return "Soundcard does not support the minimum features needed for this soundsystem (16bit stereo output). ";
case FMOD_ERR_OUTPUT_INIT: return "Error initializing output device. ";
case FMOD_ERR_OUTPUT_NOHARDWARE: return "FMOD_HARDWARE was specified but the sound card does not have the resources necessary to play it. ";
case FMOD_ERR_OUTPUT_NOSOFTWARE: return "Attempted to create a software sound but no software channels were specified in System::init. ";
case FMOD_ERR_PAN: return "Panning only works with mono or stereo sound sources. ";
case FMOD_ERR_PLUGIN: return "An unspecified error has been returned from a 3rd party plugin. ";
case FMOD_ERR_PLUGIN_INSTANCES: return "The number of allowed instances of a plugin has been exceeded. ";
case FMOD_ERR_PLUGIN_MISSING: return "A requested output, dsp unit type or codec was not available. ";
case FMOD_ERR_PLUGIN_RESOURCE: return "A resource that the plugin requires cannot be found. (ie the DLS file for MIDI playback or other DLLs that it needs to load) ";
case FMOD_ERR_PRELOADED: return "The specified sound is still in use by the event system, call EventSystem::unloadFSB before trying to release it. ";
case FMOD_ERR_PROGRAMMERSOUND: return "The specified sound is still in use by the event system, wait for the event which is using it finish with it. ";
case FMOD_ERR_RECORD: return "An error occured trying to initialize the recording device. ";
case FMOD_ERR_REVERB_INSTANCE: return "Specified instance in FMOD_REVERB_PROPERTIES couldn't be set. Most likely because it is an invalid instance number or the reverb doesnt exist. ";
case FMOD_ERR_SUBSOUNDS: return "The error occured because the sound referenced contains subsounds when it shouldn't have, or it doesn't contain subsounds when it should have. The operation may also not be able to be performed on a parent sound, or a parent sound was played without setting up a sentence first. ";
case FMOD_ERR_SUBSOUND_ALLOCATED: return "This subsound is already being used by another sound, you cannot have more than one parent to a sound. Null out the other parent's entry first. ";
case FMOD_ERR_SUBSOUND_CANTMOVE: return "Shared subsounds cannot be replaced or moved from their parent stream, such as when the parent stream is an FSB file. ";
case FMOD_ERR_SUBSOUND_MODE: return "The subsound's mode bits do not match with the parent sound's mode bits. See documentation for function that it was called with. ";
case FMOD_ERR_TAGNOTFOUND: return "The specified tag could not be found or there are no tags. ";
case FMOD_ERR_TOOMANYCHANNELS: return "The sound created exceeds the allowable input channel count. This can be increased using the maxinputchannels parameter in System::setSoftwareFormat. ";
case FMOD_ERR_UNIMPLEMENTED: return "Something in FMOD hasn't been implemented when it should be! contact support! ";
case FMOD_ERR_UNINITIALIZED: return "This command failed because System::init or System::setDriver was not called. ";
case FMOD_ERR_UNSUPPORTED: return "A command issued was not supported by this object. Possibly a plugin without certain callbacks specified. ";
case FMOD_ERR_UPDATE: return "An error caused by System::update occured. ";
case FMOD_ERR_VERSION: return "The version number of this file format is not supported. ";
case FMOD_OK: return "No errors.";
default : return "Unknown error.";
};
}
#endif

View file

@ -1,201 +0,0 @@
/* ============================================================================================= */
/* FMOD Ex - Memory info header file. Copyright (c), Firelight Technologies Pty, Ltd. 2008-2011. */
/* */
/* Use this header if you are interested in getting detailed information on FMOD's memory */
/* usage. See the documentation for more details. */
/* */
/* ============================================================================================= */
#ifndef _FMOD_MEMORYINFO_H
#define _FMOD_MEMORYINFO_H
/*
[STRUCTURE]
[
[DESCRIPTION]
Structure to be filled with detailed memory usage information of an FMOD object
[REMARKS]
Every public FMOD class has a getMemoryInfo function which can be used to get detailed information on what memory resources are associated with the object in question.
On return from getMemoryInfo, each member of this structure will hold the amount of memory used for its type in bytes.
Members marked with [in] mean the user sets the value before passing it to the function.
Members marked with [out] mean FMOD sets the value to be used after the function exits.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
System::getMemoryInfo
EventSystem::getMemoryInfo
FMOD_MEMBITS
FMOD_EVENT_MEMBITS
]
*/
typedef struct FMOD_MEMORY_USAGE_DETAILS
{
unsigned int other; /* [out] Memory not accounted for by other types */
unsigned int string; /* [out] String data */
unsigned int system; /* [out] System object and various internals */
unsigned int plugins; /* [out] Plugin objects and internals */
unsigned int output; /* [out] Output module object and internals */
unsigned int channel; /* [out] Channel related memory */
unsigned int channelgroup; /* [out] ChannelGroup objects and internals */
unsigned int codec; /* [out] Codecs allocated for streaming */
unsigned int file; /* [out] File buffers and structures */
unsigned int sound; /* [out] Sound objects and internals */
unsigned int secondaryram; /* [out] Sound data stored in secondary RAM */
unsigned int soundgroup; /* [out] SoundGroup objects and internals */
unsigned int streambuffer; /* [out] Stream buffer memory */
unsigned int dspconnection; /* [out] DSPConnection objects and internals */
unsigned int dsp; /* [out] DSP implementation objects */
unsigned int dspcodec; /* [out] Realtime file format decoding DSP objects */
unsigned int profile; /* [out] Profiler memory footprint. */
unsigned int recordbuffer; /* [out] Buffer used to store recorded data from microphone */
unsigned int reverb; /* [out] Reverb implementation objects */
unsigned int reverbchannelprops; /* [out] Reverb channel properties structs */
unsigned int geometry; /* [out] Geometry objects and internals */
unsigned int syncpoint; /* [out] Sync point memory. */
unsigned int eventsystem; /* [out] EventSystem and various internals */
unsigned int musicsystem; /* [out] MusicSystem and various internals */
unsigned int fev; /* [out] Definition of objects contained in all loaded projects e.g. events, groups, categories */
unsigned int memoryfsb; /* [out] Data loaded with preloadFSB */
unsigned int eventproject; /* [out] EventProject objects and internals */
unsigned int eventgroupi; /* [out] EventGroup objects and internals */
unsigned int soundbankclass; /* [out] Objects used to manage wave banks */
unsigned int soundbanklist; /* [out] Data used to manage lists of wave bank usage */
unsigned int streaminstance; /* [out] Stream objects and internals */
unsigned int sounddefclass; /* [out] Sound definition objects */
unsigned int sounddefdefclass; /* [out] Sound definition static data objects */
unsigned int sounddefpool; /* [out] Sound definition pool data */
unsigned int reverbdef; /* [out] Reverb definition objects */
unsigned int eventreverb; /* [out] Reverb objects */
unsigned int userproperty; /* [out] User property objects */
unsigned int eventinstance; /* [out] Event instance base objects */
unsigned int eventinstance_complex; /* [out] Complex event instance objects */
unsigned int eventinstance_simple; /* [out] Simple event instance objects */
unsigned int eventinstance_layer; /* [out] Event layer instance objects */
unsigned int eventinstance_sound; /* [out] Event sound instance objects */
unsigned int eventenvelope; /* [out] Event envelope objects */
unsigned int eventenvelopedef; /* [out] Event envelope definition objects */
unsigned int eventparameter; /* [out] Event parameter objects */
unsigned int eventcategory; /* [out] Event category objects */
unsigned int eventenvelopepoint; /* [out] Event envelope point objects */
unsigned int eventinstancepool; /* [out] Event instance pool memory */
} FMOD_MEMORY_USAGE_DETAILS;
/*
[DEFINE]
[
[NAME]
FMOD_MEMBITS
[DESCRIPTION]
Bitfield used to request specific memory usage information from the getMemoryInfo function of every public FMOD Ex class.
Use with the "memorybits" parameter of getMemoryInfo to get information on FMOD Ex memory usage.
[REMARKS]
Every public FMOD class has a getMemoryInfo function which can be used to get detailed information on what memory resources are associated with the object in question.
The FMOD_MEMBITS defines can be OR'd together to specify precisely what memory usage you'd like to get information on. See System::getMemoryInfo for an example.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
FMOD_EVENT_MEMBITS
System::getMemoryInfo
]
*/
#define FMOD_MEMBITS_OTHER 0x00000001 /* Memory not accounted for by other types */
#define FMOD_MEMBITS_STRING 0x00000002 /* String data */
#define FMOD_MEMBITS_SYSTEM 0x00000004 /* System object and various internals */
#define FMOD_MEMBITS_PLUGINS 0x00000008 /* Plugin objects and internals */
#define FMOD_MEMBITS_OUTPUT 0x00000010 /* Output module object and internals */
#define FMOD_MEMBITS_CHANNEL 0x00000020 /* Channel related memory */
#define FMOD_MEMBITS_CHANNELGROUP 0x00000040 /* ChannelGroup objects and internals */
#define FMOD_MEMBITS_CODEC 0x00000080 /* Codecs allocated for streaming */
#define FMOD_MEMBITS_FILE 0x00000100 /* Codecs allocated for streaming */
#define FMOD_MEMBITS_SOUND 0x00000200 /* Sound objects and internals */
#define FMOD_MEMBITS_SOUND_SECONDARYRAM 0x00000400 /* Sound data stored in secondary RAM */
#define FMOD_MEMBITS_SOUNDGROUP 0x00000800 /* SoundGroup objects and internals */
#define FMOD_MEMBITS_STREAMBUFFER 0x00001000 /* Stream buffer memory */
#define FMOD_MEMBITS_DSPCONNECTION 0x00002000 /* DSPConnection objects and internals */
#define FMOD_MEMBITS_DSP 0x00004000 /* DSP implementation objects */
#define FMOD_MEMBITS_DSPCODEC 0x00008000 /* Realtime file format decoding DSP objects */
#define FMOD_MEMBITS_PROFILE 0x00010000 /* Profiler memory footprint. */
#define FMOD_MEMBITS_RECORDBUFFER 0x00020000 /* Buffer used to store recorded data from microphone */
#define FMOD_MEMBITS_REVERB 0x00040000 /* Reverb implementation objects */
#define FMOD_MEMBITS_REVERBCHANNELPROPS 0x00080000 /* Reverb channel properties structs */
#define FMOD_MEMBITS_GEOMETRY 0x00100000 /* Geometry objects and internals */
#define FMOD_MEMBITS_SYNCPOINT 0x00200000 /* Sync point memory. */
#define FMOD_MEMBITS_ALL 0xffffffff /* All memory used by FMOD Ex */
/* [DEFINE_END] */
/*
[DEFINE]
[
[NAME]
FMOD_EVENT_MEMBITS
[DESCRIPTION]
Bitfield used to request specific memory usage information from the getMemoryInfo function of every public FMOD Event System class.
Use with the "event_memorybits" parameter of getMemoryInfo to get information on FMOD Event System memory usage.
[REMARKS]
Every public FMOD Event System class has a getMemoryInfo function which can be used to get detailed information on what memory resources are associated with the object in question.
The FMOD_EVENT_MEMBITS defines can be OR'd together to specify precisely what memory usage you'd like to get information on. See EventSystem::getMemoryInfo for an example.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
FMOD_MEMBITS
System::getMemoryInfo
]
*/
#define FMOD_EVENT_MEMBITS_EVENTSYSTEM 0x00000001 /* EventSystem and various internals */
#define FMOD_EVENT_MEMBITS_MUSICSYSTEM 0x00000002 /* MusicSystem and various internals */
#define FMOD_EVENT_MEMBITS_FEV 0x00000004 /* Definition of objects contained in all loaded projects e.g. events, groups, categories */
#define FMOD_EVENT_MEMBITS_MEMORYFSB 0x00000008 /* Data loaded with preloadFSB */
#define FMOD_EVENT_MEMBITS_EVENTPROJECT 0x00000010 /* EventProject objects and internals */
#define FMOD_EVENT_MEMBITS_EVENTGROUPI 0x00000020 /* EventGroup objects and internals */
#define FMOD_EVENT_MEMBITS_SOUNDBANKCLASS 0x00000040 /* Objects used to manage wave banks */
#define FMOD_EVENT_MEMBITS_SOUNDBANKLIST 0x00000080 /* Data used to manage lists of wave bank usage */
#define FMOD_EVENT_MEMBITS_STREAMINSTANCE 0x00000100 /* Stream objects and internals */
#define FMOD_EVENT_MEMBITS_SOUNDDEFCLASS 0x00000200 /* Sound definition objects */
#define FMOD_EVENT_MEMBITS_SOUNDDEFDEFCLASS 0x00000400 /* Sound definition static data objects */
#define FMOD_EVENT_MEMBITS_SOUNDDEFPOOL 0x00000800 /* Sound definition pool data */
#define FMOD_EVENT_MEMBITS_REVERBDEF 0x00001000 /* Reverb definition objects */
#define FMOD_EVENT_MEMBITS_EVENTREVERB 0x00002000 /* Reverb objects */
#define FMOD_EVENT_MEMBITS_USERPROPERTY 0x00004000 /* User property objects */
#define FMOD_EVENT_MEMBITS_EVENTINSTANCE 0x00008000 /* Event instance base objects */
#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_COMPLEX 0x00010000 /* Complex event instance objects */
#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_SIMPLE 0x00020000 /* Simple event instance objects */
#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_LAYER 0x00040000 /* Event layer instance objects */
#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_SOUND 0x00080000 /* Event sound instance objects */
#define FMOD_EVENT_MEMBITS_EVENTENVELOPE 0x00100000 /* Event envelope objects */
#define FMOD_EVENT_MEMBITS_EVENTENVELOPEDEF 0x00200000 /* Event envelope definition objects */
#define FMOD_EVENT_MEMBITS_EVENTPARAMETER 0x00400000 /* Event parameter objects */
#define FMOD_EVENT_MEMBITS_EVENTCATEGORY 0x00800000 /* Event category objects */
#define FMOD_EVENT_MEMBITS_EVENTENVELOPEPOINT 0x01000000 /* Event envelope point object+s */
#define FMOD_EVENT_MEMBITS_EVENTINSTANCEPOOL 0x02000000 /* Event instance pool data */
#define FMOD_EVENT_MEMBITS_ALL 0xffffffff /* All memory used by FMOD Event System */
/* All event instance memory */
#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_GROUP (FMOD_EVENT_MEMBITS_EVENTINSTANCE | \
FMOD_EVENT_MEMBITS_EVENTINSTANCE_COMPLEX | \
FMOD_EVENT_MEMBITS_EVENTINSTANCE_SIMPLE | \
FMOD_EVENT_MEMBITS_EVENTINSTANCE_LAYER | \
FMOD_EVENT_MEMBITS_EVENTINSTANCE_SOUND)
/* All sound definition memory */
#define FMOD_EVENT_MEMBITS_SOUNDDEF_GROUP (FMOD_EVENT_MEMBITS_SOUNDDEFCLASS | \
FMOD_EVENT_MEMBITS_SOUNDDEFDEFCLASS | \
FMOD_EVENT_MEMBITS_SOUNDDEFPOOL)
/* [DEFINE_END] */
#endif

View file

@ -1,93 +0,0 @@
/* ==================================================================================================== */
/* FMOD Ex - output development header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2011. */
/* */
/* Use this header if you are wanting to develop your own output plugin to use with */
/* FMOD's output system. With this header you can make your own output plugin that FMOD */
/* can register and use. See the documentation and examples on how to make a working plugin. */
/* */
/* ==================================================================================================== */
#ifndef _FMOD_OUTPUT_H
#define _FMOD_OUTPUT_H
#include "fmod.h"
typedef struct FMOD_OUTPUT_STATE FMOD_OUTPUT_STATE;
/*
Output callbacks
*/
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETNUMDRIVERSCALLBACK)(FMOD_OUTPUT_STATE *output_state, int *numdrivers);
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETDRIVERNAMECALLBACK)(FMOD_OUTPUT_STATE *output_state, int id, char *name, int namelen);
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETDRIVERCAPSCALLBACK)(FMOD_OUTPUT_STATE *output_state, int id, FMOD_CAPS *caps);
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_INITCALLBACK) (FMOD_OUTPUT_STATE *output_state, int selecteddriver, FMOD_INITFLAGS flags, int *outputrate, int outputchannels, FMOD_SOUND_FORMAT *outputformat, int dspbufferlength, int dspnumbuffers, void *extradriverdata);
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_CLOSECALLBACK) (FMOD_OUTPUT_STATE *output_state);
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_UPDATECALLBACK) (FMOD_OUTPUT_STATE *output_state);
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETHANDLECALLBACK) (FMOD_OUTPUT_STATE *output_state, void **handle);
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETPOSITIONCALLBACK) (FMOD_OUTPUT_STATE *output_state, unsigned int *pcm);
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_LOCKCALLBACK) (FMOD_OUTPUT_STATE *output_state, unsigned int offset, unsigned int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2);
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_UNLOCKCALLBACK) (FMOD_OUTPUT_STATE *output_state, void *ptr1, void *ptr2, unsigned int len1, unsigned int len2);
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_READFROMMIXER) (FMOD_OUTPUT_STATE *output_state, void *buffer, unsigned int length);
/*
[STRUCTURE]
[
[DESCRIPTION]
When creating an output, declare one of these and provide the relevant callbacks and name for FMOD to use when it opens and reads a file of this type.
[REMARKS]
Members marked with [in] mean the variable can be written to. The user can set the value.
Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
FMOD_OUTPUT_STATE
]
*/
typedef struct FMOD_OUTPUT_DESCRIPTION
{
const char *name; /* [in] Name of the output. */
unsigned int version; /* [in] Plugin writer's version number. */
int polling; /* [in] If TRUE (non zero), this tells FMOD to start a thread and call getposition / lock / unlock for feeding data. If 0, the output is probably callback based, so all the plugin needs to do is call readfrommixer to the appropriate pointer. */
FMOD_OUTPUT_GETNUMDRIVERSCALLBACK getnumdrivers; /* [in] For sound device enumeration. This callback is to give System::getNumDrivers somthing to return. */
FMOD_OUTPUT_GETDRIVERNAMECALLBACK getdrivername; /* [in] For sound device enumeration. This callback is to give System::getDriverName somthing to return. */
FMOD_OUTPUT_GETDRIVERCAPSCALLBACK getdrivercaps; /* [in] For sound device enumeration. This callback is to give System::getDriverCaps somthing to return. */
FMOD_OUTPUT_INITCALLBACK init; /* [in] Initialization function for the output device. This is called from System::init. */
FMOD_OUTPUT_CLOSECALLBACK close; /* [in] Cleanup / close down function for the output device. This is called from System::close. */
FMOD_OUTPUT_UPDATECALLBACK update; /* [in] Update function that is called once a frame by the user. This is called from System::update. */
FMOD_OUTPUT_GETHANDLECALLBACK gethandle; /* [in] This is called from System::getOutputHandle. This is just to return a pointer to the internal system device object that the system may be using.*/
FMOD_OUTPUT_GETPOSITIONCALLBACK getposition; /* [in] This is called from the FMOD software mixer thread if 'polling' = true. This returns a position value in samples so that FMOD knows where and when to fill its buffer. */
FMOD_OUTPUT_LOCKCALLBACK lock; /* [in] This is called from the FMOD software mixer thread if 'polling' = true. This function provides a pointer to data that FMOD can write to when software mixing. */
FMOD_OUTPUT_UNLOCKCALLBACK unlock; /* [in] This is called from the FMOD software mixer thread if 'polling' = true. This optional function accepts the data that has been mixed and copies it or does whatever it needs to before sending it to the hardware. */
} FMOD_OUTPUT_DESCRIPTION;
/*
[STRUCTURE]
[
[DESCRIPTION]
Output plugin structure that is passed into each callback.
[REMARKS]
Members marked with [in] mean the variable can be written to. The user can set the value.
Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
[PLATFORMS]
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
[SEE_ALSO]
FMOD_OUTPUT_DESCRIPTION
]
*/
struct FMOD_OUTPUT_STATE
{
void *plugindata; /* [in] Plugin writer created data the output author wants to attach to this object. */
FMOD_OUTPUT_READFROMMIXER readfrommixer; /* [out] Function to update mixer and write the result to the provided pointer. Used from callback based output only. Polling based output uses lock/unlock/getposition. */
};
#endif

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,28 +0,0 @@
Which library do I link?
------------------------
If you want to use fmodex.dll:
Visual Studio users - fmodex_vc.lib.
Metrowerks Codewarrior users - fmodex_vc.lib.
Borland users - fmodex_bc.lib.
LCC-Win32 users - fmodex_lcc.lib.
Dev-C++, MinGW and CygWin users - libfmodex.a.
If you want to use fmodexL.dll: (same as fmodex.dll but with debug logging enabled)
Visual Studio users - fmodexL_vc.lib.
Metrowerks Codewarrior users - fmodexL_vc.lib.
Borland users - fmodexL_bc.lib.
LCC-Win32 users - fmodexL_lcc.lib.
Dev-C++, MinGW and CygWin users - libfmodexL.a.
If you want to use fmodex64.dll: (same as fmodex.dll but for 64bit machines)
Visual Studio users - fmodex64_vc.lib.
If you want to use fmodexL64.dll: (same as fmodex64.dll but with debug logging enabled)
Visual Studio users - fmodexL64_vc.lib.
No other compilers are supported for 64bit libraries.

View file

@ -301,13 +301,25 @@ target_compile_definitions(SRB2SDL2 PRIVATE -DCMAKECONFIG)
# ${SRB2_BLUA_HEADERS}
#)
## strip debug symbols into separate file when using gcc.
## to be consistent with Makefile, don't generate for OS X.
if((CMAKE_COMPILER_IS_GNUCC) AND NOT (${CMAKE_SYSTEM} MATCHES Darwin))
if((${CMAKE_BUILD_TYPE} MATCHES Debug) OR (${CMAKE_BUILD_TYPE} MATCHES RelWithDebInfo))
if(${CMAKE_BUILD_TYPE} MATCHES Debug)
set(OBJCOPY_ONLY_KEEP_DEBUG "--only-keep-debug")
endif()
message(STATUS "Will make separate debug symbols in *.debug")
add_custom_command(TARGET SRB2SDL2 POST_BUILD
COMMAND ${OBJCOPY} ${OBJCOPY_ONLY_KEEP_DEBUG} $<TARGET_FILE:SRB2SDL2> $<TARGET_FILE:SRB2SDL2>.debug
COMMAND ${OBJCOPY} --strip-debug $<TARGET_FILE:SRB2SDL2>
COMMAND ${OBJCOPY} --add-gnu-debuglink=$<TARGET_FILE:SRB2SDL2>.debug $<TARGET_FILE:SRB2SDL2>
)
endif()
endif()
add_subdirectory(sdl)
add_subdirectory(objects)
if(${CMAKE_SYSTEM} MATCHES Windows)
add_subdirectory(win32)
endif()
if(NOT ${SRB2_SDL2_AVAILABLE})
message(FATAL_ERROR "There are no targets available to build an SRB2Kart executable. :(")
endif()

View file

@ -193,6 +193,9 @@ nasm_format:=
# also defines the name as a macro to the compiler.
passthru_opts:=
# separate suffix with an underscore
exesuffix:=$(call _,$(EXESUFFIX))
include Makefile.d/platform.mk
include Makefile.d/features.mk
include Makefile.d/versions.mk
@ -230,17 +233,22 @@ endif
objects:=$(addprefix $(objdir)/,$(objects))
ifdef DEBUGMODE
bin:=../bin/debug
EXEDIR?=../bin/debug
else
bin:=../bin
EXEDIR?=../bin
endif
# append branch name by default
ifndef EXENAME
base:=ringracers
branch:=$(shell git symbolic-ref -q --short HEAD)
EXENAME:=$(base)$(call _,$(filter-out master,$(branch)))$(exesuffix)
endif
# default EXENAME (usually set by platform)
EXENAME?=ringracers
DBGNAME?=$(EXENAME).debug
exe:=$(bin)/$(EXENAME)
dbg:=$(bin)/$(DBGNAME)
exe:=$(EXEDIR)/$(EXENAME)
dbg:=$(EXEDIR)/$(DBGNAME)
build_done==== Build is done, look for \
$(<F) at $(abspath $(<D)) ===

View file

@ -91,3 +91,6 @@ endif
endif
.=$(call Ifndef,ECHO,@)
# prepends an underscore if not empty
_=$(if $(1),_$(1))

View file

@ -2,11 +2,7 @@
# Mingw, if you don't know, that's Win32/Win64
#
ifndef MINGW64
EXENAME?=ringracers.exe
else
EXENAME?=ringracers64.exe
endif
exesuffix:=$(exesuffix)$(if $(MINGW64),64).exe
# disable dynamicbase if under msys2
ifdef MSYSTEM

View file

@ -1641,34 +1641,14 @@ void CV_SaveVars(UINT8 **p, boolean in_demo)
// the client will reset all netvars to default before loading
WRITEUINT16(*p, 0x0000);
for (cvar = consvar_vars; cvar; cvar = cvar->next)
if (((cvar->flags & CV_NETVAR) && !CV_IsSetToDefault(cvar)) || (in_demo && cvar->netid == cv_numlaps.netid))
if ((cvar->flags & CV_NETVAR) && !CV_IsSetToDefault(cvar))
{
if (in_demo)
WRITESTRING(*p, cvar->name);
else
WRITEUINT16(*p, cvar->netid);
// UGLY HACK: Save proper lap count in net replays
if (in_demo && cvar->netid == cv_numlaps.netid)
{
if (cv_basenumlaps.value &&
(!(mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE)
|| (mapheaderinfo[gamemap - 1]->numlaps > cv_basenumlaps.value))
)
{
WRITESTRING(*p, cv_basenumlaps.string);
}
else
{
char buf[9];
sprintf(buf, "%d", mapheaderinfo[gamemap - 1]->numlaps);
WRITESTRING(*p, buf);
}
}
else
{
WRITESTRING(*p, cvar->string);
}
WRITESTRING(*p, cvar->string);
WRITEUINT8(*p, false);
++count;
@ -2052,6 +2032,7 @@ void CV_AddValue(consvar_t *var, INT32 increment)
if (var->PossibleValue[max].value == var->value)
currentindice = max;
// The following options will NOT handle netsyncing.
if (var == &cv_chooseskin)
{
// Special case for the chooseskin variable, used only directly from the menu
@ -2103,28 +2084,7 @@ void CV_AddValue(consvar_t *var, INT32 increment)
}
else if (var == &cv_kartspeed)
{
INT32 maxspeed = (M_SecretUnlocked(SECRET_HARDSPEED) ? 2 : 1);
// Special case for the kartspeed variable, used only directly from the menu to prevent selecting hard mode
if (increment > 0) // Going up!
{
newvalue = var->value + 1;
if (newvalue > maxspeed)
newvalue = -1;
var->value = newvalue;
var->string = var->PossibleValue[var->value].strvalue;
var->func();
return;
}
else if (increment < 0) // Going down!
{
newvalue = var->value - 1;
if (newvalue < -1)
newvalue = maxspeed;
var->value = newvalue;
var->string = var->PossibleValue[var->value].strvalue;
var->func();
return;
}
max = (M_SecretUnlocked(SECRET_HARDSPEED) ? 3 : 2);
}
#ifdef PARANOIA
if (currentindice == -1)

View file

@ -3287,7 +3287,7 @@ void D_QuitNetGame(void)
if (nodeingame[i])
HSendPacket(i, true, 0, 0);
#ifdef MASTERSERVER
if (serverrunning && cv_advertise.value)
if (serverrunning && netgame && cv_advertise.value) // see mserv.c Online()
UnregisterServer();
#endif
}

View file

@ -899,7 +899,11 @@ void D_SRB2Loop(void)
if (!singletics)
{
INT64 elapsed = (INT64)(finishprecise - enterprecise);
if (elapsed > 0 && (INT64)capbudget > elapsed)
// in the case of "match refresh rate" + vsync, don't sleep at all
const boolean vsync_with_match_refresh = cv_vidwait.value && cv_fpscap.value == 0;
if (elapsed > 0 && (INT64)capbudget > elapsed && !vsync_with_match_refresh)
{
I_SleepDuration(capbudget - (finishprecise - enterprecise));
}

View file

@ -102,7 +102,6 @@ static void Got_DiscordInfo(UINT8 **cp, INT32 playernum);
static void PointLimit_OnChange(void);
static void TimeLimit_OnChange(void);
static void NumLaps_OnChange(void);
static void BaseNumLaps_OnChange(void);
static void Mute_OnChange(void);
static void AutoBalance_OnChange(void);
@ -141,7 +140,6 @@ static void Color4_OnChange(void);
static void DummyConsvar_OnChange(void);
static void SoundTest_OnChange(void);
static void BaseNumLaps_OnChange(void);
static void KartFrantic_OnChange(void);
static void KartSpeed_OnChange(void);
static void KartEncore_OnChange(void);
@ -489,10 +487,9 @@ static CV_PossibleValue_t pointlimit_cons_t[] = {{1, "MIN"}, {MAXSCORE, "MAX"},
consvar_t cv_pointlimit = CVAR_INIT ("pointlimit", "None", CV_SAVE|CV_NETVAR|CV_CALL|CV_NOINIT, pointlimit_cons_t, PointLimit_OnChange);
static CV_PossibleValue_t timelimit_cons_t[] = {{1, "MIN"}, {30, "MAX"}, {0, "None"}, {0, NULL}};
consvar_t cv_timelimit = CVAR_INIT ("timelimit", "None", CV_SAVE|CV_NETVAR|CV_CALL|CV_NOINIT, timelimit_cons_t, TimeLimit_OnChange);
static CV_PossibleValue_t numlaps_cons_t[] = {{1, "MIN"}, {99, "MAX"}, {0, NULL}};
consvar_t cv_numlaps = CVAR_INIT ("numlaps", "3", CV_NETVAR|CV_CALL|CV_NOINIT, numlaps_cons_t, NumLaps_OnChange);
static CV_PossibleValue_t basenumlaps_cons_t[] = {{1, "MIN"}, {99, "MAX"}, {0, "Map default"}, {0, NULL}};
consvar_t cv_basenumlaps = CVAR_INIT ("basenumlaps", "Map default", CV_SAVE|CV_NETVAR|CV_CALL|CV_CHEAT, basenumlaps_cons_t, BaseNumLaps_OnChange);
static CV_PossibleValue_t numlaps_cons_t[] = {{1, "MIN"}, {MAX_LAPS, "MAX"}, {0, "Map default"}, {0, NULL}};
consvar_t cv_numlaps = CVAR_INIT ("numlaps", "Map default", CV_SAVE|CV_NETVAR|CV_CALL|CV_CHEAT, numlaps_cons_t, NumLaps_OnChange);
// Point and time limits for every gametype
INT32 pointlimits[NUMGAMETYPES];
@ -707,7 +704,6 @@ void D_RegisterServerCommands(void)
// misc
CV_RegisterVar(&cv_pointlimit);
CV_RegisterVar(&cv_numlaps);
CV_RegisterVar(&cv_basenumlaps);
CV_RegisterVar(&cv_autobalance);
CV_RegisterVar(&cv_teamscramble);
@ -3570,6 +3566,8 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
if (players[playernum].mo)
players[playernum].mo->health = 1;
K_StripItems(&players[playernum]);
}
K_CheckBumpers(); // SRB2Kart
@ -4505,24 +4503,6 @@ static void PointLimit_OnChange(void)
CONS_Printf(M_GetText("Point limit disabled\n"));
}
static void NumLaps_OnChange(void)
{
if (K_CanChangeRules() == false)
{
return;
}
if ((mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE)
&& (cv_numlaps.value > mapheaderinfo[gamemap - 1]->numlaps))
{
CV_StealthSetValue(&cv_numlaps, mapheaderinfo[gamemap - 1]->numlaps);
}
// Just don't be verbose
if (gametyperules & GTR_CIRCUIT)
CONS_Printf(M_GetText("Number of laps set to %d\n"), cv_numlaps.value);
}
static void NetTimeout_OnChange(void)
{
connectiontimeout = (tic_t)cv_nettimeout.value;
@ -5330,7 +5310,6 @@ static void Follower_OnChange(void)
{
char str[SKINNAMESIZE+1], cpy[SKINNAMESIZE+1];
INT32 num;
char set[10]; // This isn't Lua and mixed declarations in the middle of code make caveman compilers scream.
// there is a slight chance that we will actually use a string instead so...
// let's investigate the string...
@ -5355,8 +5334,8 @@ static void Follower_OnChange(void)
if (num == -1) // that's an error.
CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str);
sprintf(set, "%d", num);
CV_StealthSet(&cv_follower[0], set); // set it to a number. It's easier for us to send later :)
CV_StealthSet(&cv_follower[0], str);
cv_follower[0].value = num;
}
if (!Playing())
@ -5384,7 +5363,6 @@ static void Follower2_OnChange(void)
{
char str[SKINNAMESIZE+1], cpy[SKINNAMESIZE+1];
INT32 num;
char set[10]; // This isn't Lua and mixed declarations in the middle of code make caveman compilers scream.
// there is a slight chance that we will actually use a string instead so...
// let's investigate the string...
@ -5409,8 +5387,8 @@ static void Follower2_OnChange(void)
if (num == -1) // that's an error.
CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str);
sprintf(set, "%d", num);
CV_StealthSet(&cv_follower[1], set); // set it to a number. It's easier for us to send later :)
CV_StealthSet(&cv_follower[1], str);
cv_follower[1].value = num;
}
if (!Playing())
@ -5435,7 +5413,6 @@ static void Follower3_OnChange(void)
{
char str[SKINNAMESIZE+1], cpy[SKINNAMESIZE+1];
INT32 num;
char set[10]; // This isn't Lua and mixed declarations in the middle of code make caveman compilers scream.
// there is a slight chance that we will actually use a string instead so...
// let's investigate the string...
@ -5460,8 +5437,8 @@ static void Follower3_OnChange(void)
if (num == -1) // that's an error.
CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str);
sprintf(set, "%d", num);
CV_StealthSet(&cv_follower[2], set); // set it to a number. It's easier for us to send later :)
CV_StealthSet(&cv_follower[2], str);
cv_follower[2].value = num;
}
if (!Playing())
@ -5486,7 +5463,6 @@ static void Follower4_OnChange(void)
{
char str[SKINNAMESIZE+1], cpy[SKINNAMESIZE+1];
INT32 num;
char set[10]; // This isn't Lua and mixed declarations in the middle of code make caveman compilers scream.
// there is a slight chance that we will actually use a string instead so...
// let's investigate the string...
@ -5511,8 +5487,8 @@ static void Follower4_OnChange(void)
if (num == -1) // that's an error.
CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str);
sprintf(set, "%d", num);
CV_StealthSet(&cv_follower[3], set); // set it to a number. It's easier for us to send later :)
CV_StealthSet(&cv_follower[3], str);
cv_follower[3].value = num;
}
if (!Playing())
@ -5789,22 +5765,24 @@ static void Command_ShowTime_f(void)
}
// SRB2Kart: On change messages
static void BaseNumLaps_OnChange(void)
static void NumLaps_OnChange(void)
{
if (K_CanChangeRules() == true)
if (K_CanChangeRules() == false)
{
const char *str = va("%d", cv_basenumlaps.value);
return;
}
if (cv_basenumlaps.value == 0)
{
str = "map defaults";
}
CONS_Printf(M_GetText("Number of laps will be changed to %s next round.\n"), str);
if (leveltime < starttime)
{
CONS_Printf(M_GetText("Number of laps have been set to %d.\n"), cv_numlaps.value);
numlaps = (UINT8)cv_numlaps.value;
}
else
{
CONS_Printf(M_GetText("Number of laps will be set to %d next round.\n"), cv_numlaps.value);
}
}
static void KartFrantic_OnChange(void)
{
if (K_CanChangeRules() == false)

View file

@ -55,7 +55,6 @@ extern consvar_t cv_itemrespawn;
extern consvar_t cv_pointlimit;
extern consvar_t cv_timelimit;
extern consvar_t cv_numlaps;
extern consvar_t cv_basenumlaps;
extern UINT32 timelimitintics;
extern consvar_t cv_allowexitlevel;

View file

@ -258,6 +258,7 @@ typedef enum
#define TRICKDELAY (TICRATE/4)
#define TUMBLEBOUNCES 3
#define TUMBLEGRAVITY (4*FRACUNIT)
//}
@ -281,6 +282,7 @@ typedef struct respawnvars_s
tic_t airtimer; // Time spent in the air before respawning
UINT32 distanceleft; // How far along the course to respawn you
tic_t dropdash; // Drop Dash charge timer
boolean truedeath; // Your soul has left your body
} respawnvars_t;
// player_t struct for all bot variables
@ -290,6 +292,9 @@ typedef struct botvars_s
UINT8 diffincrease; // In GP: bot difficulty will increase this much next round
boolean rival; // If true, they're the GP rival
fixed_t rubberband; // Bot rubberband value
UINT16 controller; // Special bot controller linedef ID
tic_t itemdelay; // Delay before using item at all
tic_t itemconfirm; // When high enough, they will use their item
@ -533,6 +538,7 @@ typedef struct player_s
INT16 totalring; // Total number of rings obtained for GP
tic_t realtime; // integer replacement for leveltime
UINT8 laps; // Number of laps (optional)
UINT8 latestlap;
INT32 starpostnum; // The number of the last starpost you hit
UINT8 ctfteam; // 0 == Spectator, 1 == Red, 2 == Blue

View file

@ -186,6 +186,27 @@ static inline int lib_freeslot(lua_State *L)
}
}
}
else if (fastcmp(type, "PRECIP"))
{
// Search if we already have a PRECIP by that name...
preciptype_t i;
for (i = PRECIP_FIRSTFREESLOT; i < precip_freeslot; i++)
if (fastcmp(word, precipprops[i].name))
break;
// We don't, so allocate a new one.
if (i >= precip_freeslot) {
if (precip_freeslot < MAXPRECIP)
{
CONS_Printf("Weather PRECIP_%s allocated.\n",word);
precipprops[i].name = Z_StrDup(word);
lua_pushinteger(L, precip_freeslot);
r++;
precip_freeslot++;
} else
CONS_Alert(CONS_WARNING, "Ran out of free PRECIP slots!\n");
}
}
Z_Free(s);
lua_remove(L, 1);
continue;
@ -465,6 +486,21 @@ static inline int lib_getenum(lua_State *L)
if (mathlib) return luaL_error(L, "NiGHTS grade '%s' could not be found.\n", word);
return 0;
}
else if (fastncmp("PRECIP_",word,7)) {
p = word+7;
for (i = 0; i < MAXPRECIP; i++)
{
if (precipprops[i].name == NULL)
break;
if (fastcmp(p, precipprops[i].name))
{
lua_pushinteger(L, PRECIP_NONE + i);
return 1;
}
}
return luaL_error(L, "weather type '%s' does not exist.\n", word);
}
else if (!mathlib && fastncmp("A_",word,2)) {
char *caps;
// Try to get a Lua action first.

View file

@ -287,6 +287,25 @@ void readfreeslots(MYFILE *f)
lastcustomtol <<= 1;
}
}
else if (fastcmp(type, "PRECIP"))
{
// Search if we already have a PRECIP by that name...
for (i = PRECIP_FIRSTFREESLOT; i < (int)precip_freeslot; i++)
if (fastcmp(word, precipprops[i].name))
break;
// We found it? Then don't allocate another one.
if (i < (int)precip_freeslot)
continue;
// We don't, so allocate a new one.
if (precip_freeslot < MAXPRECIP)
{
precipprops[i].name = Z_StrDup(word);
precip_freeslot++;
} else
deh_warning("Ran out of free PRECIP slots!\n");
}
else
deh_warning("Freeslots: unknown enum class '%s' for '%s_%s'", type, type, word);
}
@ -1333,7 +1352,7 @@ void readlevelheader(MYFILE *f, INT32 num)
strlwr(mapheaderinfo[num-1]->forcecharacter); // skin names are lowercase
}
else if (fastcmp(word, "WEATHER"))
mapheaderinfo[num-1]->weather = (UINT8)get_number(word2);
mapheaderinfo[num-1]->weather = get_precip(word2);
else if (fastcmp(word, "SKYTEXTURE"))
deh_strlcpy(mapheaderinfo[num-1]->skytexture, word2,
sizeof(mapheaderinfo[num-1]->skytexture), va("Level header %d: sky texture", num));
@ -1371,6 +1390,23 @@ void readlevelheader(MYFILE *f, INT32 num)
mapheaderinfo[num-1]->mobj_scale = get_number(word2);
else if (fastcmp(word, "DEFAULTWAYPOINTRADIUS"))
mapheaderinfo[num-1]->default_waypoint_radius = get_number(word2);
else if (fastcmp(word, "LIGHTCONTRAST"))
{
mapheaderinfo[num-1]->light_contrast = (UINT8)i;
}
else if (fastcmp(word, "LIGHTANGLE"))
{
if (fastcmp(word2, "EVEN"))
{
mapheaderinfo[num-1]->use_light_angle = false;
mapheaderinfo[num-1]->light_angle = 0;
}
else
{
mapheaderinfo[num-1]->use_light_angle = true;
mapheaderinfo[num-1]->light_angle = FixedAngle(FloatToFixed(atof(word2)));
}
}
// Individual triggers for level flags, for ease of use (and 2.0 compatibility)
else if (fastcmp(word, "SCRIPTISFILE"))
{
@ -3692,6 +3728,61 @@ if (!followers[numfollowers].field) \
Z_Free(s);
}
void readweather(MYFILE *f, INT32 num)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word;
char *word2;
char *tmp;
do
{
if (myfgets(s, MAXLINELEN, f))
{
if (s[0] == '\n')
break;
// First remove trailing newline, if there is one
tmp = strchr(s, '\n');
if (tmp)
*tmp = '\0';
tmp = strchr(s, '#');
if (tmp)
*tmp = '\0';
if (s == tmp)
continue; // Skip comment lines, but don't break.
// Set / reset word
word = s;
// Get the part before the " = "
tmp = strchr(s, '=');
if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word);
// Now get the part after
word2 = tmp += 2;
if (fastcmp(word, "TYPE"))
{
precipprops[num].type = get_mobjtype(word2);
}
else if (fastcmp(word, "EFFECTS"))
{
precipprops[num].effects = get_number(word2);
}
else
deh_warning("Weather %d : unknown word '%s'", num, word);
}
} while (!myfeof(f));
Z_Free(s);
}
//
//
//
@ -3814,6 +3905,24 @@ sfxenum_t get_sfx(const char *word)
return GT_COOP;
}*/
preciptype_t get_precip(const char *word)
{ // Returns the value of PRECIP_ enumerations
preciptype_t i;
if (*word >= '0' && *word <= '9')
return atoi(word);
if (fastncmp("PRECIP_",word,4))
word += 7; // take off the PRECIP_
for (i = 0; i < MAXPRECIP; i++)
{
if (precipprops[i].name == NULL)
break;
if (fasticmp(word, precipprops[i].name))
return i;
}
deh_warning("Couldn't find weather type named 'PRECIP_%s'",word);
return PRECIP_RAIN;
}
/// \todo Make ANY of this completely over-the-top math craziness obey the order of operations.
static fixed_t op_mul(fixed_t a, fixed_t b) { return a*b; }
static fixed_t op_div(fixed_t a, fixed_t b) { return a/b; }

View file

@ -83,5 +83,7 @@ void clear_conditionsets(void);
void readcupheader(MYFILE *f, cupheader_t *cup);
void readfollower(MYFILE *f);
preciptype_t get_precip(const char *word);
void readweather(MYFILE *f, INT32 num);
#endif

View file

@ -2541,6 +2541,13 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
"S_GREYSPRING3",
"S_GREYSPRING4",
// Orange Spring (Pogo)
"S_POGOSPRING1",
"S_POGOSPRING2",
"S_POGOSPRING2B",
"S_POGOSPRING3",
"S_POGOSPRING4",
// Yellow Diagonal Spring
"S_YDIAG1",
"S_YDIAG2",
@ -4631,6 +4638,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_REDSPRING",
"MT_BLUESPRING",
"MT_GREYSPRING",
"MT_POGOSPRING",
"MT_YELLOWDIAG", // Yellow Diagonal Spring
"MT_REDDIAG", // Red Diagonal Spring
"MT_BLUEDIAG", // Blue Diagonal Spring
@ -6645,6 +6653,11 @@ struct int_const_s const INT_CONST[] = {
{"SPOT_WEAK",SPOT_WEAK},
{"SPOT_BUMP",SPOT_BUMP},
// precipeffect_t
{"PRECIPFX_THUNDER",PRECIPFX_THUNDER},
{"PRECIPFX_LIGHTNING",PRECIPFX_LIGHTNING},
{"PRECIPFX_WATERPARTICLES",PRECIPFX_WATERPARTICLES},
{NULL,0}
};

View file

@ -554,6 +554,18 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
readcupheader(f, cup);
}
else if (fastcmp(word, "WEATHER") || fastcmp(word, "PRECIP") || fastcmp(word, "PRECIPITATION"))
{
if (i == 0 && word2[0] != '0') // If word2 isn't a number
i = get_precip(word2); // find a weather type by name
if (i < MAXPRECIP && i > 0)
readweather(f, i);
else
{
deh_warning("Weather number %d out of range (1 - %d)", i, MAXPRECIP-1);
ignorelines(f);
}
}
else if (fastcmp(word, "RINGRACERS"))
{
if (isdigit(word2[0]))

View file

@ -41,8 +41,7 @@ extern UINT32 mapmusresume;
// Use other bits if necessary.
extern UINT32 maptol;
extern UINT8 globalweather;
extern UINT8 curWeather;
extern INT32 cursaveslot;
//extern INT16 lastmapsaved;
extern INT16 lastmaploaded;
@ -64,31 +63,44 @@ extern tic_t marathontime;
extern UINT8 numgameovers;
extern SINT8 startinglivesbalance[maxgameovers+1];
#define NUMPRECIPFREESLOTS 64
typedef enum
{
PRECIP_NONE = 0,
PRECIP_RAIN,
PRECIP_SNOW,
PRECIP_BLIZZARD,
PRECIP_STORM,
PRECIP_STORM_NORAIN,
PRECIP_STORM_NOSTRIKES,
PRECIP_FIRSTFREESLOT,
PRECIP_LASTFREESLOT = PRECIP_FIRSTFREESLOT + NUMPRECIPFREESLOTS - 1,
MAXPRECIP
} preciptype_t;
typedef enum
{
PRECIPFX_THUNDER = 1,
PRECIPFX_LIGHTNING = 1<<1
PRECIPFX_LIGHTNING = 1<<1,
PRECIPFX_WATERPARTICLES = 1<<2
} precipeffect_t;
typedef struct
{
const char *name;
mobjtype_t type;
precipeffect_t effects;
} precipprops_t;
extern precipprops_t precipprops[MAXPRECIP];
extern preciptype_t precip_freeslot;
extern preciptype_t globalweather;
extern preciptype_t curWeather;
// Set if homebrew PWAD stuff has been added.
extern boolean modifiedgame;
@ -385,6 +397,10 @@ typedef struct
fixed_t mobj_scale; ///< Replacement for TOL_ERZ3
fixed_t default_waypoint_radius; ///< 0 is a special value for DEFAULT_WAYPOINT_RADIUS, but scaled with mobjscale
UINT8 light_contrast; ///< Range of wall lighting. 0 is no lighting.
boolean use_light_angle; ///< When false, wall lighting is evenly distributed. When true, wall lighting is directional.
angle_t light_angle; ///< Angle of directional wall lighting.
// Music stuff.
UINT32 musinterfadeout; ///< Fade out level music on intermission screen in milliseconds
char musintername[7]; ///< Intermission screen music.
@ -665,6 +681,13 @@ extern tic_t racecountdown, exitcountdown;
extern fixed_t gravity;
extern fixed_t mapobjectscale;
extern struct maplighting
{
UINT8 contrast;
boolean directional;
angle_t angle;
} maplighting;
//for CTF balancing
extern INT16 autobalance;
extern INT16 teamscramble;
@ -676,6 +699,7 @@ extern INT16 scramblecount; //for CTF team scramble
extern INT32 cheats;
// SRB2kart
extern UINT8 numlaps;
extern UINT8 gamespeed;
extern boolean franticitems;
extern boolean encoremode, prevencoremode;

View file

@ -53,8 +53,13 @@
#include "k_color.h"
#include "k_follower.h"
#ifdef TESTERS
static CV_PossibleValue_t recordmultiplayerdemos_cons_t[] = {{2, "Auto Save"}, {0, NULL}};
consvar_t cv_recordmultiplayerdemos = CVAR_INIT ("netdemo_record", "Auto Save", CV_SAVE, recordmultiplayerdemos_cons_t, NULL);
#else
static CV_PossibleValue_t recordmultiplayerdemos_cons_t[] = {{0, "Disabled"}, {1, "Manual Save"}, {2, "Auto Save"}, {0, NULL}};
consvar_t cv_recordmultiplayerdemos = CVAR_INIT ("netdemo_record", "Manual Save", CV_SAVE, recordmultiplayerdemos_cons_t, NULL);
#endif
static CV_PossibleValue_t netdemosyncquality_cons_t[] = {{1, "MIN"}, {35, "MAX"}, {0, NULL}};
consvar_t cv_netdemosyncquality = CVAR_INIT ("netdemo_syncquality", "1", CV_SAVE, netdemosyncquality_cons_t, NULL);
@ -1994,6 +1999,7 @@ void G_BeginRecording(void)
WRITEUINT8(demo_p, demoflags);
WRITEUINT8(demo_p, gametype & 0xFF);
WRITEUINT8(demo_p, numlaps);
// file list
m = demo_p;/* file count */
@ -2424,6 +2430,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
p += 16; // map md5
flags = READUINT8(p); // demoflags
p++; // gametype
p++; // numlaps
G_SkipDemoExtraFiles(&p);
aflags = flags & (DF_TIMEATTACK|DF_BREAKTHECAPSULES);
@ -2481,6 +2488,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
p += 16; // mapmd5
flags = READUINT8(p);
p++; // gametype
p++; // numlaps
G_SkipDemoExtraFiles(&p);
if (!(flags & aflags))
{
@ -2595,6 +2603,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
}
pdemo->gametype = READUINT8(info_p);
pdemo->numlaps = READUINT8(info_p);
pdemo->addonstatus = G_CheckDemoExtraFiles(&info_p, true);
info_p += 4; // RNG seed
@ -2621,20 +2630,11 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
if (!stricmp(kartspeed_cons_t[j].strvalue, svalue))
pdemo->kartspeed = kartspeed_cons_t[j].value;
}
else if (netid == cv_basenumlaps.netid && pdemo->gametype == GT_RACE)
pdemo->numlaps = atoi(svalue);
}
if (pdemoflags & DF_ENCORE)
pdemo->kartspeed |= DF_ENCORE;
/*// Temporary info until this is actually present in replays.
(void)extrainfo_p;
sprintf(pdemo->winnername, "transrights420");
pdemo->winnerskin = 1;
pdemo->winnercolor = SKINCOLOR_MOONSET;
pdemo->winnertime = 6666;*/
// Read standings!
count = 0;
@ -2830,6 +2830,7 @@ void G_DoPlayDemo(char *defdemoname)
demoflags = READUINT8(demo_p);
gametype = READUINT8(demo_p);
G_SetGametype(gametype);
numlaps = READUINT8(demo_p);
if (demo.title) // Titledemos should always play and ought to always be compatible with whatever wadlist is running.
G_SkipDemoExtraFiles(&demo_p);
@ -3253,6 +3254,7 @@ void G_AddGhost(char *defdemoname)
}
p++; // gametype
p++; // numlaps
G_SkipDemoExtraFiles(&p); // Don't wanna modify the file list for ghosts.
switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT)
@ -3470,7 +3472,7 @@ void G_UpdateStaffGhostName(lumpnum_t l)
}
p++; // Gametype
p++; // numlaps
G_SkipDemoExtraFiles(&p);
switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT)

View file

@ -93,20 +93,22 @@ UINT32 mapmusresume;
INT16 gamemap = 1;
UINT32 maptol;
UINT8 globalweather = PRECIP_NONE;
UINT8 curWeather = PRECIP_NONE;
preciptype_t globalweather = PRECIP_NONE;
preciptype_t curWeather = PRECIP_NONE;
precipprops_t precipprops[MAXPRECIP] =
{
{MT_NULL, 0}, // PRECIP_NONE
{MT_RAIN, 0}, // PRECIP_RAIN
{MT_SNOWFLAKE, 0}, // PRECIP_SNOW
{MT_BLIZZARDSNOW, 0}, // PRECIP_BLIZZARD
{MT_RAIN, PRECIPFX_THUNDER|PRECIPFX_LIGHTNING}, // PRECIP_STORM
{MT_NULL, PRECIPFX_THUNDER|PRECIPFX_LIGHTNING}, // PRECIP_STORM_NORAIN
{MT_RAIN, PRECIPFX_THUNDER} // PRECIP_STORM_NOSTRIKES
{"NONE", MT_NULL, 0}, // PRECIP_NONE
{"RAIN", MT_RAIN, 0}, // PRECIP_RAIN
{"SNOW", MT_SNOWFLAKE, 0}, // PRECIP_SNOW
{"BLIZZARD", MT_BLIZZARDSNOW, 0}, // PRECIP_BLIZZARD
{"STORM", MT_RAIN, PRECIPFX_THUNDER|PRECIPFX_LIGHTNING}, // PRECIP_STORM
{"STORM_NORAIN", MT_NULL, PRECIPFX_THUNDER|PRECIPFX_LIGHTNING}, // PRECIP_STORM_NORAIN
{"STORM_NOSTRIKES", MT_RAIN, PRECIPFX_THUNDER} // PRECIP_STORM_NOSTRIKES
};
preciptype_t precip_freeslot = PRECIP_FIRSTFREESLOT;
INT32 cursaveslot = 0; // Auto-save 1p savegame slot
//INT16 lastmapsaved = 0; // Last map we auto-saved at
INT16 lastmaploaded = 0; // Last map the game loaded
@ -287,6 +289,8 @@ tic_t racecountdown, exitcountdown; // for racing
fixed_t gravity;
fixed_t mapobjectscale;
struct maplighting maplighting;
INT16 autobalance; //for CTF team balance
INT16 teamscramble; //for CTF team scramble
INT16 scrambleplayers[MAXPLAYERS]; //for CTF team scramble
@ -298,6 +302,7 @@ INT32 cheats; //for multiplayer cheat commands
// SRB2Kart
// Cvars that we don't want changed mid-game
UINT8 numlaps; // Removed from Cvar hell
UINT8 gamespeed; // Game's current speed (or difficulty, or cc, or etc); 0 for easy, 1 for normal, 2 for hard
boolean encoremode = false; // Encore Mode currently enabled?
boolean prevencoremode;
@ -2134,6 +2139,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
INT32 khudcardanimation;
INT16 totalring;
UINT8 laps;
UINT8 latestlap;
UINT16 skincolor;
INT32 skin;
UINT32 availabilities;
@ -2220,6 +2226,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
khudfault = 0;
nocontrol = 0;
laps = 0;
latestlap = 0;
totalring = 0;
roundscore = 0;
exiting = 0;
@ -2260,6 +2267,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
nocontrol = players[player].nocontrol;
laps = players[player].laps;
latestlap = players[player].latestlap;
totalring = players[player].totalring;
roundscore = players[player].roundscore;
@ -2316,6 +2325,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->karthud[khud_cardanimation] = khudcardanimation;
p->laps = laps;
p->latestlap = latestlap;
p->totalring = totalring;
p->bot = bot;
@ -2342,6 +2352,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->kickstartaccel = kickstartaccel;
p->tripWireState = TRIP_NONE;
p->botvars.rubberband = FRACUNIT;
p->botvars.controller = UINT16_MAX;
memcpy(&p->respawn, &respawn, sizeof (p->respawn));
if (follower)
@ -3542,11 +3555,14 @@ static void G_DoCompleted(void)
wipegamestate = GS_NULL;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i])
{
// SRB2Kart: exitlevel shouldn't get you the points
if (!players[i].exiting && !(players[i].pflags & PF_NOCONTEST))
{
clientPowerAdd[i] = 0;
if (players[i].bot)
{
K_FakeBotResults(&players[i]);
@ -3564,6 +3580,7 @@ static void G_DoCompleted(void)
G_PlayerFinishLevel(i); // take away cards and stuff
}
}
// play some generic music if there's no win/cool/lose music going on (for exitlevel commands)
if ((gametyperules & GTR_CIRCUIT) && ((multiplayer && demo.playback) || j == r_splitscreen+1) && (cv_inttime.value > 0))

View file

@ -285,84 +285,31 @@ UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap) // Let's see if
return surfcolor.s.alpha;
}
static FUINT HWR_CalcWallLight(FUINT lightnum, fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t v2y)
static FUINT HWR_CalcWallLight(FUINT lightnum, seg_t *seg)
{
INT16 finallight = lightnum;
if (cv_glfakecontrast.value != 0)
if (seg != NULL && P_ApplyLightOffsetFine(lightnum))
{
const UINT8 contrast = 8;
fixed_t extralight = 0;
finallight += seg->hwLightOffset;
if (cv_glfakecontrast.value == 2) // Smooth setting
{
extralight = (-(contrast<<FRACBITS) +
FixedDiv(AngleFixed(R_PointToAngle2(0, 0,
abs(v1x - v2x),
abs(v1y - v2y))), 90<<FRACBITS)
* (contrast * 2)) >> FRACBITS;
}
else
{
if (v1y == v2y)
extralight = -contrast;
else if (v1x == v2x)
extralight = contrast;
}
if (extralight != 0)
{
finallight += extralight;
if (finallight < 0)
finallight = 0;
if (finallight > 255)
finallight = 255;
}
if (finallight > 255) finallight = 255;
if (finallight < 0) finallight = 0;
}
return (FUINT)finallight;
}
static FUINT HWR_CalcSlopeLight(FUINT lightnum, angle_t dir, fixed_t delta)
static FUINT HWR_CalcSlopeLight(FUINT lightnum, pslope_t *slope)
{
INT16 finallight = lightnum;
if (cv_glfakecontrast.value != 0 && cv_glslopecontrast.value != 0)
if (slope != NULL && P_ApplyLightOffsetFine(lightnum))
{
const UINT8 contrast = 8;
fixed_t extralight = 0;
finallight += slope->hwLightOffset;
if (cv_glfakecontrast.value == 2) // Smooth setting
{
fixed_t dirmul = abs(FixedDiv(AngleFixed(dir) - (180<<FRACBITS), 180<<FRACBITS));
extralight = -(contrast<<FRACBITS) + (dirmul * (contrast * 2));
extralight = FixedMul(extralight, delta*4) >> FRACBITS;
}
else
{
dir = ((dir + ANGLE_45) / ANGLE_90) * ANGLE_90;
if (dir == ANGLE_180)
extralight = -contrast;
else if (dir == 0)
extralight = contrast;
if (delta >= FRACUNIT/2)
extralight *= 2;
}
if (extralight != 0)
{
finallight += extralight;
if (finallight < 0)
finallight = 0;
if (finallight > 255)
finallight = 255;
}
if (finallight > 255) finallight = 255;
if (finallight < 0) finallight = 0;
}
return (FUINT)finallight;
@ -573,9 +520,7 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool
for (i = 0, v3d = planeVerts; i < nrPlaneVerts; i++,v3d++,pv++)
SETUP3DVERT(v3d, pv->x, pv->y);
if (slope)
lightlevel = HWR_CalcSlopeLight(lightlevel, R_PointToAngle2(0, 0, slope->normal.x, slope->normal.y), abs(slope->zdelta));
lightlevel = HWR_CalcSlopeLight(lightlevel, slope);
HWR_Lighting(&Surf, lightlevel, planecolormap);
if (PolyFlags & (PF_Translucent|PF_Additive|PF_Subtractive|PF_Fog))
@ -894,7 +839,7 @@ static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum,
INT32 solid, i;
lightlist_t * list = sector->lightlist;
const UINT8 alpha = Surf->PolyColor.s.alpha;
FUINT lightnum = HWR_CalcWallLight(sector->lightlevel, v1x, v1y, v2x, v2y);
FUINT lightnum = sector->lightlevel;
extracolormap_t *colormap = NULL;
realtop = top = wallVerts[3].y;
@ -918,12 +863,12 @@ static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum,
{
if (pfloor && (pfloor->flags & FF_FOG))
{
lightnum = HWR_CalcWallLight(pfloor->master->frontsector->lightlevel, v1x, v1y, v2x, v2y);
lightnum = pfloor->master->frontsector->lightlevel;
colormap = pfloor->master->frontsector->extra_colormap;
}
else
{
lightnum = HWR_CalcWallLight(*list[i].lightlevel, v1x, v1y, v2x, v2y);
lightnum = *list[i].lightlevel;
colormap = *list[i].extra_colormap;
}
}
@ -1006,11 +951,11 @@ static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum,
wallVerts[1].y = endbot;
if (polyflags & PF_Fog)
HWR_AddTransparentWall(wallVerts, Surf, texnum, polyflags, true, lightnum, colormap);
HWR_AddTransparentWall(wallVerts, Surf, texnum, polyflags, true, HWR_CalcWallLight(lightnum, gl_curline), colormap);
else if (polyflags & (PF_Translucent|PF_Additive|PF_Subtractive|PF_Environment))
HWR_AddTransparentWall(wallVerts, Surf, texnum, polyflags, false, lightnum, colormap);
HWR_AddTransparentWall(wallVerts, Surf, texnum, polyflags, false, HWR_CalcWallLight(lightnum, gl_curline), colormap);
else
HWR_ProjectWall(wallVerts, Surf, polyflags, lightnum, colormap);
HWR_ProjectWall(wallVerts, Surf, polyflags, HWR_CalcWallLight(lightnum, gl_curline), colormap);
top = bot;
endtop = endbot;
@ -1035,11 +980,11 @@ static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum,
wallVerts[1].y = endbot;
if (polyflags & PF_Fog)
HWR_AddTransparentWall(wallVerts, Surf, texnum, polyflags, true, lightnum, colormap);
HWR_AddTransparentWall(wallVerts, Surf, texnum, polyflags, true, HWR_CalcWallLight(lightnum, gl_curline), colormap);
else if (polyflags & (PF_Translucent|PF_Additive|PF_Subtractive|PF_Environment))
HWR_AddTransparentWall(wallVerts, Surf, texnum, polyflags, false, lightnum, colormap);
HWR_AddTransparentWall(wallVerts, Surf, texnum, polyflags, false, HWR_CalcWallLight(lightnum, gl_curline), colormap);
else
HWR_ProjectWall(wallVerts, Surf, polyflags, lightnum, colormap);
HWR_ProjectWall(wallVerts, Surf, polyflags, HWR_CalcWallLight(lightnum, gl_curline), colormap);
}
// HWR_DrawSkyWall
@ -1083,7 +1028,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
fixed_t h, l; // 3D sides and 2s middle textures
fixed_t hS, lS;
FUINT lightnum = 0; // shut up compiler
FUINT lightnum = 255; // shut up compiler
extracolormap_t *colormap;
FSurfaceInfo Surf;
@ -1126,7 +1071,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
cliphigh = (float)(texturehpeg + (gl_curline->flength*FRACUNIT));
}
lightnum = HWR_CalcWallLight(gl_frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y);
lightnum = HWR_CalcWallLight(gl_frontsector->lightlevel, gl_curline);
colormap = gl_frontsector->extra_colormap;
if (gl_frontsector)
@ -1801,7 +1746,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
blendmode = PF_Fog|PF_NoTexture;
lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y);
lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, gl_curline);
colormap = rover->master->frontsector->extra_colormap;
Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap);
@ -1927,7 +1872,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
blendmode = PF_Fog|PF_NoTexture;
lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y);
lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, gl_curline);
colormap = rover->master->frontsector->extra_colormap;
Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap);
@ -2384,9 +2329,9 @@ static void HWR_AddLine(seg_t * line)
// PrBoom: use REAL clipping math YAYYYYYYY!!!
if (!gld_clipper_SafeCheckRange(angle2, angle1))
{
{
return;
}
}
checkforemptylines = true;
#else
@ -2474,11 +2419,11 @@ static void HWR_AddLine(seg_t * line)
#ifdef NEWCLIP
if (!line->backsector)
{
{
gld_clipper_SafeAddClipRange(angle2, angle1);
}
else
{
}
else
{
boolean bothceilingssky = false, bothfloorssky = false;
gl_backsector = R_FakeFlat(gl_backsector, &tempsec, NULL, NULL, true);
@ -2511,7 +2456,7 @@ static void HWR_AddLine(seg_t * line)
// and no middle texture.
if (checkforemptylines && R_IsEmptyLine(line, gl_frontsector, gl_backsector))
return;
}
}
HWR_ProcessSeg(); // Doesn't need arguments because they're defined globally :D
return;
@ -5619,6 +5564,7 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
float x1, x2;
float z1, z2;
float rightsin, rightcos;
float this_scale;
spritedef_t *sprdef;
spriteframe_t *sprframe;
size_t lumpoff;
@ -5641,6 +5587,8 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
R_InterpolatePrecipMobjState(thing, FRACUNIT, &interp);
}
this_scale = FIXED_TO_FLOAT(interp.scale);
// transform the origin point
tr_x = FIXED_TO_FLOAT(interp.x) - gl_viewx;
tr_y = FIXED_TO_FLOAT(interp.y) - gl_viewy;
@ -5693,6 +5641,9 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
x2 = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset);
}
x1 *= this_scale;
x2 *= this_scale;
z1 = tr_y + x1 * rightsin;
z2 = tr_y - x2 * rightsin;
x1 = tr_x + x1 * rightcos;
@ -5720,8 +5671,8 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
#endif
// set top/bottom coords
vis->gzt = FIXED_TO_FLOAT(interp.z + spritecachedinfo[lumpoff].topoffset);
vis->gz = vis->gzt - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height);
vis->gzt = FIXED_TO_FLOAT(interp.z) + (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].topoffset) * this_scale);
vis->gz = vis->gzt - (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height) * this_scale);
vis->precip = true;
@ -6574,7 +6525,6 @@ static CV_PossibleValue_t glshaders_cons_t[] = {{HWD_SHADEROPTION_OFF, "Off"}, {
#ifdef BAD_MODEL_OPTIONS
static CV_PossibleValue_t glmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}};
#endif
static CV_PossibleValue_t glfakecontrast_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Smooth"}, {0, NULL}};
static CV_PossibleValue_t glshearing_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Third-person"}, {0, NULL}};
static void CV_glfiltermode_OnChange(void);
@ -6609,8 +6559,6 @@ consvar_t cv_glmodellighting = CVAR_INIT ("gr_modellighting", "Off", CV_SAVE, CV
consvar_t cv_glshearing = CVAR_INIT ("gr_shearing", "Off", CV_SAVE, glshearing_cons_t, NULL);
consvar_t cv_glspritebillboarding = CVAR_INIT ("gr_spritebillboarding", "On", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_glskydome = CVAR_INIT ("gr_skydome", "On", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_glfakecontrast = CVAR_INIT ("gr_fakecontrast", "Smooth", CV_SAVE, glfakecontrast_cons_t, NULL);
consvar_t cv_glslopecontrast = CVAR_INIT ("gr_slopecontrast", "Off", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_glfiltermode = CVAR_INIT ("gr_filtermode", "Nearest", CV_SAVE|CV_CALL, glfiltermode_cons_t, CV_glfiltermode_OnChange);
consvar_t cv_glanisotropicmode = CVAR_INIT ("gr_anisotropicmode", "1", CV_CALL, glanisotropicmode_cons_t, CV_glanisotropic_OnChange);
@ -6652,7 +6600,6 @@ void HWR_AddCommands(void)
CV_RegisterVar(&cv_glskydome);
CV_RegisterVar(&cv_glspritebillboarding);
CV_RegisterVar(&cv_glfakecontrast);
CV_RegisterVar(&cv_glshearing);
CV_RegisterVar(&cv_glshaders);
CV_RegisterVar(&cv_glallowshaders);

View file

@ -113,8 +113,6 @@ extern consvar_t cv_glsolvetjoin;
extern consvar_t cv_glshearing;
extern consvar_t cv_glspritebillboarding;
extern consvar_t cv_glskydome;
extern consvar_t cv_glfakecontrast;
extern consvar_t cv_glslopecontrast;
extern consvar_t cv_glbatching;

View file

@ -1381,10 +1381,6 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
R_InterpolateMobjState(spr->mobj, FRACUNIT, &interp);
}
fixed_t interpx = R_InterpolateFixed(spr->mobj->old_x, spr->mobj->x);
fixed_t interpy = R_InterpolateFixed(spr->mobj->old_y, spr->mobj->y);
fixed_t interpz = R_InterpolateFixed(spr->mobj->old_z, spr->mobj->z);
// hitlag vibrating
if (spr->mobj->hitlag > 0 && (spr->mobj->eflags & MFE_DAMAGEHITLAG))
{
@ -1395,15 +1391,15 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
mul = -mul;
}
interpx += FixedMul(spr->mobj->momx, mul);
interpy += FixedMul(spr->mobj->momy, mul);
interpy += FixedMul(spr->mobj->momz, mul);
interp.x += FixedMul(spr->mobj->momx, mul);
interp.y += FixedMul(spr->mobj->momy, mul);
interp.z += FixedMul(spr->mobj->momz, mul);
}
// sprite offset
interpx += spr->mobj->sprxoff;
interpy += spr->mobj->spryoff;
interpz += spr->mobj->sprzoff;
interp.x += spr->mobj->sprxoff;
interp.y += spr->mobj->spryoff;
interp.z += spr->mobj->sprzoff;
// Apparently people don't like jump frames like that, so back it goes
//if (tics > durs)

View file

@ -21,6 +21,7 @@ Documentation available here.
#include "doomdef.h"
#include "d_clisrv.h"
#include "command.h"
#include "console.h"
#include "m_argv.h"
#include "k_menu.h"
#include "mserv.h"
@ -81,6 +82,19 @@ Contact_error (void)
);
}
static void
Printf_url (const char *url)
{
boolean startup;
I_lock_mutex(&con_mutex);
startup = con_startup;
I_unlock_mutex(con_mutex);
(startup ? I_OutputMsg : CONS_Printf)(
"HMS: connecting '%s'...\n", url);
}
static size_t
HMS_on_read (char *s, size_t _1, size_t n, void *userdata)
{
@ -180,7 +194,7 @@ HMS_connect (const char *format, ...)
if (quack_token)
sprintf(&url[seek], "&token=%s", quack_token);
CONS_Printf("HMS: connecting '%s'...\n", url);
Printf_url(url);
buffer = malloc(sizeof *buffer);
buffer->curl = curl;

View file

@ -2447,7 +2447,7 @@ static void HU_DrawRankings(void)
if (circuitmap)
{
V_DrawCenteredString(64, 8, 0, "LAP COUNT");
V_DrawCenteredString(64, 16, hilicol, va("%d", cv_numlaps.value));
V_DrawCenteredString(64, 16, hilicol, va("%d", numlaps));
}
V_DrawCenteredString(256, 8, 0, "GAME SPEED");

View file

@ -595,13 +595,13 @@ static boolean SOCK_Get(void)
#ifdef USE_STUN
if (STUN_got_response(doomcom->data, c))
{
return false;
break;
}
#endif
if (hole_punch(c))
{
return false;
break;
}
// find remote node number

View file

@ -391,6 +391,7 @@ char sprnames[NUMSPRITES + 1][5] =
"SPHR", // Red Horizontal Spring
"SPHB", // Blue Horizontal Spring
"SPHG", // Grey Horizontal Spring
"POGS", // Pogo Spring
"BSTY", // Yellow Booster
"BSTR", // Red Booster
@ -3072,6 +3073,13 @@ state_t states[NUMSTATES] =
{SPR_SPVG, 0, 1, {NULL}, 0, 0, S_GREYSPRING4}, // S_GREYSPRING3
{SPR_SPVG, 2, 4, {NULL}, 0, 0, S_GREYSPRING1}, // S_GREYSPRING4
// Orange Spring (Pogo)
{SPR_POGS, 0, -1, {NULL}, 0, 0, S_NULL}, // S_POGOSPRING1
{SPR_POGS, 1, 2, {A_Pain}, 0, 0, S_POGOSPRING3}, // S_POGOSPRING2
{SPR_POGS, 1, 2, {A_PlaySeeSound}, 0, 0, S_POGOSPRING3}, // S_POGOSPRING2B
{SPR_POGS, 0, 1, {NULL}, 0, 0, S_POGOSPRING4}, // S_POGOSPRING3
{SPR_POGS, 2, 4, {NULL}, 0, 0, S_POGOSPRING1}, // S_POGOSPRING4
// Yellow Diagonal Spring
{SPR_SPDY, 0, -1, {NULL}, 0, 0, S_NULL}, // S_YDIAG1
{SPR_SPDY, 1, 1, {A_Pain}, 0, 0, S_YDIAG3}, // S_YDIAG2
@ -8236,6 +8244,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_GREYSPRING2 // raisestate
},
{ // MT_POGOSPRING
-1, // doomednum
S_POGOSPRING1, // spawnstate
1000, // spawnhealth
S_POGOSPRING2B, // seestate
sfx_eggspr, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
SKINCOLOR_SUNSLAM, // painchance
sfx_s3kb1, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
48*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
32*FRACUNIT, // mass
0, // damage
sfx_None, // activesound
MF_SOLID|MF_SPRING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
S_POGOSPRING2 // raisestate
},
{ // MT_YELLOWDIAG
554, // doomednum
S_YDIAG1, // spawnstate
@ -18246,7 +18281,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_SPLASH1, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
-72*FRACUNIT, // speed
72*FRACUNIT, // speed
1*FRACUNIT, // radius
8*FRACUNIT, // height
0, // display offset
@ -18273,7 +18308,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
-2*FRACUNIT, // speed
2*FRACUNIT, // speed
4*FRACUNIT, // radius
4*FRACUNIT, // height
0, // display offset
@ -18300,7 +18335,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
-24*FRACUNIT, // speed
24*FRACUNIT, // speed
4*FRACUNIT, // radius
4*FRACUNIT, // height
0, // display offset

View file

@ -937,6 +937,7 @@ typedef enum sprite
SPR_SPHR, // Red Horizontal Spring
SPR_SPHB, // Blue Horizontal Spring
SPR_SPHG, // Grey Horizontal Spring
SPR_POGS, // Pogo Spring
SPR_BSTY, // Yellow Booster
SPR_BSTR, // Red Booster
@ -3529,6 +3530,13 @@ typedef enum state
S_GREYSPRING3,
S_GREYSPRING4,
// Orange Spring (Pogo)
S_POGOSPRING1,
S_POGOSPRING2,
S_POGOSPRING2B,
S_POGOSPRING3,
S_POGOSPRING4,
// Yellow Diagonal Spring
S_YDIAG1,
S_YDIAG2,
@ -5656,6 +5664,7 @@ typedef enum mobj_type
MT_REDSPRING,
MT_BLUESPRING,
MT_GREYSPRING,
MT_POGOSPRING,
MT_YELLOWDIAG, // Yellow Diagonal Spring
MT_REDDIAG, // Red Diagonal Spring
MT_BLUEDIAG, // Blue Diagonal Spring

View file

@ -489,7 +489,6 @@ fixed_t K_BotRubberband(player_t *player)
fixed_t rubberband = FRACUNIT;
fixed_t rubbermax, rubbermin;
player_t *firstplace = NULL;
line_t *botController = NULL;
UINT8 i;
if (player->exiting)
@ -498,14 +497,17 @@ fixed_t K_BotRubberband(player_t *player)
return FRACUNIT;
}
botController = K_FindBotController(player->mo);
if (botController != NULL)
if (player->botvars.controller != UINT16_MAX)
{
// No Climb Flag: Disable rubberbanding
if (botController->flags & ML_NOCLIMB)
const line_t *botController = &lines[player->botvars.controller];
if (botController != NULL)
{
return FRACUNIT;
// No Climb Flag: Disable rubberbanding
if (botController->flags & ML_NOCLIMB)
{
return FRACUNIT;
}
}
}
@ -556,8 +558,8 @@ fixed_t K_BotRubberband(player_t *player)
// Lv. 1: x0.75 min
// Lv. 5: x0.875 min
// Lv. 9: x1.0 min
// Lv. MAX: x1.0 min
rubbermin = FRACUNIT - (((FRACUNIT/4) * (DIFFICULTBOT - min(DIFFICULTBOT, player->botvars.difficulty))) / (DIFFICULTBOT - 1));
// Lv. MAX: x1.125 min
rubbermin = FRACUNIT - (((FRACUNIT/4) * (DIFFICULTBOT - player->botvars.difficulty)) / (DIFFICULTBOT - 1));
if (rubberband > rubbermax)
{
@ -572,94 +574,19 @@ fixed_t K_BotRubberband(player_t *player)
}
/*--------------------------------------------------
fixed_t K_BotTopSpeedRubberband(player_t *player)
fixed_t K_UpdateRubberband(player_t *player)
See header file for description.
--------------------------------------------------*/
fixed_t K_BotTopSpeedRubberband(player_t *player)
fixed_t K_UpdateRubberband(player_t *player)
{
fixed_t rubberband = K_BotRubberband(player);
fixed_t dest = K_BotRubberband(player);
fixed_t ret = player->botvars.rubberband;
if (rubberband <= FRACUNIT)
{
// Never go below your regular top speed
rubberband = FRACUNIT;
}
else
{
// Max at +20% for level 9 bots
rubberband = FRACUNIT + ((rubberband - FRACUNIT) / 5);
}
// Ease into the new value.
ret += (dest - player->botvars.rubberband) >> 3;
// Only allow you to go faster than your regular top speed if you're facing the right direction
if (rubberband > FRACUNIT && player->mo != NULL && player->nextwaypoint != NULL)
{
const INT16 mindiff = 30;
const INT16 maxdiff = 60;
INT16 anglediff = 0;
fixed_t amt = rubberband - FRACUNIT;
angle_t destangle = R_PointToAngle2(
player->mo->x, player->mo->y,
player->nextwaypoint->mobj->x, player->nextwaypoint->mobj->y
);
angle_t angle = player->mo->angle - destangle;
if (angle < ANGLE_180)
{
anglediff = AngleFixed(angle) >> FRACBITS;
}
else
{
anglediff = 360 - (AngleFixed(angle) >> FRACBITS);
}
anglediff = abs(anglediff);
if (anglediff >= maxdiff)
{
rubberband = FRACUNIT;
}
else if (anglediff > mindiff)
{
amt = (amt * (maxdiff - anglediff)) / mindiff;
rubberband = FRACUNIT + amt;
}
}
return rubberband;
}
/*--------------------------------------------------
fixed_t K_BotFrictionRubberband(player_t *player, fixed_t frict)
See header file for description.
--------------------------------------------------*/
fixed_t K_BotFrictionRubberband(player_t *player, fixed_t frict)
{
const fixed_t value = 20776;
fixed_t rubberband = K_BotRubberband(player) - FRACUNIT;
fixed_t newFrict = frict;
if (rubberband <= 0)
{
// Never get weaker than normal friction
return frict;
}
if (player->tiregrease > 0)
{
// Bots will lose all of their momentum without this.
return frict;
}
newFrict = frict - FixedMul(value, rubberband);
if (newFrict < 0)
newFrict = 0;
if (newFrict > FRACUNIT)
newFrict = FRACUNIT;
return newFrict;
return ret;
}
/*--------------------------------------------------
@ -1148,7 +1075,7 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t *
if (dirdist <= rad)
{
fixed_t speedmul = FixedDiv(K_BotSpeedScaled(player, player->speed), K_GetKartSpeed(player, false));
fixed_t speedmul = FixedDiv(K_BotSpeedScaled(player, player->speed), K_GetKartSpeed(player, false, false));
fixed_t speedrad = rad/4;
if (speedmul > FRACUNIT)
@ -1343,13 +1270,9 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
// Remove any existing controls
memset(cmd, 0, sizeof(ticcmd_t));
if (gamestate != GS_LEVEL
|| player->mo->scale <= 1
|| player->playerstate == PST_DEAD
|| leveltime <= introtime
|| !(gametyperules & GTR_BOTS))
if (gamestate != GS_LEVEL)
{
// No need to do anything else.
// Not in a level.
return;
}
@ -1359,7 +1282,33 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
return;
}
if (!(gametyperules & GTR_BOTS) // No bot behaviors
|| K_GetNumWaypoints() == 0 // No waypoints
|| leveltime <= introtime // During intro camera
|| player->playerstate == PST_DEAD // Dead, respawning.
|| player->mo->scale <= 1) // Post-finish "death" animation
{
// No need to do anything else.
return;
}
if (player->exiting && player->nextwaypoint == K_GetFinishLineWaypoint() && ((mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) == LF_SECTIONRACE))
{
// Sprint map finish, don't give Sal's children migraines trying to pathfind out
return;
}
botController = K_FindBotController(player->mo);
if (botController == NULL)
{
player->botvars.controller = UINT16_MAX;
}
else
{
player->botvars.controller = botController - lines;
}
player->botvars.rubberband = K_UpdateRubberband(player);
if (player->trickpanel != 0)
{
@ -1369,6 +1318,12 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
return;
}
if (botController != NULL && (botController->flags & ML_EFFECT2))
{
// Disable bot controls entirely.
return;
}
destangle = player->mo->angle;
if (botController != NULL && (botController->flags & ML_EFFECT1))

View file

@ -88,36 +88,19 @@ fixed_t K_BotRubberband(player_t *player);
/*--------------------------------------------------
fixed_t K_BotTopSpeedRubberband(player_t *player);
fixed_t K_UpdateRubberband(player_t *player);
Gives a multiplier for a bot's rubberbanding.
Adjusted from K_BotRubberband to be used for top speed.
Eases the current rubberbanding value to the
new one, calculated by K_BotRubberband.
Input Arguments:-
player - Player to check.
player - Player to update.
Return:-
A multiplier in fixed point scale.
The new rubberband multiplier, in fixed point scale.
--------------------------------------------------*/
fixed_t K_BotTopSpeedRubberband(player_t *player);
/*--------------------------------------------------
fixed_t K_BotFrictionRubberband(player_t *player, fixed_t frict);
Gives a multiplier for a bot's rubberbanding.
Adjusted from K_BotRubberband to be used for friction.
Input Arguments:-
player - Player to check.
frict - Friction value to adjust.
Return:-
The new friction value.
--------------------------------------------------*/
fixed_t K_BotFrictionRubberband(player_t *player, fixed_t frict);
fixed_t K_UpdateRubberband(player_t *player);
/*--------------------------------------------------

View file

@ -471,7 +471,7 @@ static void K_BotItemSneaker(player_t *player, ticcmd_t *cmd)
{
if ((player->offroad && K_ApplyOffroad(player)) // Stuck in offroad, use it NOW
|| K_GetWaypointIsShortcut(player->nextwaypoint) == true // Going toward a shortcut!
|| player->speed < K_GetKartSpeed(player, false)/2 // Being slowed down too much
|| player->speed < K_GetKartSpeed(player, false, true) / 2 // Being slowed down too much
|| player->speedboost > (FRACUNIT/8) // Have another type of boost (tethering)
|| player->botvars.itemconfirm > 4*TICRATE) // Held onto it for too long
{
@ -830,7 +830,7 @@ static void K_BotItemEggmanExplosion(player_t *player, ticcmd_t *cmd)
--------------------------------------------------*/
static void K_BotItemOrbinaut(player_t *player, ticcmd_t *cmd)
{
const fixed_t topspeed = K_GetKartSpeed(player, false);
const fixed_t topspeed = K_GetKartSpeed(player, false, true);
fixed_t radius = FixedMul(2560 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed));
SINT8 throwdir = -1;
boolean tryLookback = false;
@ -888,7 +888,7 @@ static void K_BotItemOrbinaut(player_t *player, ticcmd_t *cmd)
--------------------------------------------------*/
static void K_BotItemDropTarget(player_t *player, ticcmd_t *cmd)
{
const fixed_t topspeed = K_GetKartSpeed(player, false);
const fixed_t topspeed = K_GetKartSpeed(player, false, true);
fixed_t radius = FixedMul(1280 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed));
SINT8 throwdir = -1;
boolean tryLookback = false;
@ -946,7 +946,7 @@ static void K_BotItemDropTarget(player_t *player, ticcmd_t *cmd)
--------------------------------------------------*/
static void K_BotItemJawz(player_t *player, ticcmd_t *cmd)
{
const fixed_t topspeed = K_GetKartSpeed(player, false);
const fixed_t topspeed = K_GetKartSpeed(player, false, true);
fixed_t radius = FixedMul(2560 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed));
SINT8 throwdir = 1;
boolean tryLookback = false;
@ -1165,7 +1165,7 @@ static void K_BotItemRings(player_t *player, ticcmd_t *cmd)
{
INT32 saferingsval = 16 - K_GetKartRingPower(player, false);
if (player->speed < K_GetKartSpeed(player, false)/2 // Being slowed down too much
if (player->speed < K_GetKartSpeed(player, false, true) / 2 // Being slowed down too much
|| player->speedboost > (FRACUNIT/5)) // Have another type of boost (tethering)
{
saferingsval -= 5;

View file

@ -675,6 +675,12 @@ static inline BlockItReturn_t PIT_LightningShieldAttack(mobj_t *thing)
return BMIT_ABORT;
}
if (thing == NULL || P_MobjWasRemoved(thing))
{
// Invalid?
return BMIT_ABORT;
}
if (thing == lightningSource)
{
// Don't explode yourself!!
@ -856,6 +862,9 @@ boolean K_SMKIceBlockCollide(mobj_t *t1, mobj_t *t2)
boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
{
const boolean flameT1 = (t1->player->flamedash > 0 && t1->player->itemtype == KITEM_FLAMESHIELD);
const boolean flameT2 = (t2->player->flamedash > 0 && t2->player->itemtype == KITEM_FLAMESHIELD);
boolean t1Condition = false;
boolean t2Condition = false;
boolean stungT1 = false;
@ -864,7 +873,12 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
t1Condition = (t1->scale > t2->scale + (mapobjectscale/8)) || (t1->player->invincibilitytimer > 0);
t2Condition = (t2->scale > t1->scale + (mapobjectscale/8)) || (t2->player->invincibilitytimer > 0);
if (t1Condition == true && t2Condition == false)
if ((t1Condition == true || flameT1 == true) && (t2Condition == true || flameT2 == true))
{
K_DoPowerClash(t1->player, t2->player);
return false;
}
else if (t1Condition == true && t2Condition == false)
{
P_DamageMobj(t2, t1, t1, 1, DMG_TUMBLE);
return true;
@ -873,14 +887,11 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
{
P_DamageMobj(t1, t2, t2, 1, DMG_TUMBLE);
return true;
} else if (t1Condition == true && t2Condition == true) {
K_DoPowerClash(t1->player, t2->player);
return false;
}
// Flame Shield dash damage
t1Condition = (t1->player->flamedash > 0 && t1->player->itemtype == KITEM_FLAMESHIELD);
t2Condition = (t2->player->flamedash > 0 && t2->player->itemtype == KITEM_FLAMESHIELD);
t1Condition = flameT1;
t2Condition = flameT2;
if (t1Condition == true && t2Condition == false)
{

View file

@ -129,7 +129,6 @@ void K_SetFollowerByNum(INT32 playernum, INT32 skinnum)
K_SetFollowerByNum(playernum, -1); // Not found, then set -1 (nothing) as our follower.
}
/*--------------------------------------------------
static void K_SetFollowerState(mobj_t *f, statenum_t state)
@ -193,6 +192,35 @@ UINT16 K_GetEffectiveFollowerColor(UINT16 followercolor, UINT16 playercolor)
return playercolor;
}
/*--------------------------------------------------
static void K_UpdateFollowerState(mobj_t *f, statenum_t state, followerstate_t type)
Sets a follower object's state & current state type tracker.
If the state tracker already matches, then this is ignored.
Input Arguments:-
f - The follower's mobj_t.
state - The state to set.
type - State type tracker.
Return:-
None
--------------------------------------------------*/
static void K_UpdateFollowerState(mobj_t *f, statenum_t state, followerstate_t type)
{
if (f == NULL || P_MobjWasRemoved(f) == true)
{
// safety net
return;
}
if (f->extravalue1 != (INT32)type)
{
K_SetFollowerState(f, state);
f->extravalue1 = type;
}
}
/*--------------------------------------------------
void K_HandleFollower(player_t *player)
@ -299,8 +327,9 @@ void K_HandleFollower(player_t *player)
// so let's spawn one!
P_SetTarget(&player->follower, P_SpawnMobj(sx, sy, sz, MT_FOLLOWER));
K_SetFollowerState(player->follower, fl.idlestate);
P_SetTarget(&player->follower->target, player->mo); // we need that to know when we need to disappear
K_UpdateFollowerState(player->follower, fl.idlestate, FOLLOWERSTATE_IDLE);
P_SetTarget(&player->follower->target, player->mo); // we need that to know when we need to disappear
P_InitAngle(player->follower, player->mo->angle);
// This is safe to only spawn it here, the follower is removed then respawned when switched.
@ -314,16 +343,6 @@ void K_HandleFollower(player_t *player)
P_SetTarget(&player->follower->hnext->hnext, bmobj); // this seems absolutely stupid, I know, but this will make updating the momentums/flags of these a bit easier.
P_SetTarget(&bmobj->target, player->follower); // Ditto
}
player->follower->extravalue1 = 0; // extravalue1 is used to know what "state set" to use.
/*
0 = idle
1 = forwards
2 = hurt
3 = win
4 = lose
5 = hitconfirm (< this one uses ->movecount as timer to know when to end, and goes back to normal states afterwards, unless hurt)
*/
}
else // follower exists, woo!
{
@ -430,16 +449,32 @@ void K_HandleFollower(player_t *player)
if (player->follower->z <= fh)
{
player->follower->z = fh;
if (player->follower->momz < 0)
if (!(player->mo->eflags & MFE_VERTICALFLIP) && player->follower->momz <= 0 && fl.bobamp != 0)
{
// Ground bounce
player->follower->momz = P_GetMobjZMovement(player->mo) + FixedMul(fl.bobamp, player->follower->scale);
player->follower->extravalue1 = FOLLOWERSTATE_RESET;
}
else if (player->follower->momz < 0)
{
// Ceiling clip
player->follower->momz = 0;
}
}
else if (player->follower->z >= ch)
{
player->follower->z = ch;
if (player->follower->momz > 0)
if ((player->mo->eflags & MFE_VERTICALFLIP) && player->follower->momz >= 0 && fl.bobamp != 0)
{
// Ground bounce
player->follower->momz = P_GetMobjZMovement(player->mo) - FixedMul(fl.bobamp, player->follower->scale);
player->follower->extravalue1 = FOLLOWERSTATE_RESET;
}
else if (player->follower->momz > 0)
{
// Ceiling clip
player->follower->momz = 0;
}
}
@ -498,11 +533,7 @@ void K_HandleFollower(player_t *player)
// spin out
player->follower->angle = player->drawangle;
if (player->follower->extravalue1 != 2)
{
player->follower->extravalue1 = 2;
K_SetFollowerState(player->follower, fl.hurtstate);
}
K_UpdateFollowerState(player->follower, fl.hurtstate, FOLLOWERSTATE_HURT);
if (player->mo->health <= 0)
{
@ -510,58 +541,32 @@ void K_HandleFollower(player_t *player)
player->follower->momz = player->mo->momz;
}
}
else if (player->exiting)
{
// win/ loss animations
if (K_IsPlayerLosing(player))
{
// L
K_UpdateFollowerState(player->follower, fl.losestate, FOLLOWERSTATE_LOSE);
}
else
{
// W
K_UpdateFollowerState(player->follower, fl.winstate, FOLLOWERSTATE_WIN);
}
}
else if (player->follower->movecount)
{
if (player->follower->extravalue1 != 5)
{
player->follower->extravalue1 = 5;
K_SetFollowerState(player->follower, fl.hitconfirmstate);
}
K_UpdateFollowerState(player->follower, fl.hitconfirmstate, FOLLOWERSTATE_HITCONFIRM);
player->follower->movecount--;
}
else if (player->speed > 10*player->mo->scale) // animation for moving fast enough
else if (player->speed > 10*player->mo->scale) // animation for moving fast enough
{
if (player->follower->extravalue1 != 1)
{
player->follower->extravalue1 = 1;
K_SetFollowerState(player->follower, fl.followstate);
}
K_UpdateFollowerState(player->follower, fl.followstate, FOLLOWERSTATE_FOLLOW);
}
else
{
// animations when nearly still. This includes winning and losing.
if (player->follower->extravalue1 != 0)
{
if (player->exiting)
{
// win/ loss animations
if (K_IsPlayerLosing(player))
{
// L
if (player->follower->extravalue1 != 4)
{
player->follower->extravalue1 = 4;
K_SetFollowerState(player->follower, fl.losestate);
}
}
else
{
// W
if (player->follower->extravalue1 != 3)
{
player->follower->extravalue1 = 3;
K_SetFollowerState(player->follower, fl.winstate);
}
}
}
else
{
// normal standstill
player->follower->extravalue1 = 0;
K_SetFollowerState(player->follower, fl.idlestate);
}
}
K_UpdateFollowerState(player->follower, fl.idlestate, FOLLOWERSTATE_IDLE);
}
}
}

View file

@ -28,6 +28,18 @@ typedef enum
FOLLOWERMODE__MAX
} followermode_t;
typedef enum
{
FOLLOWERSTATE_RESET, // Set to this to reset the state entirely.
FOLLOWERSTATE_IDLE,
FOLLOWERSTATE_FOLLOW,
FOLLOWERSTATE_HURT,
FOLLOWERSTATE_WIN,
FOLLOWERSTATE_LOSE,
FOLLOWERSTATE_HITCONFIRM, // Uses movecount as a timer for how long to play this state.
FOLLOWERSTATE__MAX
} followerstate_t;
//
// We'll define these here because they're really just a mobj that'll follow some rules behind a player
//

View file

@ -1708,7 +1708,7 @@ static void K_DrawKartPositionNum(INT32 num)
{
localpatch = kp_winnernum[(leveltime % (NUMWINFRAMES*3)) / 3];
}
else if (stplyr->laps >= cv_numlaps.value || stplyr->exiting) // Check for the final lap, or won
else if (stplyr->laps >= numlaps || stplyr->exiting) // Check for the final lap, or won
{
boolean useRedNums = K_IsPlayerLosing(stplyr);
@ -2339,7 +2339,7 @@ static void K_drawKartLapsAndRings(void)
V_DrawScaledPatch(fx, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_splitlapflag);
V_DrawScaledPatch(fx+22, fy, V_HUDTRANS|V_SLIDEIN|splitflags, frameslash);
if (cv_numlaps.value >= 10)
if (numlaps >= 10)
{
UINT8 ln[2];
ln[0] = ((stplyr->laps / 10) % 10);
@ -2348,8 +2348,8 @@ static void K_drawKartLapsAndRings(void)
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[0]]);
V_DrawScaledPatch(fx+17, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[1]]);
ln[0] = ((abs(cv_numlaps.value) / 10) % 10);
ln[1] = (abs(cv_numlaps.value) % 10);
ln[0] = ((numlaps / 10) % 10);
ln[1] = (numlaps % 10);
V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[0]]);
V_DrawScaledPatch(fx+31, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[1]]);
@ -2357,7 +2357,7 @@ static void K_drawKartLapsAndRings(void)
else
{
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(stplyr->laps) % 10]);
V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(cv_numlaps.value) % 10]);
V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(numlaps) % 10]);
}
// Rings
@ -2395,7 +2395,7 @@ static void K_drawKartLapsAndRings(void)
{
// Laps
V_DrawScaledPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_lapsticker);
V_DrawKartString(LAPS_X+33, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", min(stplyr->laps, cv_numlaps.value), cv_numlaps.value));
V_DrawKartString(LAPS_X+33, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", min(stplyr->laps, numlaps), numlaps));
// Rings
if (!uselives)
@ -2507,19 +2507,19 @@ static void K_drawKartSpeedometer(void)
{
case 1: // Sonic Drift 2 style percentage
default:
convSpeed = (stplyr->speed * 100) / K_GetKartSpeed(stplyr, false); // Based on top speed!
convSpeed = (stplyr->speed * 100) / K_GetKartSpeed(stplyr, false, true); // Based on top speed!
labeln = 0;
break;
case 2: // Kilometers
convSpeed = FixedDiv(FixedMul(stplyr->speed, 142371), mapobjectscale)/FRACUNIT; // 2.172409058
convSpeed = FixedDiv(FixedMul(stplyr->speed, 142371), mapobjectscale) / FRACUNIT; // 2.172409058
labeln = 1;
break;
case 3: // Miles
convSpeed = FixedDiv(FixedMul(stplyr->speed, 88465), mapobjectscale)/FRACUNIT; // 1.349868774
convSpeed = FixedDiv(FixedMul(stplyr->speed, 88465), mapobjectscale) / FRACUNIT; // 1.349868774
labeln = 2;
break;
case 4: // Fracunits
convSpeed = FixedDiv(stplyr->speed, mapobjectscale)/FRACUNIT; // 1.0. duh.
convSpeed = FixedDiv(stplyr->speed, mapobjectscale) / FRACUNIT; // 1.0. duh.
labeln = 3;
break;
}
@ -4369,7 +4369,7 @@ static void K_drawLapStartAnim(void)
kp_lapanim_hand[stplyr->karthud[khud_laphand]-1], NULL);
}
if (stplyr->laps == (UINT8)(cv_numlaps.value))
if (stplyr->laps == (UINT8)(numlaps))
{
newval = (62 - (32 * max(0, progress - 76))) * FRACUNIT;
oldval = (62 - (32 * max(0, progressOld - 76))) * FRACUNIT;

View file

@ -357,15 +357,15 @@ static INT32 K_KartItemOddsRace[NUMKARTRESULTS-1][8] =
/*Invincibility*/ { 0, 0, 0, 0, 3, 4, 6, 9 }, // Invincibility
/*Banana*/ { 2, 3, 1, 0, 0, 0, 0, 0 }, // Banana
/*Eggman Monitor*/ { 1, 2, 0, 0, 0, 0, 0, 0 }, // Eggman Monitor
/*Orbinaut*/ { 5, 4, 2, 2, 0, 0, 0, 0 }, // Orbinaut
/*Jawz*/ { 0, 3, 2, 1, 1, 0, 0, 0 }, // Jawz
/*Mine*/ { 0, 2, 3, 1, 0, 0, 0, 0 }, // Mine
/*Orbinaut*/ { 5, 5, 2, 2, 0, 0, 0, 0 }, // Orbinaut
/*Jawz*/ { 0, 4, 2, 1, 0, 0, 0, 0 }, // Jawz
/*Mine*/ { 0, 3, 3, 1, 0, 0, 0, 0 }, // Mine
/*Land Mine*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Land Mine
/*Ballhog*/ { 0, 0, 2, 2, 0, 0, 0, 0 }, // Ballhog
/*Self-Propelled Bomb*/ { 0, 0, 0, 0, 0, 2, 4, 0 }, // Self-Propelled Bomb
/*Grow*/ { 0, 0, 0, 1, 2, 3, 0, 0 }, // Grow
/*Shrink*/ { 0, 0, 0, 0, 0, 0, 2, 0 }, // Shrink
/*Lightning Shield*/ { 1, 2, 0, 0, 0, 0, 0, 0 }, // Lightning Shield
/*Lightning Shield*/ { 1, 0, 0, 0, 0, 0, 0, 0 }, // Lightning Shield
/*Bubble Shield*/ { 0, 1, 2, 1, 0, 0, 0, 0 }, // Bubble Shield
/*Flame Shield*/ { 0, 0, 0, 0, 0, 1, 3, 5 }, // Flame Shield
/*Hyudoro*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Hyudoro
@ -373,13 +373,13 @@ static INT32 K_KartItemOddsRace[NUMKARTRESULTS-1][8] =
/*Super Ring*/ { 2, 1, 1, 0, 0, 0, 0, 0 }, // Super Ring
/*Kitchen Sink*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Kitchen Sink
/*Drop Target*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Drop Target
/*Sneaker x2*/ { 0, 0, 2, 2, 1, 0, 0, 0 }, // Sneaker x2
/*Sneaker x3*/ { 0, 0, 0, 2, 6,10, 5, 0 }, // Sneaker x3
/*Sneaker x2*/ { 0, 0, 2, 2, 2, 0, 0, 0 }, // Sneaker x2
/*Sneaker x3*/ { 0, 0, 0, 1, 6,10, 5, 0 }, // Sneaker x3
/*Banana x3*/ { 0, 1, 1, 0, 0, 0, 0, 0 }, // Banana x3
/*Banana x10*/ { 0, 0, 0, 1, 0, 0, 0, 0 }, // Banana x10
/*Orbinaut x3*/ { 0, 0, 1, 0, 0, 0, 0, 0 }, // Orbinaut x3
/*Orbinaut x4*/ { 0, 0, 0, 1, 1, 0, 0, 0 }, // Orbinaut x4
/*Jawz x2*/ { 0, 0, 1, 2, 0, 0, 0, 0 } // Jawz x2
/*Orbinaut x4*/ { 0, 0, 0, 2, 0, 0, 0, 0 }, // Orbinaut x4
/*Jawz x2*/ { 0, 0, 1, 2, 1, 0, 0, 0 } // Jawz x2
};
static INT32 K_KartItemOddsBattle[NUMKARTRESULTS][2] =
@ -387,32 +387,32 @@ static INT32 K_KartItemOddsBattle[NUMKARTRESULTS][2] =
//P-Odds 0 1
/*Sneaker*/ { 2, 1 }, // Sneaker
/*Rocket Sneaker*/ { 0, 0 }, // Rocket Sneaker
/*Invincibility*/ { 2, 1 }, // Invincibility
/*Banana*/ { 1, 0 }, // Banana
/*Invincibility*/ { 4, 1 }, // Invincibility
/*Banana*/ { 0, 0 }, // Banana
/*Eggman Monitor*/ { 1, 0 }, // Eggman Monitor
/*Orbinaut*/ { 8, 0 }, // Orbinaut
/*Jawz*/ { 8, 1 }, // Jawz
/*Mine*/ { 6, 1 }, // Mine
/*Land Mine*/ { 0, 0 }, // Land Mine
/*Land Mine*/ { 2, 0 }, // Land Mine
/*Ballhog*/ { 2, 1 }, // Ballhog
/*Self-Propelled Bomb*/ { 0, 0 }, // Self-Propelled Bomb
/*Grow*/ { 2, 1 }, // Grow
/*Shrink*/ { 0, 0 }, // Shrink
/*Lightning Shield*/ { 4, 0 }, // Lightning Shield
/*Bubble Shield*/ { 1, 0 }, // Bubble Shield
/*Flame Shield*/ { 0, 0 }, // Flame Shield
/*Flame Shield*/ { 1, 0 }, // Flame Shield
/*Hyudoro*/ { 2, 0 }, // Hyudoro
/*Pogo Spring*/ { 2, 0 }, // Pogo Spring
/*Pogo Spring*/ { 3, 0 }, // Pogo Spring
/*Super Ring*/ { 0, 0 }, // Super Ring
/*Kitchen Sink*/ { 0, 0 }, // Kitchen Sink
/*Drop Target*/ { 0, 0 }, // Drop Target
/*Drop Target*/ { 2, 0 }, // Drop Target
/*Sneaker x2*/ { 0, 0 }, // Sneaker x2
/*Sneaker x3*/ { 1, 1 }, // Sneaker x3
/*Banana x3*/ { 1, 0 }, // Banana x3
/*Sneaker x3*/ { 0, 1 }, // Sneaker x3
/*Banana x3*/ { 0, 0 }, // Banana x3
/*Banana x10*/ { 1, 1 }, // Banana x10
/*Orbinaut x3*/ { 2, 0 }, // Orbinaut x3
/*Orbinaut x4*/ { 1, 1 }, // Orbinaut x4
/*Jawz x2*/ { 2, 1 } // Jawz x2
/*Jawz x2*/ { 5, 1 } // Jawz x2
};
#define DISTVAR (2048) // Magic number distance for use with item roulette tiers
@ -1176,9 +1176,15 @@ static fixed_t K_PlayerWeight(mobj_t *mobj, mobj_t *against)
}
else
{
// Applies rubberbanding, to prevent rubberbanding bots
// from causing super crazy bumps.
fixed_t spd = K_GetKartSpeed(mobj->player, false, true);
weight = (mobj->player->kartweight) * FRACUNIT;
if (mobj->player->speed > K_GetKartSpeed(mobj->player, false))
weight += (mobj->player->speed - K_GetKartSpeed(mobj->player, false))/8;
if (mobj->player->speed > spd)
weight += (mobj->player->speed - spd) / 8;
if (mobj->player->itemtype == KITEM_BUBBLESHIELD)
weight += 9*FRACUNIT;
}
@ -1694,9 +1700,13 @@ static void K_DrawDraftCombiring(player_t *player, player_t *victim, fixed_t cur
UINT8 c;
if (maxdist == 0)
c = 0;
{
c = leveltime % CHAOTIXBANDCOLORS;
}
else
{
c = FixedMul(CHAOTIXBANDCOLORS<<FRACBITS, FixedDiv(curdist-minimumdist, maxdist-minimumdist)) >> FRACBITS;
}
stepx = (victim->mo->x - player->mo->x) / CHAOTIXBANDLEN;
stepy = (victim->mo->y - player->mo->y) / CHAOTIXBANDLEN;
@ -1715,8 +1725,16 @@ static void K_DrawDraftCombiring(player_t *player, player_t *victim, fixed_t cur
curz + (P_RandomRange(24,48)*mapobjectscale),
MT_SIGNSPARKLE);
P_SetMobjState(band, S_SIGNSPARK1 + (leveltime % 11));
P_SetScale(band, (band->destscale = (3*player->mo->scale)/2));
if (maxdist == 0)
{
P_SetMobjState(band, S_KSPARK1 + (leveltime % 8));
P_SetScale(band, (band->destscale = player->mo->scale));
}
else
{
P_SetMobjState(band, S_SIGNSPARK1 + (leveltime % 11));
P_SetScale(band, (band->destscale = (3*player->mo->scale)/2));
}
band->color = colors[c];
band->colorized = true;
@ -1747,7 +1765,7 @@ static void K_DrawDraftCombiring(player_t *player, player_t *victim, fixed_t cur
*/
static void K_UpdateDraft(player_t *player)
{
fixed_t topspd = K_GetKartSpeed(player, false);
fixed_t topspd = K_GetKartSpeed(player, false, false);
fixed_t draftdistance;
fixed_t minDist;
UINT8 leniency;
@ -1769,17 +1787,20 @@ static void K_UpdateDraft(player_t *player)
draftdistance = FixedMul(draftdistance, K_GetKartGameSpeedScalar(gamespeed));
}
// On the contrary, the leniency period biases toward high weight.
// (See also: the leniency variable in K_SpawnDraftDust)
leniency = (3*TICRATE)/4 + ((player->kartweight-1) * (TICRATE/4));
minDist = 640 * player->mo->scale;
if (gametype == GT_BATTLE)
{
// TODO: gametyperules
minDist /= 4;
draftdistance *= 2;
leniency *= 4;
}
// On the contrary, the leniency period biases toward high weight.
// (See also: the leniency variable in K_SpawnDraftDust)
leniency = (3*TICRATE)/4 + ((player->kartweight-1) * (TICRATE/4));
// Not enough speed to draft.
if (player->speed >= 20*player->mo->scale)
{
@ -1850,7 +1871,23 @@ static void K_UpdateDraft(player_t *player)
// Draft power is used later in K_GetKartBoostPower, ranging from 0 for normal speed and FRACUNIT for max draft speed.
// How much this increments every tic biases toward acceleration! (min speed gets 1.5% per tic, max speed gets 0.5% per tic)
if (player->draftpower < FRACUNIT)
player->draftpower += (FRACUNIT/200) + ((9 - player->kartspeed) * ((3*FRACUNIT)/1600));
{
fixed_t add = (FRACUNIT/200) + ((9 - player->kartspeed) * ((3*FRACUNIT)/1600));;
player->draftpower += add;
if (player->bot && player->botvars.rival)
{
// Double speed for the rival!
player->draftpower += add;
}
if (gametype == GT_BATTLE)
{
// TODO: gametyperules
// Double speed in Battle
player->draftpower += add;
}
}
if (player->draftpower > FRACUNIT)
player->draftpower = FRACUNIT;
@ -1867,9 +1904,14 @@ static void K_UpdateDraft(player_t *player)
}
// No one to draft off of? Then you can knock that off.
if (player->draftleeway) // Prevent small disruptions from stopping your draft.
if (player->draftleeway > 0) // Prevent small disruptions from stopping your draft.
{
player->draftleeway--;
if (P_IsObjectOnGround(player->mo) == true)
{
// Allow maintaining tether in air setpieces.
player->draftleeway--;
}
if (player->lastdraft >= 0
&& player->lastdraft < MAXPLAYERS
&& playeringame[player->lastdraft]
@ -2026,7 +2068,7 @@ void K_SpawnDashDustRelease(player_t *player)
static fixed_t K_GetBrakeFXScale(player_t *player, fixed_t maxScale)
{
fixed_t s = FixedDiv(player->speed,
K_GetKartSpeed(player, false));
K_GetKartSpeed(player, false, false));
s = max(s, FRACUNIT);
s = min(s, maxScale);
@ -2359,7 +2401,7 @@ void K_KartMoveAnimation(player_t *player)
{
const INT16 minturn = KART_FULLTURN/8;
const fixed_t fastspeed = (K_GetKartSpeed(player, false) * 17) / 20; // 85%
const fixed_t fastspeed = (K_GetKartSpeed(player, false, true) * 17) / 20; // 85%
const fixed_t speedthreshold = player->mo->scale / 8;
const boolean onground = P_IsObjectOnGround(player->mo);
@ -2910,7 +2952,7 @@ boolean K_TripwirePassConditions(player_t *player)
player->growshrinktimer > 0 ||
player->flamedash ||
player->hyudorotimer ||
player->speed > 2 * K_GetKartSpeed(player, false)
player->speed > 2 * K_GetKartSpeed(player, false, true)
)
return true;
return false;
@ -2928,7 +2970,7 @@ boolean K_WaterRun(player_t *player)
player->sneakertimer ||
player->tiregrease ||
player->flamedash ||
player->speed > 2 * K_GetKartSpeed(player, false)
player->speed > 2 * K_GetKartSpeed(player, false, true)
)
return true;
return false;
@ -2950,11 +2992,13 @@ INT16 K_GetSpindashChargeTime(player_t *player)
fixed_t K_GetSpindashChargeSpeed(player_t *player)
{
// more speed for higher weight & speed
// Tails = +6.25%, Fang = +20.31%, Mighty = +20.31%, Metal = +25%
// Tails = +18.75%, Fang = +46.88%, Mighty = +46.88%, Metal = +56.25%
// (can be higher than this value when overcharged)
return (player->kartspeed + player->kartweight) * (FRACUNIT/32);
}
const fixed_t val = ((player->kartspeed + player->kartweight) + 2) * (FRACUNIT/32);
// TODO: gametyperules
return (gametype == GT_BATTLE) ? (4 * val) : val;
}
// sets boostpower, speedboost, accelboost, and handleboost to whatever we need it to be
static void K_GetKartBoostPower(player_t *player)
@ -3040,19 +3084,27 @@ static void K_GetKartBoostPower(player_t *player)
if (player->startboost) // Startup Boost
{
ADDBOOST(FRACUNIT/2, 4*FRACUNIT, 0); // + 50% top speed, + 400% acceleration, +0% handling
ADDBOOST(FRACUNIT, 4*FRACUNIT, sliptidehandling/2); // + 100% top speed, + 400% acceleration, +25% handling
}
if (player->driftboost) // Drift Boost
{
if (player->strongdriftboost) // Purple/Rainbow drift boost
// Rebuff Eggman's stat block corner
const INT32 heavyAccel = ((9 - player->kartspeed) * 2) + (player->kartweight - 1);
const fixed_t heavyAccelBonus = FRACUNIT + ((heavyAccel * maxmetabolismincrease * 2) / 24);
fixed_t driftSpeed = FRACUNIT/4; // 25% base
if (player->strongdriftboost > 0)
{
ADDBOOST(FRACUNIT/3, 4*FRACUNIT, 0); // + 33% top speed, + 400% acceleration, +0% handling
}
else
{
ADDBOOST(FRACUNIT/4, 4*FRACUNIT, 0); // + 25% top speed, + 400% acceleration, +0% handling
// Purple/Rainbow drift boost
driftSpeed = FixedMul(driftSpeed, 4*FRACUNIT/3); // 25% -> 33%
}
// Bottom-left bonus
driftSpeed = FixedMul(driftSpeed, heavyAccelBonus);
ADDBOOST(driftSpeed, 4*FRACUNIT, 0); // + variable top speed, + 400% acceleration, +0% handling
}
if (player->trickboost) // Trick pannel up-boost
@ -3081,6 +3133,12 @@ static void K_GetKartBoostPower(player_t *player)
draftspeed *= 2;
}
if (player->itemtype == KITEM_LIGHTNINGSHIELD)
{
// infinite tether
draftspeed *= 2;
}
speedboost += FixedMul(draftspeed, player->draftpower); // (Drafting suffers no boost stack penalty.)
numboosts++;
}
@ -3139,14 +3197,17 @@ fixed_t K_GetKartSpeedFromStat(UINT8 kartspeed)
return finalspeed;
}
fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower)
fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower, boolean dorubberband)
{
const boolean mobjValid = (player->mo != NULL && P_MobjWasRemoved(player->mo) == false);
fixed_t finalspeed = K_GetKartSpeedFromStat(player->kartspeed);
if (gametyperules & GTR_BUMPERS && player->bumpers <= 0)
finalspeed = 3 * finalspeed / 2;
if (player->spheres > 0)
{
fixed_t sphereAdd = (FRACUNIT/80); // 50% at max
fixed_t sphereAdd = (FRACUNIT/40); // 100% at max
finalspeed = FixedMul(finalspeed, FRACUNIT + (sphereAdd * player->spheres));
}
@ -3156,7 +3217,7 @@ fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower)
fixed_t add = (player->botvars.difficulty * (FRACUNIT/10)) / DIFFICULTBOT;
finalspeed = FixedMul(finalspeed, FRACUNIT + add);
if (player->botvars.rival == true)
if (player->bot && player->botvars.rival)
{
// +10% top speed for the rival
finalspeed = FixedMul(finalspeed, 11*FRACUNIT/10);
@ -3173,14 +3234,14 @@ fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower)
finalspeed = FixedMul(finalspeed, K_GrowShrinkSpeedMul(player));
}
if (K_PlayerUsesBotMovement(player))
{
finalspeed = FixedMul(finalspeed, K_BotTopSpeedRubberband(player));
}
finalspeed = FixedMul(finalspeed, player->boostpower + player->speedboost);
}
if (dorubberband == true && K_PlayerUsesBotMovement(player) == true)
{
finalspeed = FixedMul(finalspeed, player->botvars.rubberband);
}
return finalspeed;
}
@ -3190,11 +3251,9 @@ fixed_t K_GetKartAccel(player_t *player)
k_accel += 17 * (9 - player->kartspeed); // 121 - 257
if (player->spheres > 0)
{
fixed_t sphereAdd = (FRACUNIT/10); // 500% at max
k_accel = FixedMul(k_accel, FRACUNIT + (sphereAdd * player->spheres));
}
// karma bomb gets 2x acceleration
if (gametype == GT_BATTLE && player->bumpers <= 0)
k_accel *= 2;
return FixedMul(k_accel, (FRACUNIT + player->accelboost) / 4);
}
@ -3291,22 +3350,23 @@ SINT8 K_GetForwardMove(player_t *player)
fixed_t K_GetNewSpeed(player_t *player)
{
const fixed_t accelmax = 4000;
const fixed_t p_speed = K_GetKartSpeed(player, true);
const fixed_t p_accel = K_GetKartAccel(player);
const fixed_t p_speed = K_GetKartSpeed(player, true, true);
fixed_t p_accel = K_GetKartAccel(player);
fixed_t newspeed, oldspeed, finalspeed;
fixed_t orig = ORIG_FRICTION;
if (K_PlayerUsesBotMovement(player))
if (K_PlayerUsesBotMovement(player) == true && player->botvars.rubberband > 0)
{
orig = K_BotFrictionRubberband(player, ORIG_FRICTION);
// Acceleration is tied to top speed...
// so if we want JUST a top speed boost, we have to do this...
p_accel = FixedDiv(p_accel, player->botvars.rubberband);
}
oldspeed = R_PointToDist2(0, 0, player->rmomx, player->rmomy); // FixedMul(P_AproxDistance(player->rmomx, player->rmomy), player->mo->scale);
oldspeed = R_PointToDist2(0, 0, player->rmomx, player->rmomy);
// Don't calculate the acceleration as ever being above top speed
if (oldspeed > p_speed)
oldspeed = p_speed;
newspeed = FixedDiv(FixedDiv(FixedMul(oldspeed, accelmax - p_accel) + FixedMul(p_speed, p_accel), accelmax), orig);
newspeed = FixedDiv(FixedDiv(FixedMul(oldspeed, accelmax - p_accel) + FixedMul(p_speed, p_accel), accelmax), ORIG_FRICTION);
finalspeed = newspeed - oldspeed;
@ -3419,6 +3479,27 @@ void K_SetHitLagForObjects(mobj_t *mo1, mobj_t *mo2, INT32 tics, boolean fromDam
K_AddHitLag(mo2, finalTics, false); // mo2 is the inflictor, so don't use the damage property.
}
void K_AwardPlayerRings(player_t *player, INT32 rings, boolean overload)
{
UINT16 superring;
if (!overload)
{
INT32 totalrings =
RINGTOTAL(player) + (player->superring / 3);
/* capped at 20 rings */
if ((totalrings + rings) > 20)
rings = (20 - totalrings);
}
superring = player->superring + (rings * 3);
/* check if not overflow */
if (superring > player->superring)
player->superring = superring;
}
void K_DoInstashield(player_t *player)
{
mobj_t *layera;
@ -3524,8 +3605,11 @@ void K_SpinPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 typ
if (( player->spinouttype & KSPIN_THRUST ))
{
// At spinout, player speed is increased to 1/4 their regular speed, moving them forward
if (player->speed < K_GetKartSpeed(player, true)/4)
P_InstaThrust(player->mo, player->mo->angle, FixedMul(K_GetKartSpeed(player, true)/4, player->mo->scale));
fixed_t spd = K_GetKartSpeed(player, true, true) / 4;
if (player->speed < spd)
P_InstaThrust(player->mo, player->mo->angle, FixedMul(spd, player->mo->scale));
S_StartSound(player->mo, sfx_slip);
}
@ -3558,9 +3642,25 @@ static void K_RemoveGrowShrink(player_t *player)
P_RestoreMusic(player);
}
static fixed_t K_TumbleZ(mobj_t *mo, fixed_t input)
{
// Scales base tumble gravity to FRACUNIT
const fixed_t baseGravity = FixedMul(DEFAULT_GRAVITY, TUMBLEGRAVITY);
// Adapt momz w/ gravity
fixed_t gravityAdjust = FixedDiv(P_GetMobjGravity(mo), baseGravity);
if (mo->eflags & MFE_UNDERWATER)
{
// Reverse doubled falling speed.
gravityAdjust /= 2;
}
return FixedMul(input, -gravityAdjust);
}
void K_TumblePlayer(player_t *player, mobj_t *inflictor, mobj_t *source)
{
fixed_t gravityadjust;
(void)source;
K_DirectorFollowAttack(player, inflictor, source);
@ -3589,16 +3689,7 @@ void K_TumblePlayer(player_t *player, mobj_t *inflictor, mobj_t *source)
S_StartSound(player->mo, sfx_s3k9b);
// adapt momz w/ gravity?
// as far as kart goes normal gravity is 2 (FRACUNIT*2)
gravityadjust = P_GetMobjGravity(player->mo)/2; // so we'll halve it for our calculations.
if (player->mo->eflags & MFE_UNDERWATER)
gravityadjust /= 2; // halve "gravity" underwater
// and then modulate momz like that...
player->mo->momz = -gravityadjust * player->tumbleHeight;
player->mo->momz = K_TumbleZ(player->mo, player->tumbleHeight * FRACUNIT);
P_SetPlayerMobjState(player->mo, S_KART_SPINOUT);
@ -3613,8 +3704,6 @@ static boolean K_LastTumbleBounceCondition(player_t *player)
static void K_HandleTumbleBounce(player_t *player)
{
fixed_t gravityadjust;
player->tumbleBounces++;
player->tumbleHeight = (player->tumbleHeight * ((player->tumbleHeight > 100) ? 3 : 4)) / 5;
player->pflags &= ~PF_TUMBLESOUND;
@ -3647,7 +3736,7 @@ static void K_HandleTumbleBounce(player_t *player)
// A bit of damage hitlag.
// This gives a window for DI!!
K_AddHitLag(player->mo, 6, true);
K_AddHitLag(player->mo, 3, true);
if (P_IsDisplayPlayer(player) && player->tumbleHeight >= 40)
P_StartQuake((player->tumbleHeight*3/2)<<FRACBITS, 6); // funny earthquakes for the FEEL
@ -3657,16 +3746,8 @@ static void K_HandleTumbleBounce(player_t *player)
player->mo->momx = player->mo->momx / 2;
player->mo->momy = player->mo->momy / 2;
// adapt momz w/ gravity?
// as far as kart goes normal gravity is 2 (FRACUNIT*2)
gravityadjust = P_GetMobjGravity(player->mo)/2; // so we'll halve it for our calculations.
if (player->mo->eflags & MFE_UNDERWATER)
gravityadjust /= 2; // halve "gravity" underwater
// and then modulate momz like that...
player->mo->momz = -gravityadjust * player->tumbleHeight;
player->mo->momz = K_TumbleZ(player->mo, player->tumbleHeight * FRACUNIT);
}
// Play a falling sound when you start falling while tumbling and you're nowhere near done bouncing
@ -3683,6 +3764,21 @@ static void K_HandleTumbleSound(player_t *player)
}
}
void K_TumbleInterrupt(player_t *player)
{
// If player was tumbling, set variables so that they don't tumble like crazy after they're done respawning
if (player->tumbleBounces > 0)
{
player->tumbleBounces = 0; // MAXBOUNCES-1;
player->pflags &= ~PF_TUMBLELASTBOUNCE;
//players->tumbleHeight = 20;
players->mo->rollangle = 0;
player->spinouttype = KSPIN_WIPEOUT;
player->spinouttimer = player->wipeoutslow = TICRATE+2;
}
}
void K_ApplyTripWire(player_t *player, tripwirestate_t state)
{
if (state == TRIP_PASSED)
@ -3694,7 +3790,7 @@ void K_ApplyTripWire(player_t *player, tripwirestate_t state)
K_AddHitLag(player->mo, 10, false);
if (state == TRIP_PASSED && player->spinouttimer &&
player->speed > 2* K_GetKartSpeed(player, false))
player->speed > 2 * K_GetKartSpeed(player, false, true))
{
K_TumblePlayer(player, NULL, NULL);
}
@ -3764,6 +3860,8 @@ void K_HandleBumperChanges(player_t *player, UINT8 prevBumpers)
if (player->bumpers > 0 && prevBumpers == 0)
{
K_DoInvincibility(player, 8 * TICRATE);
if (netgame)
{
CONS_Printf(M_GetText("%s is back in the game!\n"), player_names[player-players]);
@ -4026,19 +4124,21 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I
{
mobj_t *th;
fixed_t x, y, z;
fixed_t topspeed = K_GetKartSpeed(source->player, false, false);
fixed_t finalspeed = speed;
fixed_t finalscale = mapobjectscale;
mobj_t *throwmo;
if (source->player != NULL)
{
if (source->player->itemscale == ITEMSCALE_SHRINK)
{
// Nerf the base item speed a bit.
finalspeed = FixedMul(finalspeed, SHRINK_PHYSICS_SCALE);
}
if (source->player->speed > K_GetKartSpeed(source->player, false))
if (source->player->speed > topspeed)
{
angle_t input = source->angle - an;
boolean invert = (input > ANGLE_180);
@ -4046,7 +4146,7 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I
input = InvAngle(input);
finalspeed = max(speed, FixedMul(speed, FixedMul(
FixedDiv(source->player->speed, K_GetKartSpeed(source->player, false)), // Multiply speed to be proportional to your own, boosted maxspeed.
FixedDiv(source->player->speed, topspeed), // Multiply speed to be proportional to your own, boosted maxspeed.
(((180<<FRACBITS) - AngleFixed(input)) / 180) // multiply speed based on angle diff... i.e: don't do this for firing backward :V
)));
}
@ -4498,7 +4598,7 @@ static void K_SpawnAIZDust(player_t *player)
if (!P_IsObjectOnGround(player->mo))
return;
if (player->speed <= K_GetKartSpeed(player, false))
if (player->speed <= K_GetKartSpeed(player, false, true))
return;
travelangle = K_MomentumAngle(player->mo);
@ -4683,6 +4783,9 @@ void K_SpawnDraftDust(mobj_t *mo)
{
UINT8 leniency = (3*TICRATE)/4 + ((mo->player->kartweight-1) * (TICRATE/4));
if (gametype == GT_BATTLE)
leniency *= 4;
ang = mo->player->drawangle;
if (mo->player->drift != 0)
@ -5645,7 +5748,7 @@ void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound)
mo->player->tricktime = 0; // Reset post-hitlag timer
// Setup the boost for potential upwards trick, at worse, make it your regular max speed. (boost = curr speed*1.25)
mo->player->trickboostpower = max(FixedDiv(mo->player->speed, K_GetKartSpeed(mo->player, false)) - FRACUNIT, 0)*125/100;
mo->player->trickboostpower = max(FixedDiv(mo->player->speed, K_GetKartSpeed(mo->player, false, false)) - FRACUNIT, 0)*125/100;
//CONS_Printf("Got boost: %d%\n", mo->player->trickboostpower*100 / FRACUNIT);
}
@ -5696,6 +5799,30 @@ static void K_ThrowLandMine(player_t *player)
throwmo->movecount = 0; // above player
}
void K_DoInvincibility(player_t *player, tic_t time)
{
if (!player->invincibilitytimer)
{
mobj_t *overlay = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_INVULNFLASH);
P_SetTarget(&overlay->target, player->mo);
overlay->destscale = player->mo->scale;
P_SetScale(overlay, player->mo->scale);
}
player->invincibilitytimer += time;
if (P_IsLocalPlayer(player) == true)
{
S_ChangeMusicSpecial("kinvnc");
}
else //used to be "if (P_IsDisplayPlayer(player) == false)"
{
S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmi : sfx_kinvnc));
}
P_RestoreMusic(player);
}
void K_KillBananaChain(mobj_t *banana, mobj_t *inflictor, mobj_t *source)
{
mobj_t *cachenext;
@ -6528,14 +6655,16 @@ static void K_MoveHeldObjects(player_t *player)
cur->angle = R_PointToAngle2(cur->x, cur->y, targx, targy);
/*if (P_IsObjectOnGround(player->mo) && player->speed > 0 && player->bananadrag > TICRATE
&& P_RandomChance(min(FRACUNIT/2, FixedDiv(player->speed, K_GetKartSpeed(player, false))/2)))
/*
if (P_IsObjectOnGround(player->mo) && player->speed > 0 && player->bananadrag > TICRATE
&& P_RandomChance(min(FRACUNIT/2, FixedDiv(player->speed, K_GetKartSpeed(player, false, false))/2)))
{
if (leveltime & 1)
targz += 8*(2*FRACUNIT)/7;
else
targz -= 8*(2*FRACUNIT)/7;
}*/
}
*/
if (speed > dist)
P_InstaThrust(cur, cur->angle, speed-dist);
@ -7169,6 +7298,8 @@ static void K_LookForRings(mobj_t *pmo)
*/
void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
{
const boolean onground = P_IsObjectOnGround(player->mo);
K_UpdateOffroad(player);
K_UpdateDraft(player);
K_UpdateEngineSounds(player); // Thanks, VAda!
@ -7440,8 +7571,10 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
if (player->strongdriftboost)
player->strongdriftboost--;
if (player->startboost)
if (player->startboost > 0 && onground == true)
{
player->startboost--;
}
if (player->spindashboost)
{
@ -7646,7 +7779,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
if (K_GetKartButtons(player) & BT_BRAKE &&
P_IsObjectOnGround(player->mo) &&
K_GetKartSpeed(player, false) / 2 <= player->speed)
K_GetKartSpeed(player, false, false) / 2 <= player->speed)
{
K_SpawnBrakeVisuals(player);
}
@ -7656,7 +7789,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
void K_KartResetPlayerColor(player_t *player)
{
boolean forcereset = false;
boolean fullbright = false;
if (!player->mo || P_MobjWasRemoved(player->mo)) // Can't do anything
@ -7672,9 +7804,9 @@ void K_KartResetPlayerColor(player_t *player)
if (player->eggmanexplode) // You're gonna diiiiie
{
const INT32 flashtime = 4<<(player->eggmanexplode/TICRATE);
if (player->eggmanexplode == 1 || (player->eggmanexplode % (flashtime/2) != 0))
if (player->eggmanexplode % (flashtime/2) != 0)
{
forcereset = true;
;
}
else if (player->eggmanexplode % flashtime == 0)
{
@ -7696,6 +7828,7 @@ void K_KartResetPlayerColor(player_t *player)
{
const tic_t defaultTime = itemtime+(2*TICRATE);
tic_t flicker = 2;
boolean skip = false;
fullbright = true;
@ -7703,22 +7836,21 @@ void K_KartResetPlayerColor(player_t *player)
{
player->mo->color = K_RainbowColor(leveltime / 2);
player->mo->colorized = true;
forcereset = false;
skip = true;
}
else
{
flicker += (defaultTime - player->invincibilitytimer) / TICRATE / 2;
forcereset = true;
}
if (leveltime % flicker == 0)
{
player->mo->color = SKINCOLOR_INVINCFLASH;
player->mo->colorized = true;
forcereset = false;
skip = true;
}
if (!forcereset)
if (skip)
{
goto finalise;
}
@ -7733,8 +7865,6 @@ void K_KartResetPlayerColor(player_t *player)
fullbright = true;
goto finalise;
}
forcereset = true;
}
if (player->ringboost && (leveltime & 1)) // ring boosting
@ -7746,10 +7876,7 @@ void K_KartResetPlayerColor(player_t *player)
else
{
player->mo->colorized = (player->dye != 0);
if (forcereset)
{
player->mo->color = player->dye ? player->dye : player->skincolor;
}
player->mo->color = player->dye ? player->dye : player->skincolor;
}
finalise:
@ -7951,6 +8078,12 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player)
if (angledelta < nextbestdelta || momdelta < nextbestmomdelta)
{
if (P_TraceBlockingLines(player->mo, waypoint->nextwaypoints[i]->mobj) == false)
{
// Save sight checks when all of the other checks pass, so we only do it if we have to
continue;
}
bestwaypoint = waypoint->nextwaypoints[i];
if (angledelta < nextbestdelta)
@ -7997,6 +8130,12 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player)
if (angledelta < nextbestdelta && momdelta < nextbestmomdelta)
{
if (P_TraceBlockingLines(player->mo, waypoint->prevwaypoints[i]->mobj) == false)
{
// Save sight checks when all of the other checks pass, so we only do it if we have to
continue;
}
bestwaypoint = waypoint->prevwaypoints[i];
nextbestdelta = angledelta;
@ -8168,7 +8307,7 @@ void K_UpdateDistanceFromFinishLine(player_t *const player)
// distance calculation to work easily
if ((mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) == 0U)
{
const UINT8 numfulllapsleft = ((UINT8)cv_numlaps.value - player->laps);
const UINT8 numfulllapsleft = ((UINT8)numlaps - player->laps);
player->distancetofinish += numfulllapsleft * K_GetCircuitLength();
@ -8341,14 +8480,13 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue)
return 0;
}
p_maxspeed = K_GetKartSpeed(player, false);
p_maxspeed = K_GetKartSpeed(player, false, true);
p_speed = min(currentSpeed, (p_maxspeed * 2));
weightadjust = FixedDiv((p_maxspeed * 3) - p_speed, (p_maxspeed * 3) + (player->kartweight * FRACUNIT));
if (K_PlayerUsesBotMovement(player))
{
turnfixed = FixedMul(turnfixed, 5*FRACUNIT/4); // Base increase to turning
turnfixed = FixedMul(turnfixed, K_BotRubberband(player));
}
if (player->drift != 0 && P_IsObjectOnGround(player->mo))
@ -8394,7 +8532,7 @@ INT32 K_GetUnderwaterTurnAdjust(player_t *player)
steer = 9 * steer / 5;
return FixedMul(steer, 8 * FixedDiv(player->speed,
2 * K_GetKartSpeed(player, false) / 3));
2 * K_GetKartSpeed(player, false, true) / 3));
}
else
return 0;
@ -8908,9 +9046,10 @@ static INT32 K_FlameShieldMax(player_t *player)
disttofinish = players[i].distancetofinish;
}
if (numplayers <= 1)
if (numplayers <= 1 || gametype == GT_BATTLE)
{
return 16; // max when alone, for testing
// and when in battle, for chaos
}
else if (player->position == 1)
{
@ -9149,8 +9288,14 @@ static void K_KartSpindash(player_t *player)
// if spindash was charged enough, give a small thrust.
if (player->spindash >= SPINDASHTHRUSTTIME)
{
fixed_t thrust = FixedMul(player->mo->scale, player->spindash*FRACUNIT/5);
// TODO: gametyperules
if (gametype == GT_BATTLE)
thrust *= 2;
// Give a bit of a boost depending on charge.
P_InstaThrust(player->mo, player->mo->angle, FixedMul(player->mo->scale, player->spindash*FRACUNIT/5));
P_InstaThrust(player->mo, player->mo->angle, thrust);
}
if (!player->tiregrease)
@ -9348,13 +9493,6 @@ void K_AdjustPlayerFriction(player_t *player)
else
player->mo->movefactor = FRACUNIT;
}
// Don't go too far above your top speed when rubberbanding
// Down here, because we do NOT want to modify movefactor
if (K_PlayerUsesBotMovement(player))
{
player->mo->friction = K_BotFrictionRubberband(player, player->mo->friction);
}
}
//
@ -9617,25 +9755,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
case KITEM_INVINCIBILITY:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) // Doesn't hold your item slot hostage normally, so you're free to waste it if you have multiple
{
if (!player->invincibilitytimer)
{
mobj_t *overlay = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_INVULNFLASH);
P_SetTarget(&overlay->target, player->mo);
overlay->destscale = player->mo->scale;
P_SetScale(overlay, player->mo->scale);
}
player->invincibilitytimer += itemtime+(2*TICRATE); // 10 seconds
if (P_IsLocalPlayer(player) == true)
{
S_ChangeMusicSpecial("kinvnc");
}
else //used to be "if (P_IsDisplayPlayer(player) == false)"
{
S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmi : sfx_kinvnc));
}
P_RestoreMusic(player);
K_DoInvincibility(player, 10 * TICRATE);
K_PlayPowerGloatSound(player->mo);
player->itemamount--;
}
@ -9883,7 +10003,8 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
player->mo->destscale = FixedMul(player->mo->destscale, SHRINK_SCALE);
}
player->growshrinktimer = itemtime+(4*TICRATE); // 12 seconds
// TODO: gametyperules
player->growshrinktimer = (gametype == GT_BATTLE ? 8 : 12) * TICRATE;
if (player->invincibilitytimer > 0)
{
@ -10007,14 +10128,17 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
if ((cmd->buttons & BT_ATTACK) && (player->pflags & PF_HOLDREADY))
{
// TODO: gametyperules
const INT32 incr = gametype == GT_BATTLE ? 4 : 2;
if (player->flamedash == 0)
{
S_StartSound(player->mo, sfx_s3k43);
K_PlayBoostTaunt(player->mo);
}
player->flamedash += 2;
player->flamemeter += 2;
player->flamedash += incr;
player->flamemeter += incr;
if (!onground)
{
@ -10041,8 +10165,12 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
{
player->pflags |= PF_HOLDREADY;
if (player->flamemeter > 0)
player->flamemeter--;
// TODO: gametyperules
if (gametype != GT_BATTLE || leveltime % 6 == 0)
{
if (player->flamemeter > 0)
player->flamemeter--;
}
if (player->flamelength > destlen)
{
@ -10071,16 +10199,15 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO && player->trickpanel == 0)
{
K_PlayBoostTaunt(player->mo);
K_DoPogoSpring(player->mo, 32<<FRACBITS, 2);
player->trickpanel = 1;
player->pflags |= PF_TRICKDELAY;
//K_DoPogoSpring(player->mo, 32<<FRACBITS, 2);
P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_POGOSPRING);
player->itemamount--;
}
break;
case KITEM_SUPERRING:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO && player->superring < (UINT16_MAX - (10*3)))
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
player->superring += (10*3);
K_AwardPlayerRings(player, 10, true);
player->itemamount--;
}
break;
@ -10193,7 +10320,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
const angle_t lr = ANGLE_45;
fixed_t momz = FixedDiv(player->mo->momz, mapobjectscale); // bring momz back to scale...
fixed_t speedmult = max(0, FRACUNIT - abs(momz)/TRICKMOMZRAMP); // TRICKMOMZRAMP momz is minimum speed (Should be 20)
fixed_t basespeed = P_AproxDistance(player->mo->momx, player->mo->momy); // at WORSE, keep your normal speed when tricking.
fixed_t basespeed = K_GetKartSpeed(player, false, false); // at WORSE, keep your normal speed when tricking.
fixed_t speed = FixedMul(speedmult, P_AproxDistance(player->mo->momx, player->mo->momy));
K_trickPanelTimingVisual(player, momz);

View file

@ -67,11 +67,13 @@ void K_KartPlayerAfterThink(player_t *player);
angle_t K_MomentumAngle(mobj_t *mo);
void K_AddHitLag(mobj_t *mo, INT32 tics, boolean fromDamage);
void K_SetHitLagForObjects(mobj_t *mo1, mobj_t *mo2, INT32 tics, boolean fromDamage);
void K_AwardPlayerRings(player_t *player, INT32 rings, boolean overload);
void K_DoInstashield(player_t *player);
void K_DoPowerClash(player_t *t1, player_t *t2);
void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UINT8 bumpersRemoved);
void K_SpinPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 type);
void K_TumblePlayer(player_t *player, mobj_t *inflictor, mobj_t *source);
void K_TumbleInterrupt(player_t *player);
INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source);
void K_DebtStingPlayer(player_t *player, mobj_t *source);
void K_HandleBumperChanges(player_t *player, UINT8 prevBumpers);
@ -91,6 +93,7 @@ mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing,
void K_PuntMine(mobj_t *mine, mobj_t *punter);
void K_DoSneaker(player_t *player, INT32 type);
void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound);
void K_DoInvincibility(player_t *player, tic_t time);
void K_KillBananaChain(mobj_t *banana, mobj_t *inflictor, mobj_t *source);
void K_UpdateHnextList(player_t *player, boolean clean);
void K_DropHnextList(player_t *player, boolean keepshields);
@ -126,7 +129,7 @@ INT16 K_GetSpindashChargeTime(player_t *player);
fixed_t K_GetSpindashChargeSpeed(player_t *player);
fixed_t K_GrowShrinkSpeedMul(player_t *player);
fixed_t K_GetKartSpeedFromStat(UINT8 kartspeed);
fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower);
fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower, boolean dorubberbanding);
fixed_t K_GetKartAccel(player_t *player);
UINT16 K_GetKartFlashing(player_t *player);
boolean K_PlayerShrinkCheat(player_t *player);

View file

@ -1,5 +1,12 @@
/// \file k_pwrlv.c
/// \brief SRB2Kart Power Levels
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2022 by Sally Cochenour
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
// \brief Power Level system
#include "k_pwrlv.h"
#include "d_netcmd.h"
@ -19,9 +26,12 @@ UINT16 vspowerlevel[PWRLV_NUMTYPES];
// This is done so that clients will never be able to hack someone else's score over the server.
UINT16 clientpowerlevels[MAXPLAYERS][PWRLV_NUMTYPES];
// Which players spec-scummed, and their power level before scumming.
// On race finish, everyone is considered to have "won" against these people.
INT16 nospectategrief[MAXPLAYERS];
// Total calculated power add during the match,
// totalled at the end of the round.
INT16 clientPowerAdd[MAXPLAYERS];
// Players who spectated mid-race
UINT8 spectateGriefed = 0;
// Game setting scrambles based on server Power Level
SINT8 speedscramble = -1;
@ -52,8 +62,14 @@ void K_ClearClientPowerLevels(void)
{
UINT8 i, j;
for (i = 0; i < MAXPLAYERS; i++)
{
clientPowerAdd[i] = 0;
for (j = 0; j < PWRLV_NUMTYPES; j++)
{
clientpowerlevels[i][j] = 0;
}
}
}
// Adapted from this: http://wiki.tockdom.com/wiki/Player_Rating
@ -71,7 +87,7 @@ INT16 K_CalculatePowerLevelInc(INT16 diff)
diff = -MAXDIFF;
#undef MAXDIFF
x = ((diff-2)<<FRACBITS) / PWRLVRECORD_START;
x = ((diff-2)<<FRACBITS) / PWRLVRECORD_MEDIAN;
for (j = 3; j < 10; j++) // Just skipping to 3 since 0 thru 2 will always just add 0...
{
@ -98,6 +114,23 @@ INT16 K_CalculatePowerLevelInc(INT16 diff)
return (INT16)(increment >> FRACBITS);
}
INT16 K_PowerLevelPlacementScore(player_t *player)
{
if ((player->pflags & PF_NOCONTEST) || (player->spectator))
{
return 0;
}
if (gametyperules & GTR_CIRCUIT)
{
return MAXPLAYERS - player->position;
}
else
{
return player->score;
}
}
INT16 K_CalculatePowerLevelAvg(void)
{
fixed_t avg = 0;
@ -143,7 +176,269 @@ INT16 K_CalculatePowerLevelAvg(void)
return (INT16)(avg >> FRACBITS);
}
// -- K_UpdatePowerLevels could not be moved here due to usage of y_data, unfortunately. --
void K_UpdatePowerLevels(player_t *player, UINT8 lap, boolean forfeit)
{
const UINT8 playerNum = player - players;
const boolean exitBonus = ((lap > numlaps) || (player->pflags & PF_NOCONTEST));
SINT8 powerType = K_UsingPowerLevels();
INT16 yourScore = 0;
UINT16 yourPower = 0;
UINT8 i;
// Compare every single player against each other for power level increases.
// Every player you won against gives you more points, and vice versa.
// The amount of points won per match-up depends on the difference between the loser's power and the winner's power.
// See K_CalculatePowerLevelInc for more info.
if (powerType == PWRLV_DISABLED)
{
return;
}
if (!playeringame[playerNum] || player->spectator)
{
return;
}
//CONS_Printf("\n========\n");
//CONS_Printf("* Power Level change for player %s (LAP %d) *\n", player_names[playerNum], lap);
//CONS_Printf("========\n");
yourPower = clientpowerlevels[playerNum][powerType];
if (yourPower == 0)
{
// Guests don't record power level changes.
return;
}
//CONS_Printf("%s's PWR.LV: %d\n", player_names[playerNum], yourPower);
yourScore = K_PowerLevelPlacementScore(player);
//CONS_Printf("%s's gametype score: %d\n", player_names[playerNum], yourScore);
//CONS_Printf("========\n");
for (i = 0; i < MAXPLAYERS; i++)
{
UINT16 theirScore = 0;
INT16 theirPower = 0;
INT16 diff = 0; // Loser PWR.LV - Winner PWR.LV
INT16 inc = 0; // Total pt increment
boolean won = false;
if (i == playerNum) // Same person
{
continue;
}
if (!playeringame[i] || players[i].spectator)
{
continue;
}
//CONS_Printf("%s VS %s:\n", player_names[playerNum], player_names[i]);
theirPower = clientpowerlevels[i][powerType];
if (theirPower == 0)
{
// No power level (splitscreen guests, bots)
continue;
}
//CONS_Printf("%s's PWR.LV: %d\n", player_names[i], theirPower);
theirScore = K_PowerLevelPlacementScore(&players[i]);
//CONS_Printf("%s's gametype score: %d\n", player_names[i], theirScore);
if (yourScore == theirScore && forfeit == false) // Tie -- neither get any points for this match up.
{
//CONS_Printf("TIE, no change.\n");
continue;
}
won = (yourScore > theirScore);
if (won == true && forfeit == false) // This player won!
{
diff = theirPower - yourPower;
inc += K_CalculatePowerLevelInc(diff);
//CONS_Printf("WON! Diff is %d, increment is %d\n", diff, inc);
}
else // This player lost...
{
diff = yourPower - theirPower;
inc -= K_CalculatePowerLevelInc(diff);
//CONS_Printf("LOST... Diff is %d, increment is %d\n", diff, inc);
}
if (exitBonus == false)
{
INT16 prevInc = inc;
inc /= max(numlaps-1, 1);
if (inc == 0)
{
if (prevInc > 0)
{
inc = 1;
}
else if (prevInc < 0)
{
inc = -1;
}
}
//CONS_Printf("Reduced (%d / %d = %d) because it's not the end of the race\n", prevInc, numlaps, inc);
}
//CONS_Printf("========\n");
if (inc == 0)
{
CONS_Printf("Total Result: No increment, no change.\n");
continue;
}
//CONS_Printf("Total Result:\n");
//CONS_Printf("Increment: %d\n", inc);
//CONS_Printf("%s current: %d\n", player_names[playerNum], clientPowerAdd[playerNum]);
clientPowerAdd[playerNum] += inc;
//CONS_Printf("%s final: %d\n", player_names[playerNum], clientPowerAdd[playerNum]);
//CONS_Printf("%s current: %d\n", player_names[i], clientPowerAdd[i]);
clientPowerAdd[i] -= inc;
//CONS_Printf("%s final: %d\n", player_names[i], clientPowerAdd[i]);
//CONS_Printf("========\n");
}
}
void K_UpdatePowerLevelsOnFailure(player_t *player)
{
// Update upon spectate / quit / NO CONTEST
INT16 lapsLeft = 0;
UINT8 i;
lapsLeft = (numlaps - player->latestlap) + 1;
if (lapsLeft <= 0)
{
return;
}
for (i = 0; i < lapsLeft; i++)
{
K_UpdatePowerLevels(player, player->latestlap + (i + 1), true);
}
player->latestlap = numlaps+1;
}
INT16 K_FinalPowerIncrement(player_t *player, INT16 yourPower, INT16 baseInc)
{
INT16 inc = baseInc;
UINT8 numPlayers = 0;
UINT8 i;
if (yourPower == 0)
{
// Guests don't record power level changes.
return 0;
}
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator)
{
continue;
}
numPlayers++;
}
if (inc <= 0)
{
if (player->position == 1)
{
// Won the whole match?
// Get at least one point.
inc = 1;
}
else
{
// You trade points in 1v1s,
// but is more lenient in bigger lobbies.
inc /= max(1, numPlayers-1);
if (inc == 0)
{
if (baseInc > 0)
{
inc = 1;
}
else if (baseInc < 0)
{
inc = -1;
}
}
}
}
if (yourPower + inc > PWRLVRECORD_MAX)
{
inc -= ((yourPower + inc) - PWRLVRECORD_MAX);
}
if (yourPower + inc < PWRLVRECORD_MIN)
{
inc -= ((yourPower + inc) - PWRLVRECORD_MIN);
}
return inc;
}
void K_CashInPowerLevels(void)
{
SINT8 powerType = K_UsingPowerLevels();
UINT8 i;
//CONS_Printf("\n========\n");
//CONS_Printf("Cashing in power level changes...\n");
//CONS_Printf("========\n");
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] == true && powerType != PWRLV_DISABLED)
{
INT16 inc = K_FinalPowerIncrement(&players[i], clientpowerlevels[i][powerType], clientPowerAdd[i]);
clientpowerlevels[i][powerType] += inc;
//CONS_Printf("%s: %d -> %d (%d)\n", player_names[i], clientpowerlevels[i][powerType] - inc, clientpowerlevels[i][powerType], inc);
if (!demo.playback && i == consoleplayer && inc != 0)
{
vspowerlevel[powerType] = clientpowerlevels[i][powerType];
if (M_UpdateUnlockablesAndExtraEmblems())
{
S_StartSound(NULL, sfx_ncitem);
}
G_SaveGameData();
}
}
clientPowerAdd[i] = 0;
}
//CONS_Printf("========\n");
}
void K_SetPowerLevelScrambles(SINT8 powertype)
{
@ -227,7 +522,7 @@ void K_SetPowerLevelScrambles(SINT8 powertype)
{
case 5:
speed = KARTSPEED_HARD;
encore = true;
encore = P_RandomChance(FRACUNIT>>1);
break;
case 4:
speed = P_RandomChance((7<<FRACBITS)/10) ? KARTSPEED_HARD : KARTSPEED_NORMAL;
@ -238,7 +533,7 @@ void K_SetPowerLevelScrambles(SINT8 powertype)
encore = P_RandomChance(FRACUNIT>>2);
break;
case 2:
speed = 1;
speed = KARTSPEED_NORMAL;
encore = P_RandomChance(FRACUNIT>>3);
break;
case 1: default:
@ -254,7 +549,7 @@ void K_SetPowerLevelScrambles(SINT8 powertype)
CONS_Debug(DBG_GAMELOGIC, "Rolled speed: %d\n", speed);
CONS_Debug(DBG_GAMELOGIC, "Rolled encore: %s\n", (encore ? "true" : "false"));
if (cv_kartspeed.value == -1)
if (cv_kartspeed.value == KARTSPEED_AUTO)
speedscramble = speed;
else
speedscramble = -1;
@ -270,88 +565,89 @@ void K_SetPowerLevelScrambles(SINT8 powertype)
}
}
void K_PlayerForfeit(UINT8 playernum, boolean pointloss)
void K_PlayerForfeit(UINT8 playerNum, boolean pointLoss)
{
UINT8 p = 0;
INT32 powertype = PWRLV_DISABLED;
UINT16 yourpower = PWRLVRECORD_DEF;
UINT16 theirpower = PWRLVRECORD_DEF;
INT16 diff = 0; // Loser PWR.LV - Winner PWR.LV
SINT8 powerType = PWRLV_DISABLED;
UINT16 yourPower = 0;
INT16 inc = 0;
UINT8 i;
// power level & spectating is netgames only
if (!netgame)
{
return;
// This server isn't using power levels anyway!
if (!cv_kartusepwrlv.value)
return;
}
// Hey, I just got here!
if (players[playernum].jointime <= 1)
if (players[playerNum].jointime <= 1)
{
return;
}
// 20 sec into the match counts as a forfeit -- automatic loss against every other player in the match.
// 20 sec into a match counts as a forfeit -- automatic loss against every other player in the match.
if (gamestate != GS_LEVEL || leveltime <= starttime+(20*TICRATE))
{
return;
}
spectateGriefed++;
// This server isn't using power levels, so don't mess with them.
if (!cv_kartusepwrlv.value)
{
return;
}
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && !players[i].spectator)
if ((playeringame[i] && !players[i].spectator)
|| (i == playerNum))
{
p++;
}
}
if (p < 2) // no players
return;
if ((gametyperules & GTR_CIRCUIT))
powertype = PWRLV_RACE;
else if ((gametyperules & GTR_BUMPERS))
powertype = PWRLV_BATTLE;
if (powertype == PWRLV_DISABLED) // No power type?!
return;
if (clientpowerlevels[playernum][powertype] == 0) // splitscreen guests don't record power level changes
return;
yourpower = clientpowerlevels[playernum][powertype];
// Set up the point compensation.
nospectategrief[playernum] = yourpower;
if (!pointloss) // This is set for stuff like sync-outs, which shouldn't be so harsh on the victim!
return;
for (i = 0; i < MAXPLAYERS; i++)
{
if (i == playernum)
continue;
if (clientpowerlevels[i][powertype] == 0) // No power level (splitscreen guests, bots)
continue;
theirpower = clientpowerlevels[i][powertype];
diff = yourpower - theirpower;
inc -= K_CalculatePowerLevelInc(diff);
return;
}
if (inc == 0) // No change.
return;
powerType = K_UsingPowerLevels();
if (yourpower + inc > PWRLVRECORD_MAX) // I mean... we're subtracting... but y'know how it is :V
inc -= ((yourpower + inc) - PWRLVRECORD_MAX);
if (yourpower + inc < PWRLVRECORD_MIN)
inc -= ((yourpower + inc) - PWRLVRECORD_MIN);
clientpowerlevels[playernum][powertype] += inc;
if (!demo.playback && playernum == consoleplayer)
if (powerType == PWRLV_DISABLED) // No power type?!
{
vspowerlevel[powertype] = clientpowerlevels[playernum][powertype];
return;
}
yourPower = clientpowerlevels[playerNum][powerType];
if (yourPower == 0) // splitscreen guests don't record power level changes
{
return;
}
K_UpdatePowerLevelsOnFailure(&players[playerNum]);
inc = K_FinalPowerIncrement(&players[playerNum], yourPower, clientPowerAdd[playerNum]);
if (inc >= 0)
{
// Don't record no change or increases.
return;
}
// pointLoss isn't set for stuff like sync-outs,
// which shouldn't be so harsh on the victim!
if (!demo.playback && pointLoss == true && playerNum == consoleplayer)
{
vspowerlevel[powerType] = yourPower + inc;
if (M_UpdateUnlockablesAndExtraEmblems())
{
S_StartSound(NULL, sfx_ncitem);
G_SaveGameData(); // save your punishment!
}
G_SaveGameData();
}
}

View file

@ -1,16 +1,30 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2022 by Sally Cochenour
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
// \brief Power Level system
#ifndef __K_PWRLV__
#define __K_PWRLV__
#include "doomtype.h"
#include "doomdef.h"
#include "d_player.h"
#define PWRLV_DISABLED -1
#define PWRLV_RACE 0
#define PWRLV_BATTLE 1
#define PWRLV_NUMTYPES 2
typedef enum
{
PWRLV_DISABLED = -1,
PWRLV_RACE = 0,
PWRLV_BATTLE = 1,
PWRLV_NUMTYPES = 2,
} pwrlv_type_t;
#define PWRLVRECORD_START 1000
#define PWRLVRECORD_DEF 5000
#define PWRLVRECORD_MEDIAN 5000
#define PWRLVRECORD_MIN 1
#define PWRLVRECORD_MAX 9999
@ -19,13 +33,18 @@ extern SINT8 encorescramble;
extern UINT16 vspowerlevel[PWRLV_NUMTYPES];
extern UINT16 clientpowerlevels[MAXPLAYERS][PWRLV_NUMTYPES];
extern INT16 nospectategrief[MAXPLAYERS];
extern INT16 clientPowerAdd[MAXPLAYERS];
extern UINT8 spectateGriefed;
SINT8 K_UsingPowerLevels(void);
void K_ClearClientPowerLevels(void);
INT16 K_CalculatePowerLevelInc(INT16 diff);
INT16 K_PowerLevelPlacementScore(player_t *player);
INT16 K_CalculatePowerLevelAvg(void);
//void K_UpdatePowerLevels(void);
void K_UpdatePowerLevels(player_t *player, UINT8 lap, boolean forfeit);
void K_UpdatePowerLevelsOnFailure(player_t *player);
INT16 K_FinalPowerIncrement(player_t *player, INT16 yourPower, INT16 increment);
void K_CashInPowerLevels(void);
void K_SetPowerLevelScrambles(SINT8 powertype);
void K_PlayerForfeit(UINT8 playernum, boolean nopointloss);

View file

@ -151,18 +151,8 @@ void K_DoIngameRespawn(player_t *player)
player->ringboost = 0;
player->driftboost = player->strongdriftboost = 0;
// If player was tumbling, set variables so that they don't tumble like crazy after they're done respawning
if (player->tumbleBounces > 0)
{
player->tumbleBounces = 0; // MAXBOUNCES-1;
player->pflags &= ~PF_TUMBLELASTBOUNCE;
//players->tumbleHeight = 20;
players->mo->rollangle = 0;
player->spinouttype = KSPIN_WIPEOUT;
player->spinouttimer = player->wipeoutslow = (3*TICRATE/2)+2;
}
K_TumbleInterrupt(player);
P_ResetPlayer(player);
// Set up respawn position if invalid
@ -278,6 +268,7 @@ void K_DoIngameRespawn(player_t *player)
player->respawn.state = RESPAWNST_MOVE;
player->respawn.airtimer = player->airtime;
player->respawn.truedeath = false;
}
/*--------------------------------------------------
@ -567,7 +558,9 @@ static void K_MovePlayerToRespawnPoint(player_t *player)
lasersteps--;
}
if (lasersteps == 0) // Don't spawn them beyond the respawn point.
// Respawning after death: everything about the player
// is invisible
if (!player->respawn.truedeath && lasersteps == 0) // Don't spawn them beyond the respawn point.
{
mobj_t *lasermo = P_SpawnMobj(laser.x, laser.y, laser.z + (player->mo->height / 2), MT_DEZLASER);

View file

@ -361,6 +361,12 @@ waypoint_t *K_GetBestWaypointForMobj(mobj_t *const mobj)
// remember: huge radius
if (closestdist <= rad && checkdist <= rad && finishline != NULL)
{
if (!P_TraceBlockingLines(mobj, checkwaypoint->mobj))
{
// Save sight checks when all of the other checks pass, so we only do it if we have to
continue;
}
// If the mobj is touching multiple waypoints at once,
// then solve ties by taking the one closest to the finish line.
// Prevents position from flickering wildly when taking turns.
@ -375,7 +381,7 @@ waypoint_t *K_GetBestWaypointForMobj(mobj_t *const mobj)
{
if (!P_TraceBlockingLines(mobj, checkwaypoint->mobj))
{
// Save sight checks for the end, so we only do it if we have to
// Save sight checks when all of the other checks pass, so we only do it if we have to
continue;
}

View file

@ -162,6 +162,7 @@ static const struct {
{META_SPRITEINFO, "spriteinfo_t"},
{META_PIVOTLIST, "spriteframepivot_t[]"},
{META_FRAMEPIVOT, "spriteframepivot_t"},
{META_PRECIPPROPS, "precipprops_t"},
{META_TAGLIST, "taglist"},
@ -3704,10 +3705,11 @@ static int lib_kGetKartSpeed(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
boolean doboostpower = lua_optboolean(L, 2);
boolean dorubberbanding = lua_optboolean(L, 3);
//HUDSAFE
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushfixed(L, K_GetKartSpeed(player, doboostpower));
lua_pushfixed(L, K_GetKartSpeed(player, doboostpower, dorubberbanding));
return 1;
}

View file

@ -1758,6 +1758,151 @@ static int colorramp_len(lua_State *L)
return 1;
}
//////////////////
// PRECIP PROPS //
//////////////////
// Arbitrary precipprops[] table index -> precipprops_t *
static int lib_getPrecipProps(lua_State *L)
{
INT32 i;
lua_remove(L, 1);
i = luaL_checkinteger(L, 1);
if (i <= 0 || i >= MAXPRECIP)
return luaL_error(L, "precipprops[] index %d out of range (1 - %d)", i, MAXPRECIP-1);
LUA_PushUserdata(L, &precipprops[i], META_PRECIPPROPS);
return 1;
}
// Lua table full of data -> precipprops[]
static int lib_setPrecipProps(lua_State *L)
{
precipprops_t *props;
lua_remove(L, 1); // don't care about precipprops[] userdata.
{
INT32 i = luaL_checkinteger(L, 1);
if (i <= 0 || i >= MAXPRECIP)
return luaL_error(L, "precipprops[] index %d out of range (1 - %d)", i, MAXPRECIP-1);
props = &precipprops[i]; // get the precipprops to assign to.
}
luaL_checktype(L, 2, LUA_TTABLE); // check that we've been passed a table.
lua_remove(L, 1); // pop preciptype num, don't need it any more.
lua_settop(L, 1); // cut the stack here. the only thing left now is the table of data we're assigning to the precipprops.
if (hud_running)
return luaL_error(L, "Do not alter precipprops in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter precipprops in CMD building code!");
// clear the precipprops to start with, in case of missing table elements
// make sure we do not clear the name
memset(props + sizeof(props->name), 0, sizeof(precipprops_t) - sizeof(props->name));
lua_pushnil(L);
while (lua_next(L, 1)) {
lua_Integer i = 0;
const char *str = NULL;
lua_Integer value;
if (lua_isnumber(L, 2))
i = lua_tointeger(L, 2);
else
str = luaL_checkstring(L, 2);
if (i == 1 || (str && fastcmp(str, "type")))
{
value = luaL_checkinteger(L, 3);
if (value < MT_NULL || value >= NUMMOBJTYPES)
return luaL_error(L, "type number %d is invalid.", value);
props->type = luaL_checkinteger(L, 3);
}
else if (i == 2 || (str && fastcmp(str, "effects")))
{
props->effects = luaL_checkinteger(L, 3);
}
lua_pop(L, 1);
}
return 0;
}
// #precipprops -> MAXPRECIP
static int lib_precippropslen(lua_State *L)
{
lua_pushinteger(L, MAXPRECIP);
return 1;
}
// precipprops_t *, field -> number
static int precipprops_get(lua_State *L)
{
precipprops_t *props = *((precipprops_t **)luaL_checkudata(L, 1, META_PRECIPPROPS));
const char *field = luaL_checkstring(L, 2);
I_Assert(props != NULL);
I_Assert(props >= precipprops);
if (fastcmp(field, "type"))
{
lua_pushinteger(L, props->type);
}
else if (fastcmp(field,"effects"))
{
lua_pushinteger(L, props->effects);
}
else
{
CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "precipprops_t", field);
return 0;
}
return 1;
}
// precipprops_t *, field, number -> precipprops[]
static int precipprops_set(lua_State *L)
{
precipprops_t *props = *((precipprops_t **)luaL_checkudata(L, 1, META_PRECIPPROPS));
const char *field = luaL_checkstring(L, 2);
if (hud_running)
return luaL_error(L, "Do not alter precipprops in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter precipprops in CMD building code!");
I_Assert(props != NULL);
I_Assert(props >= precipprops);
if (fastcmp(field, "type"))
{
props->type = luaL_checkinteger(L, 3);
}
else if (fastcmp(field, "effects"))
{
props->effects = luaL_checkinteger(L, 3);
}
else
{
return luaL_error(L, LUA_QL("precipprops_t") " has no field named " LUA_QS, field);
}
return 0;
}
// precipprops_t * -> PRECIP_*
static int precipprops_num(lua_State *L)
{
precipprops_t *props = *((precipprops_t **)luaL_checkudata(L, 1, META_PRECIPPROPS));
I_Assert(props != NULL);
I_Assert(props >= precipprops);
lua_pushinteger(L, props - precipprops);
return 1;
}
//////////////////////////////
//
// Now push all these functions into the Lua state!
@ -1861,6 +2006,17 @@ int LUA_InfoLib(lua_State *L)
lua_setfield(L, -2, "__len");
lua_pop(L, 1);
luaL_newmetatable(L, META_PRECIPPROPS);
lua_pushcfunction(L, precipprops_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, precipprops_set);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, precipprops_num);
lua_setfield(L, -2, "__len");
lua_pop(L, 1);
lua_newuserdata(L, 0);
lua_createtable(L, 0, 2);
lua_pushcfunction(L, lib_getSprname);
@ -1961,6 +2117,19 @@ int LUA_InfoLib(lua_State *L)
lua_setmetatable(L, -2);
lua_setglobal(L, "spriteinfo");
lua_newuserdata(L, 0);
lua_createtable(L, 0, 2);
lua_pushcfunction(L, lib_getPrecipProps);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, lib_setPrecipProps);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, lib_precippropslen);
lua_setfield(L, -2, "__len");
lua_setmetatable(L, -2);
lua_setglobal(L, "precipprops");
luaL_newmetatable(L, META_LUABANKS);
lua_pushcfunction(L, lib_getluabanks);
lua_setfield(L, -2, "__index");

View file

@ -28,6 +28,7 @@ extern lua_State *gL;
#define META_SPRITEINFO "SPRITEINFO_T*"
#define META_PIVOTLIST "SPRITEFRAMEPIVOT_T[]"
#define META_FRAMEPIVOT "SPRITEFRAMEPIVOT_T*"
#define META_PRECIPPROPS "PRECIPPROPS_T*"
#define META_TAGLIST "TAGLIST"

View file

@ -446,6 +446,8 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->realtime);
else if (fastcmp(field,"laps"))
lua_pushinteger(L, plr->laps);
else if (fastcmp(field,"latestlap"))
lua_pushinteger(L, plr->latestlap);
else if (fastcmp(field,"ctfteam"))
lua_pushinteger(L, plr->ctfteam);
else if (fastcmp(field,"checkskip"))
@ -786,6 +788,8 @@ static int player_set(lua_State *L)
plr->realtime = (tic_t)luaL_checkinteger(L, 3);
else if (fastcmp(field,"laps"))
plr->laps = (UINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"latestlap"))
plr->latestlap = (UINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"ctfteam"))
plr->ctfteam = (INT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"checkskip"))

View file

@ -391,7 +391,7 @@ int LUA_PushGlobals(lua_State *L, const char *word)
lua_pushinteger(L, mapobjectscale);
return 1;
} else if (fastcmp(word,"numlaps")) {
lua_pushinteger(L, cv_numlaps.value);
lua_pushinteger(L, numlaps);
return 1;
} else if (fastcmp(word,"racecountdown")) {
lua_pushinteger(L, racecountdown);

View file

@ -72,7 +72,7 @@ static CV_PossibleValue_t masterserver_update_rate_cons_t[] = {
};
consvar_t cv_masterserver = CVAR_INIT ("masterserver", "https://ms.kartkrew.org/ms/api", CV_SAVE|CV_CALL, NULL, MasterServer_OnChange);
consvar_t cv_rendezvousserver = CVAR_INIT ("rendezvousserver", "relay.kartkrew.org", CV_SAVE|CV_CALL, NULL, RendezvousServer_OnChange);
consvar_t cv_rendezvousserver = CVAR_INIT ("holepunchserver", "relay.kartkrew.org", CV_SAVE|CV_CALL, NULL, RendezvousServer_OnChange);
consvar_t cv_servername = CVAR_INIT ("servername", "Ring Racers server", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Update_parameters);
consvar_t cv_server_contact = CVAR_INIT ("server_contact", "", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Update_parameters);
@ -436,7 +436,7 @@ void UnregisterServer(void)
static boolean
Online (void)
{
return ( serverrunning && cv_advertise.value );
return ( serverrunning && netgame && cv_advertise.value );
}
static inline void SendPingToMasterServer(void)
@ -534,7 +534,7 @@ Advertise_OnChange(void)
if (cv_advertise.value)
{
if (serverrunning)
if (serverrunning && netgame)
{
Lock_state();
{

View file

@ -0,0 +1 @@
target_sourcefile(c)

View file

@ -179,6 +179,7 @@ move_to_player (mobj_t *hyu)
mobj_t *target = hyudoro_target(hyu);
angle_t angle;
fixed_t speed;
if (!target)
return;
@ -186,8 +187,20 @@ move_to_player (mobj_t *hyu)
angle = R_PointToAngle2(
hyu->x, hyu->y, target->x, target->y);
P_InstaThrust(hyu, angle, (hyu->radius / 2) +
max(hyu->radius, K_GetSpeed(target)));
speed = (hyu->radius / 2) +
max(hyu->radius, K_GetSpeed(target));
// For first place only: cap hyudoro speed at 50%
// target player's kart speed
if (target->player && target->player->position == 1)
{
const fixed_t normalspeed =
K_GetKartSpeed(target->player, false, false) / 2;
speed = min(speed, normalspeed);
}
P_InstaThrust(hyu, angle, speed);
hyu->z = target->z; // stay level with target
hyu->angle = angle;

View file

@ -4980,7 +4980,7 @@ void A_DetonChase(mobj_t *actor)
fixed_t xyspeed, speed;
if (actor->target->player)
speed = K_GetKartSpeed(actor->tracer->player, false);
speed = K_GetKartSpeed(actor->tracer->player, false, false);
else
speed = actor->target->info->speed;
@ -13285,7 +13285,7 @@ void A_JawzChase(mobj_t *actor)
{
if (actor->tracer->player)
{
fixed_t speeddifference = abs(topspeed - min(actor->tracer->player->speed, K_GetKartSpeed(actor->tracer->player, false)));
fixed_t speeddifference = abs(topspeed - min(actor->tracer->player->speed, K_GetKartSpeed(actor->tracer->player, false, false)));
topspeed = topspeed - FixedMul(speeddifference, FRACUNIT-FixedDiv(distaway, distbarrier));
}
}
@ -13607,6 +13607,12 @@ void A_SPBChase(mobj_t *actor)
actor->lastlook = actor->tracer->player-players; // Save the player num for death scumming...
actor->tracer->player->pflags |= PF_RINGLOCK; // set ring lock
if (actor->tracer->hitlag)
{
// If the player is frozen through no fault of their own, the SPB should be too.
actor->hitlag = actor->tracer->hitlag;
}
if (!P_IsObjectOnGround(actor->tracer))
{
// In the air you have no control; basically don't hit unless you make a near complete stop
@ -13615,7 +13621,7 @@ void A_SPBChase(mobj_t *actor)
else
{
// 7/8ths max speed for Knuckles, 3/4ths max speed for min accel, exactly max speed for max accel
defspeed = FixedMul(((fracmax+1)<<FRACBITS) - easiness, K_GetKartSpeed(actor->tracer->player, false)) / fracmax;
defspeed = FixedMul(((fracmax+1)<<FRACBITS) - easiness, K_GetKartSpeed(actor->tracer->player, false, false)) / fracmax;
}
// Be fairer on conveyors
@ -13695,7 +13701,7 @@ void A_SPBChase(mobj_t *actor)
// Red speed lines for when it's gaining on its target. A tell for when you're starting to lose too much speed!
if (R_PointToDist2(0, 0, actor->momx, actor->momy) > (actor->tracer->player ? (16*actor->tracer->player->speed)/15
: (16*R_PointToDist2(0, 0, actor->tracer->momx, actor->tracer->momy))/15) // Going faster than the target
&& xyspeed > K_GetKartSpeed(actor->tracer->player, false)/4) // Don't display speedup lines at pitifully low speeds
&& xyspeed > K_GetKartSpeed(actor->tracer->player, false, false) / 4) // Don't display speedup lines at pitifully low speeds
SpawnSPBSpeedLines(actor);
return;
@ -14026,21 +14032,21 @@ void A_LightningFollowPlayer(mobj_t *actor)
if (!actor->target)
return;
if (actor->extravalue1) // Make the radius also follow the player somewhat accuratly
{
if (actor->extravalue1) // Make the radius also follow the player somewhat accuratly
{
sx = actor->target->x + FixedMul((actor->target->scale*actor->extravalue1), FINECOSINE((actor->angle)>>ANGLETOFINESHIFT));
sy = actor->target->y + FixedMul((actor->target->scale*actor->extravalue1), FINESINE((actor->angle)>>ANGLETOFINESHIFT));
P_MoveOrigin(actor, sx, sy, actor->target->z);
}
else // else just teleport to player directly
P_MoveOrigin(actor, actor->target->x, actor->target->y, actor->target->z);
K_MatchGenericExtraFlags(actor, actor->target); // copy our target for graviflip
actor->momx = actor->target->momx;
actor->momy = actor->target->momy;
actor->momz = actor->target->momz; // Give momentum since we don't teleport to our player literally every frame.
sx = actor->target->x + FixedMul((actor->target->scale*actor->extravalue1), FINECOSINE((actor->angle)>>ANGLETOFINESHIFT));
sy = actor->target->y + FixedMul((actor->target->scale*actor->extravalue1), FINESINE((actor->angle)>>ANGLETOFINESHIFT));
P_MoveOrigin(actor, sx, sy, actor->target->z);
}
else // else just teleport to player directly
{
P_MoveOrigin(actor, actor->target->x, actor->target->y, actor->target->z);
}
K_MatchGenericExtraFlags(actor, actor->target); // copy our target for graviflip
actor->momx = actor->target->momx;
actor->momy = actor->target->momy;
actor->momz = actor->target->momz; // Give momentum since we don't teleport to our player literally every frame.
}
// A_FZBoomFlash:

View file

@ -792,16 +792,11 @@ boolean P_CheckRacers(void)
boolean eliminatelast = cv_karteliminatelast.value;
boolean everyonedone = true;
boolean eliminatebots = false;
boolean griefed = false;
const boolean griefed = (spectateGriefed > 0);
// Check if all the players in the race have finished. If so, end the level.
for (i = 0; i < MAXPLAYERS; i++)
{
if (nospectategrief[i] != -1) // prevent spectate griefing
{
griefed = true;
}
if (!playeringame[i] || players[i].spectator || players[i].lives <= 0) // Not playing
{
// Y'all aren't even playing
@ -922,7 +917,7 @@ boolean P_CheckRacers(void)
// We're still playing, but no one else is, so we need to reset spectator griefing.
if (numplayersingame <= 1)
{
memset(nospectategrief, -1, sizeof (nospectategrief));
spectateGriefed = 0;
}
// Turns out we're still having a good time & playing the game, we didn't have to do anything :)
@ -1076,6 +1071,11 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
target->player->playerstate = PST_DEAD;
// respawn from where you died
target->player->respawn.pointx = target->x;
target->player->respawn.pointy = target->y;
target->player->respawn.pointz = target->z;
if (target->player == &players[consoleplayer])
{
// don't die in auto map,
@ -1403,7 +1403,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
// special behavior for ring capsules
if (target->threshold == KITEM_SUPERRING)
{
player->superring = min(player->superring + 5*target->movecount*3, UINT16_MAX);
K_AwardPlayerRings(player, 5 * target->movecount, true);
break;
}
@ -1828,7 +1828,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
boolean force = false;
INT32 laglength = 6;
INT32 kinvextend = 0;
if (objectplacing)
return false;
@ -2001,9 +2000,14 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
// Extend the invincibility if the hit was a direct hit.
if (inflictor == source && source->player->invincibilitytimer)
{
kinvextend = (source->player->invincibilitytimer)+5*TICRATE;
//CONS_Printf("extend k_invincibilitytimer for %s - old value %d new value %d\n", player_names[source->player - players], source->player->invincibilitytimer/TICRATE, kinvextend/TICRATE);
source->player->invincibilitytimer = kinvextend;
tic_t kinvextend;
if (gametype == GT_BATTLE)
kinvextend = 2*TICRATE;
else
kinvextend = 5*TICRATE;
source->player->invincibilitytimer += kinvextend;
}
K_PlayHitEmSound(source, target);

View file

@ -28,6 +28,9 @@
//#define VIEWHEIGHTS "41"
// Maximum laps per map.
#define MAX_LAPS 99
// Maximum player score.
#define MAXSCORE 99999990 // 999999990
@ -277,6 +280,7 @@ void P_RespawnSpecials(void);
mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type);
void P_CalculatePrecipFloor(precipmobj_t *mobj);
void P_RecalcPrecipInSector(sector_t *sector);
void P_PrecipitationEffects(void);

View file

@ -263,9 +263,6 @@ static boolean P_SpecialIsLinedefCrossType(line_t *ld)
{
boolean linedefcrossspecial = false;
if (P_IsLineTripWire(ld))
return true;
switch (ld->special)
{
case 2001: // Finish line
@ -301,6 +298,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
UINT16 starcolor = (spring->info->painchance % numskincolors);
fixed_t savemomx = 0;
fixed_t savemomy = 0;
statenum_t raisestate = spring->info->raisestate;
// Object was already sprung this tic
if (object->eflags & MFE_SPRUNG)
@ -412,8 +410,6 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
// Re-solidify
spring->flags |= (spring->info->flags & (MF_SPRING|MF_SPECIAL));
P_SetMobjState(spring, spring->info->raisestate);
if (object->player)
{
if (spring->flags & MF_ENEMY) // Spring shells
@ -421,6 +417,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
P_SetTarget(&spring->target, object);
}
K_TumbleInterrupt(object->player);
P_ResetPlayer(object->player);
object->player->springstars = max(vertispeed, horizspeed) / FRACUNIT / 2;
@ -444,8 +441,37 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
{
object->player->tiregrease = greasetics;
}
if (spring->type == MT_POGOSPRING)
{
if (spring->reactiontime == 0)
{
object->player->tricktime = 0; // Reset post-hitlag timer
// Setup the boost for potential upwards trick, at worse, make it your regular max speed. (boost = curr speed*1.25)
object->player->trickboostpower = max(FixedDiv(object->player->speed, K_GetKartSpeed(object->player, false, false)) - FRACUNIT, 0)*125/100;
//CONS_Printf("Got boost: %d%\n", mo->player->trickboostpower*100 / FRACUNIT);
object->player->trickpanel = 1;
object->player->pflags |= PF_TRICKDELAY;
}
else
{
raisestate = spring->info->seestate;
object->player->tumbleBounces = 1;
object->player->pflags &= ~PF_TUMBLESOUND;
object->player->tumbleHeight = 50;
P_SetPlayerMobjState(object->player->mo, S_KART_SPINOUT);
// FIXME: try to compensate tumbling gravity
object->momz = 3 * object->momz / 2;
}
spring->reactiontime++;
}
}
P_SetMobjState(spring, raisestate);
return true;
}
@ -1675,6 +1701,20 @@ static BlockItReturn_t PIT_CheckLine(line_t *ld)
{
add_spechit(ld);
}
else if (P_IsLineTripWire(ld))
{
fixed_t textop, texbottom;
P_GetMidtextureTopBottom(ld, tmx, tmy,
&textop, &texbottom);
/* The effect handling is done later but it won't
know the height values anymore. So don't even add
this line to the list unless this thing clips the
tripwire's midtexture. */
if (tmthing->z <= textop && thingtop >= texbottom)
add_spechit(ld);
}
return BMIT_CONTINUE;
}

View file

@ -485,6 +485,83 @@ void P_CameraLineOpening(line_t *linedef)
}
}
boolean
P_GetMidtextureTopBottom
( line_t * linedef,
fixed_t x,
fixed_t y,
fixed_t * return_top,
fixed_t * return_bottom)
{
side_t *side = &sides[linedef->sidenum[0]];
fixed_t textop, texbottom, texheight;
INT32 texnum = R_GetTextureNum(side->midtexture); // make sure the texture is actually valid
sector_t *front = linedef->frontsector;
sector_t *back = linedef->backsector;
fixed_t z;
if (!texnum)
return false;
textop = P_GetSectorCeilingZAt(front, x, y);
texbottom = P_GetSectorFloorZAt(front, x, y);
if (back)
{
z = P_GetSectorCeilingZAt(back, x, y);
if (z < textop)
textop = z;
z = P_GetSectorFloorZAt(back, x, y);
if (z > texbottom)
texbottom = z;
}
// Get the midtexture's height
texheight = textures[texnum]->height << FRACBITS;
// Set texbottom and textop to the Z coordinates of the texture's boundaries
#if 0
// don't remove this code unless solid midtextures
// on non-solid polyobjects should NEVER happen in the future
if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) {
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
texbottom = back->floorheight + side->rowoffset;
textop = back->ceilingheight + side->rowoffset;
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
texbottom = back->floorheight + side->rowoffset;
textop = texbottom + texheight*(side->repeatcnt+1);
} else {
textop = back->ceilingheight + side->rowoffset;
texbottom = textop - texheight*(side->repeatcnt+1);
}
} else
#endif
{
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
texbottom += side->rowoffset;
textop += side->rowoffset;
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
texbottom += side->rowoffset;
textop = texbottom + texheight*(side->repeatcnt+1);
} else {
textop += side->rowoffset;
texbottom = textop - texheight*(side->repeatcnt+1);
}
}
if (return_top)
*return_top = textop;
if (return_bottom)
*return_bottom = texbottom;
return true;
}
void P_LineOpening(line_t *linedef, mobj_t *mobj)
{
enum { FRONT, BACK };
@ -596,45 +673,11 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
if ((linedef->flags & ML_EFFECT4 || (mobj->player && P_IsLineTripWire(linedef) && !K_TripwirePass(mobj->player)))
&& !linedef->polyobj // don't do anything for polyobjects! ...for now
) {
side_t *side = &sides[linedef->sidenum[0]];
fixed_t textop, texbottom, texheight;
fixed_t textop, texbottom;
fixed_t texmid, delta1, delta2;
INT32 texnum = R_GetTextureNum(side->midtexture); // make sure the texture is actually valid
if (texnum) {
// Get the midtexture's height
texheight = textures[texnum]->height << FRACBITS;
// Set texbottom and textop to the Z coordinates of the texture's boundaries
#if 0
// don't remove this code unless solid midtextures
// on non-solid polyobjects should NEVER happen in the future
if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) {
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
texbottom = back->floorheight + side->rowoffset;
textop = back->ceilingheight + side->rowoffset;
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
texbottom = back->floorheight + side->rowoffset;
textop = texbottom + texheight*(side->repeatcnt+1);
} else {
textop = back->ceilingheight + side->rowoffset;
texbottom = textop - texheight*(side->repeatcnt+1);
}
} else
#endif
{
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
texbottom = openbottom + side->rowoffset;
textop = opentop + side->rowoffset;
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
texbottom = openbottom + side->rowoffset;
textop = texbottom + texheight*(side->repeatcnt+1);
} else {
textop = opentop + side->rowoffset;
texbottom = textop - texheight*(side->repeatcnt+1);
}
}
if (P_GetMidtextureTopBottom(linedef, cross.x, cross.y, &textop, &texbottom))
{
texmid = texbottom+(textop-texbottom)/2;
delta1 = abs(mobj->z - texmid);

View file

@ -56,6 +56,8 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing, fixed_t x,fixed_t y);
boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y);
void P_HitSpecialLines(mobj_t *thing, fixed_t x, fixed_t y, fixed_t momx, fixed_t momy);
boolean P_GetMidtextureTopBottom(line_t *linedef, fixed_t x, fixed_t y, fixed_t *return_top, fixed_t *return_bottom);
extern fixed_t opentop, openbottom, openrange, lowfloor, highceiling;
extern pslope_t *opentopslope, *openbottomslope;
extern ffloor_t *openfloorrover, *openceilingrover;

View file

@ -88,6 +88,15 @@ void P_AddCachedAction(mobj_t *mobj, INT32 statenum)
actioncachehead.prev = newaction;
}
static inline INT32 randomframe (mobj_t *mobj, INT32 n)
{
// Only mobj thinkers should use synced RNG
if (mobj->thinker.function.acp1 == (actionf_p1)P_MobjThinker)
return P_RandomKey(n);
else
return M_RandomKey(n);
}
//
// P_SetupStateAnimation
//
@ -118,8 +127,8 @@ static void P_SetupStateAnimation(mobj_t *mobj, state_t *st)
}
else if (st->frame & FF_RANDOMANIM)
{
mobj->frame += P_RandomKey(animlength + 1); // Random starting frame
mobj->anim_duration -= P_RandomKey(st->var2); // Random duration for first frame
mobj->frame += randomframe(mobj, animlength + 1); // Random starting frame
mobj->anim_duration -= randomframe(mobj, st->var2); // Random duration for first frame
}
}
@ -1121,7 +1130,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
if (mo->player->tumbleBounces > 0)
{
gravityadd = (5*gravityadd)/2;
gravityadd = FixedMul(TUMBLEGRAVITY, gravityadd);
}
}
else
@ -2999,7 +3008,7 @@ boolean P_CanRunOnWater(player_t *player, ffloor_t *rover)
clip > -(player->mo->height / 2) &&
span > player->mo->height &&
player->speed / 5 > abs(player->mo->momz) &&
player->speed > K_GetKartSpeed(player, false) &&
player->speed > K_GetKartSpeed(player, false, false) &&
K_WaterRun(player) &&
(rover->flags & FF_SWIMMABLE);
}
@ -3753,19 +3762,25 @@ animonly:
P_CyclePlayerMobjState(mobj);
}
static void CalculatePrecipFloor(precipmobj_t *mobj)
void P_CalculatePrecipFloor(precipmobj_t *mobj)
{
// recalculate floorz each time
const sector_t *mobjsecsubsec;
boolean setWater = false;
if (mobj && mobj->subsector && mobj->subsector->sector)
mobjsecsubsec = mobj->subsector->sector;
else
return;
mobj->precipflags &= ~PCF_INVISIBLE;
mobj->floorz = P_GetSectorFloorZAt(mobjsecsubsec, mobj->x, mobj->y);
mobj->ceilingz = P_GetSectorCeilingZAt(mobjsecsubsec, mobj->x, mobj->y);
if (mobjsecsubsec->ffloors)
{
ffloor_t *rover;
fixed_t topheight;
fixed_t height;
for (rover = mobjsecsubsec->ffloors; rover; rover = rover->next)
{
@ -3773,14 +3788,44 @@ static void CalculatePrecipFloor(precipmobj_t *mobj)
if (!(rover->flags & FF_EXISTS))
continue;
if (!(rover->flags & FF_BLOCKOTHERS) && !(rover->flags & FF_SWIMMABLE))
continue;
if (precipprops[curWeather].effects & PRECIPFX_WATERPARTICLES)
{
if (!(rover->flags & FF_SWIMMABLE))
continue;
topheight = P_GetFFloorTopZAt(rover, mobj->x, mobj->y);
if (topheight > mobj->floorz)
mobj->floorz = topheight;
if (setWater == false)
{
mobj->ceilingz = P_GetFFloorTopZAt(rover, mobj->x, mobj->y);
mobj->floorz = P_GetFFloorBottomZAt(rover, mobj->x, mobj->y);
setWater = true;
}
else
{
height = P_GetFFloorTopZAt(rover, mobj->x, mobj->y);
if (height > mobj->ceilingz)
mobj->ceilingz = height;
height = P_GetFFloorBottomZAt(rover, mobj->x, mobj->y);
if (height < mobj->floorz)
mobj->floorz = height;
}
}
else
{
if (!(rover->flags & FF_BLOCKOTHERS) && !(rover->flags & FF_SWIMMABLE))
continue;
height = P_GetFFloorTopZAt(rover, mobj->x, mobj->y);
if (height > mobj->floorz)
mobj->floorz = height;
}
}
}
if ((precipprops[curWeather].effects & PRECIPFX_WATERPARTICLES) && setWater == false)
{
mobj->precipflags |= PCF_INVISIBLE;
}
}
void P_RecalcPrecipInSector(sector_t *sector)
@ -3793,7 +3838,7 @@ void P_RecalcPrecipInSector(sector_t *sector)
sector->moved = true; // Recalc lighting and things too, maybe
for (psecnode = sector->touching_preciplist; psecnode; psecnode = psecnode->m_thinglist_next)
CalculatePrecipFloor(psecnode->m_thing);
P_CalculatePrecipFloor(psecnode->m_thing);
}
//
@ -3805,11 +3850,12 @@ void P_NullPrecipThinker(precipmobj_t *mobj)
{
//(void)mobj;
mobj->precipflags &= ~PCF_THUNK;
R_ResetPrecipitationMobjInterpolationState(mobj);
}
void P_PrecipThinker(precipmobj_t *mobj)
{
R_ResetPrecipitationMobjInterpolationState(mobj);
boolean flip = (mobj->precipflags & PCF_FLIP);
P_CycleStateAnimation((mobj_t *)mobj);
@ -3817,9 +3863,10 @@ void P_PrecipThinker(precipmobj_t *mobj)
{
// Reset to ceiling!
P_SetPrecipMobjState(mobj, mobj->info->spawnstate);
mobj->z = mobj->ceilingz;
mobj->momz = mobj->info->speed;
mobj->z = (flip) ? (mobj->floorz) : (mobj->ceilingz);
mobj->momz = FixedMul(-mobj->info->speed, mapobjectscale);
mobj->precipflags &= ~PCF_SPLASH;
R_ResetPrecipitationMobjInterpolationState(mobj);
}
if (mobj->tics != -1)
@ -3851,18 +3898,20 @@ void P_PrecipThinker(precipmobj_t *mobj)
if (mobj->precipflags & PCF_SPLASH)
return;
mobj->z += mobj->momz;
// adjust height
if ((mobj->z += mobj->momz) <= mobj->floorz)
if ((flip) ? (mobj->z >= mobj->ceilingz) : (mobj->z <= mobj->floorz))
{
if ((mobj->info->deathstate == S_NULL) || (mobj->precipflags & PCF_PIT)) // no splashes on sky or bottomless pits
{
mobj->z = mobj->ceilingz;
mobj->z = (flip) ? (mobj->floorz) : (mobj->ceilingz);
R_ResetPrecipitationMobjInterpolationState(mobj);
}
else
{
P_SetPrecipMobjState(mobj, mobj->info->deathstate);
mobj->z = mobj->floorz;
mobj->z = (flip) ? (mobj->ceilingz) : (mobj->floorz);
mobj->precipflags |= PCF_SPLASH;
R_ResetPrecipitationMobjInterpolationState(mobj);
}
@ -9716,6 +9765,7 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
case MT_BLUESPHERE:
case MT_EMERALD:
case MT_ITEMCAPSULE:
case MT_POGOSPRING:
thing->shadowscale = FRACUNIT/2;
break;
case MT_DRIFTCLIP:
@ -9966,6 +10016,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
mobj->color = BALLOONCOLORS[P_RandomKey(sizeof(BALLOONCOLORS))];
}
break;
case MT_POGOSPRING:
P_SetScale(mobj, (mobj->destscale = 3 * mobj->destscale / 2));
break;
case MT_KART_LEFTOVER:
mobj->color = SKINCOLOR_RED;
break;
@ -10334,8 +10387,8 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype
{
const mobjinfo_t *info = &mobjinfo[type];
state_t *st;
fixed_t start_z = INT32_MIN;
precipmobj_t *mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
fixed_t starting_floorz;
mobj->type = type;
mobj->info = info;
@ -10357,26 +10410,43 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype
// set subsector and/or block links
P_SetPrecipitationThingPosition(mobj);
mobj->floorz = starting_floorz = P_GetSectorFloorZAt (mobj->subsector->sector, x, y);
mobj->ceilingz = P_GetSectorCeilingZAt(mobj->subsector->sector, x, y);
mobj->floorz = P_GetSectorFloorZAt (mobj->subsector->sector, x, y);
mobj->ceilingz = P_GetSectorCeilingZAt(mobj->subsector->sector, x, y);
mobj->floorrover = NULL;
mobj->ceilingrover = NULL;
mobj->z = z;
mobj->momz = info->speed;
mobj->momz = FixedMul(-info->speed, mapobjectscale);
if (info->speed < 0)
{
mobj->precipflags |= PCF_FLIP;
}
start_z = mobj->floorz;
mobj->thinker.function.acp1 = (actionf_p1)P_NullPrecipThinker;
P_AddThinker(THINK_PRECIP, &mobj->thinker);
CalculatePrecipFloor(mobj);
P_CalculatePrecipFloor(mobj);
if (mobj->floorz != starting_floorz)
mobj->precipflags |= PCF_FOF;
else if (GETSECSPECIAL(mobj->subsector->sector->special, 1) == 7
|| GETSECSPECIAL(mobj->subsector->sector->special, 1) == 6
|| mobj->subsector->sector->floorpic == skyflatnum)
mobj->precipflags |= PCF_PIT;
if (mobj->floorz != start_z)
{
; //mobj->precipflags |= PCF_FOF;
}
else
{
INT32 special = GETSECSPECIAL(mobj->subsector->sector->special, 1);
boolean sFlag = (mobj->precipflags & PCF_FLIP) ? (mobj->subsector->sector->flags & SF_FLIPSPECIAL_CEILING) : (mobj->subsector->sector->flags & SF_FLIPSPECIAL_FLOOR);
boolean pitFloor = ((special == 6 || special == 7) && sFlag);
boolean skyFloor = (mobj->precipflags & PCF_FLIP) ? (mobj->subsector->sector->ceilingpic == skyflatnum) : (mobj->subsector->sector->floorpic == skyflatnum);
if (pitFloor || skyFloor)
{
mobj->precipflags |= PCF_PIT;
}
}
R_ResetPrecipitationMobjInterpolationState(mobj);
@ -10578,16 +10648,121 @@ static CV_PossibleValue_t respawnitemtime_cons_t[] = {{1, "MIN"}, {300, "MAX"},
consvar_t cv_itemrespawntime = CVAR_INIT ("respawnitemtime", "2", CV_NETVAR|CV_CHEAT, respawnitemtime_cons_t, NULL);
consvar_t cv_itemrespawn = CVAR_INIT ("respawnitem", "On", CV_NETVAR, CV_OnOff, NULL);
void P_SpawnPrecipitation(void)
static void P_SpawnPrecipitationAt(fixed_t basex, fixed_t basey)
{
INT32 i, j, k;
mobjtype_t type = precipprops[curWeather].type;
UINT8 randomstates = (UINT8)mobjinfo[type].damage;
fixed_t basex, basey, x, y, z, height;
INT32 j, k;
const mobjtype_t type = precipprops[curWeather].type;
const UINT8 randomstates = (UINT8)mobjinfo[type].damage;
const boolean flip = (mobjinfo[type].speed < 0);
fixed_t i, x, y, z, height;
UINT16 numparticles = 0;
boolean condition = false;
subsector_t *precipsector = NULL;
precipmobj_t *rainmo = NULL;
if (dedicated || !cv_drawdist_precip.value || curWeather == PRECIP_NONE) // SRB2Kart
// If mobjscale < FRACUNIT, each blockmap cell covers
// more area so spawn more precipitation in that area.
for (i = 0; i < FRACUNIT; i += mapobjectscale)
{
x = basex + ((M_RandomKey(MAPBLOCKUNITS << 3) << FRACBITS) >> 3);
y = basey + ((M_RandomKey(MAPBLOCKUNITS << 3) << FRACBITS) >> 3);
precipsector = R_PointInSubsectorOrNull(x, y);
// No sector? Stop wasting time,
// move on to the next entry in the blockmap
if (!precipsector)
continue;
// Not in a sector with visible sky?
if (precipprops[curWeather].effects & PRECIPFX_WATERPARTICLES)
{
condition = false;
if (precipsector->sector->ffloors)
{
ffloor_t *rover;
for (rover = precipsector->sector->ffloors; rover; rover = rover->next)
{
if (!(rover->flags & FF_EXISTS))
continue;
if (!(rover->flags & FF_SWIMMABLE))
continue;
condition = true;
break;
}
}
}
else
{
condition = (precipsector->sector->ceilingpic == skyflatnum);
}
if (precipsector->sector->flags & SF_INVERTPRECIP)
{
condition = !condition;
}
if (!condition)
{
continue;
}
height = precipsector->sector->ceilingheight - precipsector->sector->floorheight;
height = FixedDiv(height, mapobjectscale);
// Exists, but is too small for reasonable precipitation.
if (height < 64<<FRACBITS)
continue;
// Hack around a quirk of this entire system, where taller sectors look like they get less precipitation.
numparticles = 1 + (height / (MAPBLOCKUNITS<<4<<FRACBITS));
// Don't set z properly yet...
z = (flip) ? (precipsector->sector->floorheight) : (precipsector->sector->ceilingheight);
for (j = 0; j < numparticles; j++)
{
rainmo = P_SpawnPrecipMobj(x, y, z, type);
if (randomstates > 0)
{
UINT8 mrand = M_RandomByte();
UINT8 threshold = UINT8_MAX / (randomstates + 1);
statenum_t st = mobjinfo[type].spawnstate;
for (k = 0; k < randomstates; k++)
{
if (mrand < (threshold * (k+1)))
{
P_SetPrecipMobjState(rainmo, st+k+1);
break;
}
}
}
// Randomly assign a height, now that floorz is set.
rainmo->z = M_RandomRange(rainmo->floorz >> FRACBITS, rainmo->ceilingz >> FRACBITS) << FRACBITS;
}
}
}
void P_SpawnPrecipitation(void)
{
INT32 i;
const mobjtype_t type = precipprops[curWeather].type;
fixed_t basex, basey;
if (dedicated || !cv_drawdist_precip.value || type == MT_NULL)
return;
// Use the blockmap to narrow down our placing patterns
@ -10596,59 +10771,7 @@ void P_SpawnPrecipitation(void)
basex = bmaporgx + (i % bmapwidth) * MAPBLOCKSIZE;
basey = bmaporgy + (i / bmapwidth) * MAPBLOCKSIZE;
{
UINT16 numparticles = 0;
x = basex + ((M_RandomKey(MAPBLOCKUNITS<<3)<<FRACBITS)>>3);
y = basey + ((M_RandomKey(MAPBLOCKUNITS<<3)<<FRACBITS)>>3);
precipsector = R_PointInSubsectorOrNull(x, y);
// No sector? Stop wasting time,
// move on to the next entry in the blockmap
if (!precipsector)
continue;
// Not in a sector with visible sky?
if (precipsector->sector->ceilingpic != skyflatnum)
continue;
height = precipsector->sector->ceilingheight - precipsector->sector->floorheight;
// Exists, but is too small for reasonable precipitation.
if (height < 64<<FRACBITS)
continue;
// Hack around a quirk of this entire system, where taller sectors look like they get less precipitation.
numparticles = 1 + (height / (MAPBLOCKUNITS<<4<<FRACBITS));
// Don't set z properly yet...
z = precipsector->sector->ceilingheight;
for (j = 0; j < numparticles; j++)
{
rainmo = P_SpawnPrecipMobj(x, y, z, type);
if (randomstates > 0)
{
UINT8 mrand = M_RandomByte();
UINT8 threshold = UINT8_MAX / (randomstates + 1);
statenum_t st = mobjinfo[type].spawnstate;
for (k = 0; k < randomstates; k++)
{
if (mrand < (threshold * (k+1)))
{
P_SetPrecipMobjState(rainmo, st+k+1);
break;
}
}
}
// Randomly assign a height, now that floorz is set.
rainmo->z = M_RandomRange(rainmo->floorz>>FRACBITS, rainmo->ceilingz>>FRACBITS)<<FRACBITS;
}
}
P_SpawnPrecipitationAt(basex, basey);
}
}
@ -10878,16 +11001,20 @@ void P_RespawnSpecials(void)
else
{
if (pcount == 1) // No respawn when alone
{
return;
}
else if (pcount > 1)
{
time = (120 - ((pcount-2) * 10)) * TICRATE;
time = (120 - ((pcount-2) * 20)) * TICRATE;
// If the map is longer or shorter than 3 laps, then adjust ring respawn to account for this.
// 5 lap courses would have more retreaded ground, while 2 lap courses would have less.
if ((mapheaderinfo[gamemap-1]->numlaps != 3)
&& !(mapheaderinfo[gamemap-1]->levelflags & LF_SECTIONRACE))
&& !(mapheaderinfo[gamemap-1]->levelflags & LF_SECTIONRACE))
{
time = (time * 3) / max(1, mapheaderinfo[gamemap-1]->numlaps);
}
if (time < 10*TICRATE)
{
@ -11243,8 +11370,6 @@ void P_MovePlayerToStarpost(INT32 playernum)
mobj_t *mobj = p->mo;
I_Assert(mobj != NULL);
K_DoIngameRespawn(p);
P_UnsetThingPosition(mobj);
mobj->x = p->respawn.pointx;
mobj->y = p->respawn.pointy;
@ -11286,6 +11411,11 @@ void P_MovePlayerToStarpost(INT32 playernum)
else
p->drawangle = mobj->angle; // default to the camera angle
K_DoIngameRespawn(p);
p->respawn.truedeath = true;
mobj->renderflags |= RF_DONTDRAW;
P_AfterPlayerSpawn(playernum);
}
@ -13482,9 +13612,6 @@ mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zo
newmobj->old_z2 = mobj->old_z2 + zofs;
}
newmobj->destscale = mobj->destscale;
P_SetScale(newmobj, mobj->scale);
newmobj->old_x2 = mobj->old_x2 + xofs;
newmobj->old_y2 = mobj->old_y2 + yofs;
newmobj->old_x = mobj->old_x + xofs;

View file

@ -262,12 +262,11 @@ typedef enum
// PRECIPITATION flags ?! ?! ?!
//
typedef enum {
PCF_INVISIBLE = 1, // Don't draw.
PCF_PIT = 1<<1, // Above pit.
PCF_FOF = 1<<2, // Above FOF.
PCF_MOVINGFOF = 1<<3, // Above MOVING FOF (this means we need to keep floorz up to date...)
PCF_SPLASH = 1<<4, // Splashed on the ground, return to the ceiling after the animation's over
PCF_THUNK = 1<<5, // Ran the thinker this tic.
PCF_THUNK = 1, // Ran the thinker this tic.
PCF_SPLASH = 1<<1, // Splashed on the ground, return to the ceiling after the animation's over
PCF_INVISIBLE = 1<<2, // Don't draw.
PCF_PIT = 1<<3, // Above pit.
PCF_FLIP = 1<<4, // Spawning from floor, moving upwards.
} precipflag_t;
// Map Object definition.
@ -462,6 +461,8 @@ typedef struct precipmobj_s
fixed_t ceilingz; // Nearest ceiling above.
struct ffloor_s *floorrover; // FOF referred by floorz
struct ffloor_s *ceilingrover; // FOF referred by ceilingz
fixed_t floordrop;
fixed_t ceilingdrop;
// For movement checking.
fixed_t radius; // Fixed at 2*FRACUNIT
@ -473,7 +474,7 @@ typedef struct precipmobj_s
INT32 tics; // state tic counter
state_t *state;
INT32 flags; // flags from mobjinfo tables
UINT32 flags; // flags from mobjinfo tables
} precipmobj_t;
typedef struct actioncache_s

View file

@ -106,6 +106,7 @@ static void P_NetArchivePlayers(void)
{
WRITEINT16(save_p, clientpowerlevels[i][j]);
}
WRITEINT16(save_p, clientPowerAdd[i]);
if (!playeringame[i])
continue;
@ -167,6 +168,7 @@ static void P_NetArchivePlayers(void)
WRITEINT16(save_p, players[i].totalring);
WRITEUINT32(save_p, players[i].realtime);
WRITEUINT8(save_p, players[i].laps);
WRITEUINT8(save_p, players[i].latestlap);
WRITEINT32(save_p, players[i].starpostnum);
WRITEUINT8(save_p, players[i].ctfteam);
@ -373,11 +375,14 @@ static void P_NetArchivePlayers(void)
WRITEUINT32(save_p, players[i].respawn.airtimer);
WRITEUINT32(save_p, players[i].respawn.distanceleft);
WRITEUINT32(save_p, players[i].respawn.dropdash);
WRITEUINT8(save_p, players[i].respawn.truedeath);
// botvars_t
WRITEUINT8(save_p, players[i].botvars.difficulty);
WRITEUINT8(save_p, players[i].botvars.diffincrease);
WRITEUINT8(save_p, players[i].botvars.rival);
WRITEFIXED(save_p, players[i].botvars.rubberband);
WRITEUINT16(save_p, players[i].botvars.controller);
WRITEUINT32(save_p, players[i].botvars.itemdelay);
WRITEUINT32(save_p, players[i].botvars.itemconfirm);
WRITESINT8(save_p, players[i].botvars.turnconfirm);
@ -401,6 +406,7 @@ static void P_NetUnArchivePlayers(void)
{
clientpowerlevels[i][j] = READINT16(save_p);
}
clientPowerAdd[i] = READINT16(save_p);
// Do NOT memset player struct to 0
// other areas may initialize data elsewhere
@ -463,6 +469,7 @@ static void P_NetUnArchivePlayers(void)
players[i].totalring = READINT16(save_p); // Total number of rings obtained for GP
players[i].realtime = READUINT32(save_p); // integer replacement for leveltime
players[i].laps = READUINT8(save_p); // Number of laps (optional)
players[i].latestlap = READUINT8(save_p);
players[i].starpostnum = READINT32(save_p);
players[i].ctfteam = READUINT8(save_p); // 1 == Red, 2 == Blue
@ -652,11 +659,14 @@ static void P_NetUnArchivePlayers(void)
players[i].respawn.airtimer = READUINT32(save_p);
players[i].respawn.distanceleft = READUINT32(save_p);
players[i].respawn.dropdash = READUINT32(save_p);
players[i].respawn.truedeath = READUINT8(save_p);
// botvars_t
players[i].botvars.difficulty = READUINT8(save_p);
players[i].botvars.diffincrease = READUINT8(save_p);
players[i].botvars.rival = (boolean)READUINT8(save_p);
players[i].botvars.rubberband = READFIXED(save_p);
players[i].botvars.controller = READUINT16(save_p);
players[i].botvars.itemdelay = READUINT32(save_p);
players[i].botvars.itemconfirm = READUINT32(save_p);
players[i].botvars.turnconfirm = READSINT8(save_p);
@ -3137,6 +3147,8 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
slope->normal.x = READFIXED(save_p);
slope->normal.y = READFIXED(save_p);
slope->normal.z = READFIXED(save_p);
P_UpdateSlopeLightOffset(slope);
}
if (diff2 & MD2_HITLAG)
{
@ -4487,6 +4499,7 @@ static void P_NetArchiveMisc(boolean resending)
WRITEUINT8(save_p, battlecapsules);
WRITEUINT8(save_p, gamespeed);
WRITEUINT8(save_p, numlaps);
WRITEUINT8(save_p, franticitems);
WRITEUINT8(save_p, comeback);
@ -4507,8 +4520,7 @@ static void P_NetArchiveMisc(boolean resending)
WRITEUINT32(save_p, indirectitemcooldown);
WRITEUINT32(save_p, mapreset);
for (i = 0; i < MAXPLAYERS; i++)
WRITEINT16(save_p, nospectategrief[i]);
WRITEUINT8(save_p, spectateGriefed);
WRITEUINT8(save_p, thwompsactive);
WRITEUINT8(save_p, lastLowestLap);
@ -4636,6 +4648,7 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading)
battlecapsules = (boolean)READUINT8(save_p);
gamespeed = READUINT8(save_p);
numlaps = READUINT8(save_p);
franticitems = (boolean)READUINT8(save_p);
comeback = (boolean)READUINT8(save_p);
@ -4656,8 +4669,7 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading)
indirectitemcooldown = READUINT32(save_p);
mapreset = READUINT32(save_p);
for (i = 0; i < MAXPLAYERS; i++)
nospectategrief[i] = READINT16(save_p);
spectateGriefed = READUINT8(save_p);
thwompsactive = (boolean)READUINT8(save_p);
lastLowestLap = READUINT8(save_p);

View file

@ -391,7 +391,7 @@ static void P_ClearSingleMapHeaderInfo(INT16 i)
mapheaderinfo[num]->muspostbossfadein = 0;
mapheaderinfo[num]->musforcereset = -1;
mapheaderinfo[num]->forcecharacter[0] = '\0';
mapheaderinfo[num]->weather = 0;
mapheaderinfo[num]->weather = PRECIP_NONE;
snprintf(mapheaderinfo[num]->skytexture, 5, "SKY1");
mapheaderinfo[num]->skytexture[4] = 0;
mapheaderinfo[num]->skybox_scalex = 16;
@ -414,6 +414,9 @@ static void P_ClearSingleMapHeaderInfo(INT16 i)
mapheaderinfo[num]->menuflags = 0;
mapheaderinfo[num]->mobj_scale = FRACUNIT;
mapheaderinfo[num]->default_waypoint_radius = 0;
mapheaderinfo[num]->light_contrast = 16;
mapheaderinfo[num]->use_light_angle = false;
mapheaderinfo[num]->light_angle = 0;
#if 1 // equivalent to "FlickyList = DEMO"
P_SetDemoFlickies(num);
#else // equivalent to "FlickyList = NONE"
@ -2323,13 +2326,25 @@ static inline float P_SegLengthFloat(seg_t *seg)
*/
void P_UpdateSegLightOffset(seg_t *li)
{
const UINT8 contrast = 16;
const UINT8 contrast = maplighting.contrast;
const fixed_t contrastFixed = ((fixed_t)contrast) * FRACUNIT;
fixed_t light = FRACUNIT;
fixed_t extralight = 0;
extralight = -((fixed_t)contrast*FRACUNIT) +
FixedDiv(AngleFixed(R_PointToAngle2(0, 0,
abs(li->v1->x - li->v2->x),
abs(li->v1->y - li->v2->y))), 90*FRACUNIT) * ((fixed_t)contrast * 2);
if (maplighting.directional == true)
{
angle_t liAngle = R_PointToAngle2(0, 0, (li->v1->x - li->v2->x), (li->v1->y - li->v2->y)) - ANGLE_90;
light = FixedMul(FINECOSINE(liAngle >> ANGLETOFINESHIFT), FINECOSINE(maplighting.angle >> ANGLETOFINESHIFT))
+ FixedMul(FINESINE(liAngle >> ANGLETOFINESHIFT), FINESINE(maplighting.angle >> ANGLETOFINESHIFT));
light = (light + FRACUNIT) / 2;
}
else
{
light = FixedDiv(R_PointToAngle2(0, 0, abs(li->v1->x - li->v2->x), abs(li->v1->y - li->v2->y)), ANGLE_90);
}
extralight = -contrastFixed + FixedMul(light, contrastFixed * 2);
// Between -2 and 2 for software, -16 and 16 for hardware
li->lightOffset = FixedFloor((extralight / 8) + (FRACUNIT / 2)) / FRACUNIT;
@ -2338,6 +2353,20 @@ void P_UpdateSegLightOffset(seg_t *li)
#endif
}
boolean P_ApplyLightOffset(UINT8 baselightnum)
{
// Don't apply light offsets at full bright or full dark.
// Is in steps of light num .
return (baselightnum < LIGHTLEVELS-1 && baselightnum > 0);
}
boolean P_ApplyLightOffsetFine(UINT8 baselightlevel)
{
// Don't apply light offsets at full bright or full dark.
// Uses exact light levels for more smoothness.
return (baselightlevel < 255 && baselightlevel > 0);
}
static void P_InitializeSeg(seg_t *seg)
{
if (seg->linedef)
@ -4035,25 +4064,37 @@ static void P_InitPlayers(void)
static void P_InitGametype(void)
{
spectateGriefed = 0;
K_CashInPowerLevels(); // Pushes power level changes even if intermission was skipped
P_InitPlayers();
if (modeattacking && !demo.playback)
P_LoadRecordGhosts();
if ((gametyperules & GTR_CIRCUIT) && server)
numlaps = 0;
if (gametyperules & GTR_CIRCUIT)
{
if ((netgame || multiplayer) && cv_basenumlaps.value
if ((netgame || multiplayer) && cv_numlaps.value
&& (!(mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE)
|| (mapheaderinfo[gamemap - 1]->numlaps > cv_basenumlaps.value)))
|| (mapheaderinfo[gamemap - 1]->numlaps > cv_numlaps.value)))
{
CV_StealthSetValue(&cv_numlaps, cv_basenumlaps.value);
numlaps = cv_numlaps.value;
}
else
{
CV_StealthSetValue(&cv_numlaps, mapheaderinfo[gamemap - 1]->numlaps);
numlaps = mapheaderinfo[gamemap - 1]->numlaps;
}
}
wantedcalcdelay = wantedfrequency*2;
indirectitemcooldown = 0;
mapreset = 0;
thwompsactive = false;
lastLowestLap = 0;
spbplace = -1;
// Start recording replay in multiplayer with a temp filename
//@TODO I'd like to fix dedis crashing when recording replays for the future too...
if (!demo.playback && multiplayer && !dedicated)
@ -4089,6 +4130,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
// Map header should always be in place at this point
INT32 i, ranspecialwipe = 0;
sector_t *ss;
levelloading = true;
// This is needed. Don't touch.
@ -4341,8 +4383,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
P_SpawnSlopes(fromnetsave);
P_SpawnSpecialsAfterSlopes();
P_SpawnMapThings(!fromnetsave);
for (numcoopstarts = 0; numcoopstarts < MAXPLAYERS; numcoopstarts++)
@ -4404,17 +4444,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
K_InitDirector();
}
wantedcalcdelay = wantedfrequency*2;
indirectitemcooldown = 0;
mapreset = 0;
for (i = 0; i < MAXPLAYERS; i++)
nospectategrief[i] = -1;
thwompsactive = false;
lastLowestLap = 0;
spbplace = -1;
// clear special respawning que
iquehead = iquetail = 0;

View file

@ -113,6 +113,8 @@ void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 num);
void P_LoadMusicsRange(UINT16 wadnum, UINT16 first, UINT16 num);
void P_WriteThings(void);
void P_UpdateSegLightOffset(seg_t *li);
boolean P_ApplyLightOffset(UINT8 baselightnum);
boolean P_ApplyLightOffsetFine(UINT8 baselightlevel);
size_t P_PrecacheLevelFlats(void);
void P_AllocMapHeader(INT16 i);

View file

@ -578,6 +578,15 @@ static boolean P_CrossBlockingSubsector(size_t num, register traceblocking_t *tb
// This line will always block us
return false;
}
if (tb->compareThing->player != NULL)
{
if (P_IsLineTripWire(line) == true && K_TripwirePass(tb->compareThing->player) == false)
{
// Can't go through trip wire.
return false;
}
}
}
// passed the subsector ok
@ -728,7 +737,18 @@ static boolean P_CrossBotTraversalSubsector(size_t num, register traceblocking_t
return false;
}
if (tb->compareThing->player != NULL)
{
if (P_IsLineTripWire(line) == true && K_TripwirePass(tb->compareThing->player) == false)
{
// Can't go through trip wire.
return false;
}
}
// set openrange, opentop, openbottom
tmx = tb->compareThing->x;
tmy = tb->compareThing->y;
P_LineOpening(line, tb->compareThing);
maxstep = P_GetThingStepUp(tb->compareThing);
@ -740,10 +760,13 @@ static boolean P_CrossBotTraversalSubsector(size_t num, register traceblocking_t
return false;
}
// Treat damage sectors like walls
if (tb->compareThing->player != NULL)
{
boolean alreadyHates = K_BotHatesThisSector(tb->compareThing->player, tb->compareThing->subsector->sector, tb->compareThing->x, tb->compareThing->y);
// Treat damage sectors like walls
boolean alreadyHates = K_BotHatesThisSector(
tb->compareThing->player, tb->compareThing->subsector->sector,
tb->compareThing->x, tb->compareThing->y
);
if (alreadyHates == false)
{
@ -753,18 +776,16 @@ static boolean P_CrossBotTraversalSubsector(size_t num, register traceblocking_t
P_ClosestPointOnLine(tb->compareThing->x, tb->compareThing->y, line, &pos);
lineside = P_PointOnLineSide(tb->compareThing->x, tb->compareThing->y, line);
if (K_BotHatesThisSector(tb->compareThing->player, ((lineside == 1) ? line->frontsector : line->backsector), pos.x, pos.y))
if (K_BotHatesThisSector(
tb->compareThing->player,
((lineside == 1) ? line->frontsector : line->backsector),
pos.x, pos.y
))
{
// This line does not block us, but we don't want to be in it.
return false;
}
}
if (P_IsLineTripWire(line) == true && K_TripwirePass(tb->compareThing->player) == false)
{
// Can't go through trip wire.
return false;
}
}
}

View file

@ -31,11 +31,74 @@ UINT16 slopecount = 0;
static void P_BuildSlopeAnchorList (void);
static void P_SetupAnchoredSlopes (void);
// Calculate light
void P_UpdateSlopeLightOffset(pslope_t *slope)
{
const UINT8 contrast = maplighting.contrast;
fixed_t contrastFixed = ((fixed_t)contrast) * FRACUNIT;
fixed_t zMul = FRACUNIT;
fixed_t light = FRACUNIT;
fixed_t extralight = 0;
if (slope->normal.z == 0)
{
slope->lightOffset = slope->hwLightOffset = 0;
return;
}
if (maplighting.directional == true)
{
fixed_t nX = -slope->normal.x;
fixed_t nY = -slope->normal.y;
fixed_t nLen = FixedHypot(nX, nY);
if (nLen == 0)
{
slope->lightOffset = slope->hwLightOffset = 0;
return;
}
nX = FixedDiv(nX, nLen);
nY = FixedDiv(nY, nLen);
/*
if (slope is ceiling)
{
// There is no good way to calculate this condition here.
// We reverse it in R_FindPlane now.
nX = -nX;
nY = -nY;
}
*/
light = FixedMul(nX, FINECOSINE(maplighting.angle >> ANGLETOFINESHIFT))
+ FixedMul(nY, FINESINE(maplighting.angle >> ANGLETOFINESHIFT));
light = (light + FRACUNIT) / 2;
}
else
{
light = FixedDiv(R_PointToAngle2(0, 0, abs(slope->normal.y), abs(slope->normal.x)), ANGLE_90);
}
zMul = min(FRACUNIT, abs(slope->zdelta)*3/2); // *3/2, to make 60 degree slopes match walls.
contrastFixed = FixedMul(contrastFixed, zMul);
extralight = -contrastFixed + FixedMul(light, contrastFixed * 2);
// Between -2 and 2 for software, -16 and 16 for hardware
slope->lightOffset = FixedFloor((extralight / 8) + (FRACUNIT / 2)) / FRACUNIT;
#ifdef HWRENDER
slope->hwLightOffset = FixedFloor(extralight + (FRACUNIT / 2)) / FRACUNIT;
#endif
}
// Calculate line normal
void P_CalculateSlopeNormal(pslope_t *slope) {
slope->normal.z = FINECOSINE(slope->zangle>>ANGLETOFINESHIFT);
slope->normal.x = FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), slope->d.x);
slope->normal.y = FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), slope->d.y);
P_UpdateSlopeLightOffset(slope);
}
// Calculate slope's high & low z
@ -128,8 +191,10 @@ void P_ReconfigureViaVertexes (pslope_t *slope, const vector3_t v1, const vector
// Get angles
slope->xydirection = R_PointToAngle2(0, 0, slope->d.x, slope->d.y)+ANGLE_180;
slope->zangle = InvAngle(R_PointToAngle2(0, 0, FRACUNIT, slope->zdelta));
slope->zangle = R_PointToAngle2(0, 0, FRACUNIT, -slope->zdelta);
}
P_UpdateSlopeLightOffset(slope);
}
/// Setup slope via constants.
@ -159,7 +224,9 @@ static void ReconfigureViaConstants (pslope_t *slope, const fixed_t a, const fix
// Get angles
slope->xydirection = R_PointToAngle2(0, 0, slope->d.x, slope->d.y)+ANGLE_180;
slope->zangle = InvAngle(R_PointToAngle2(0, 0, FRACUNIT, slope->zdelta));
slope->zangle = R_PointToAngle2(0, 0, FRACUNIT, -slope->zdelta);
P_UpdateSlopeLightOffset(slope);
}
/// Recalculate dynamic slopes.
@ -544,6 +611,7 @@ static void line_SpawnViaMapthingVertexes(const int linenum, const boolean spawn
UINT16 tag2 = line->args[2];
UINT16 tag3 = line->args[3];
UINT8 flags = 0; // Slope flags
if (line->args[4] & TMSL_NOPHYSICS)
flags |= SL_NOPHYSICS;
if (line->args[4] & TMSL_DYNAMIC)

View file

@ -49,6 +49,7 @@ typedef enum
void P_LinkSlopeThinkers (void);
void P_UpdateSlopeLightOffset(pslope_t *slope);
void P_CalculateSlopeNormal(pslope_t *slope);
void P_ReconfigureViaVertexes(pslope_t *slope, const vector3_t v1, const vector3_t v2, const vector3_t v3);
void P_InitSlopes(void);

View file

@ -1769,10 +1769,18 @@ void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller)
//
// Switches the weather!
//
void P_SwitchWeather(UINT8 newWeather)
void P_SwitchWeather(preciptype_t newWeather)
{
boolean purge = false;
mobjtype_t swap = MT_NULL;
INT32 oldEffects = precipprops[curWeather].effects;
if (newWeather >= precip_freeslot)
{
// Weather type invalid, set to no weather.
CONS_Debug(DBG_SETUP, "Weather ID %d out of bounds\n", newWeather);
newWeather = PRECIP_NONE;
}
if (precipprops[newWeather].type == MT_NULL)
{
@ -1790,6 +1798,8 @@ void P_SwitchWeather(UINT8 newWeather)
}
}
curWeather = newWeather;
if (purge == true)
{
thinker_t *think;
@ -1844,14 +1854,22 @@ void P_SwitchWeather(UINT8 newWeather)
precipmobj->sprite = precipmobj->state->sprite;
precipmobj->frame = precipmobj->state->frame;
precipmobj->momz = mobjinfo[swap].speed;
precipmobj->precipflags &= ~PCF_INVISIBLE;
precipmobj->momz = FixedMul(-mobjinfo[swap].speed, mapobjectscale);
precipmobj->precipflags &= ~(PCF_INVISIBLE|PCF_FLIP);
if (precipmobj->momz > 0)
{
precipmobj->precipflags |= PCF_FLIP;
}
if ((oldEffects & PRECIPFX_WATERPARTICLES) != (precipprops[curWeather].effects & PRECIPFX_WATERPARTICLES))
{
P_CalculatePrecipFloor(precipmobj);
}
}
}
curWeather = newWeather;
if (swap == MT_NULL && precipprops[newWeather].type != MT_NULL)
if (swap == MT_NULL && precipprops[curWeather].type != MT_NULL)
P_SpawnPrecipitation();
}
@ -1899,14 +1917,6 @@ static void K_HandleLapIncrement(player_t *player)
player->karthud[khud_laphand] = 0; // No hands in FREE PLAY
player->karthud[khud_lapanimation] = 80;
// save best lap for record attack
if (player == &players[consoleplayer])
{
if (curlap < bestlap || bestlap == 0)
bestlap = curlap;
curlap = 0;
}
}
if (rainbowstartavailable == true)
@ -1920,18 +1930,18 @@ static void K_HandleLapIncrement(player_t *player)
rainbowstartavailable = false;
}
if (netgame && player->laps >= (UINT8)cv_numlaps.value)
if (netgame && player->laps >= numlaps)
CON_LogMessage(va(M_GetText("%s has finished the race.\n"), player_names[player-players]));
player->starpostnum = 0;
if (P_IsDisplayPlayer(player))
{
if (player->laps == (UINT8)(cv_numlaps.value)) // final lap
if (player->laps == numlaps) // final lap
S_StartSound(NULL, sfx_s3k68);
else if ((player->laps > 1) && (player->laps < (UINT8)(cv_numlaps.value))) // non-final lap
else if ((player->laps > 1) && (player->laps < numlaps)) // non-final lap
S_StartSound(NULL, sfx_s221);
else if (player->laps > (UINT8)(cv_numlaps.value))
else if (player->laps > numlaps)
{
// finished
S_StartSound(NULL, sfx_s3k6a);
@ -1940,7 +1950,7 @@ static void K_HandleLapIncrement(player_t *player)
}
else
{
if ((player->laps > (UINT8)(cv_numlaps.value)) && (player->position == 1))
if ((player->laps > numlaps) && (player->position == 1))
{
// opponent finished
S_StartSound(NULL, sfx_s253);
@ -1948,12 +1958,34 @@ static void K_HandleLapIncrement(player_t *player)
}
// finished race exit setup
if (player->laps > (unsigned)cv_numlaps.value)
if (player->laps > numlaps)
{
P_DoPlayerExit(player);
P_SetupSignExit(player);
}
if (player->laps > player->latestlap)
{
if (player->laps > 1)
{
// save best lap for record attack
if (modeattacking && player == &players[consoleplayer])
{
if (curlap < bestlap || bestlap == 0)
{
bestlap = curlap;
}
curlap = 0;
}
// Update power levels for this lap.
K_UpdatePowerLevels(player, player->laps, false);
}
player->latestlap = player->laps;
}
thwompsactive = true; // Lap 2 effects
lowestLap = P_FindLowestLap();
@ -3641,7 +3673,11 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
return;
if (delay <= 0 || !(leveltime % delay))
P_GivePlayerRings(mo->player, rings);
{
// No Climb: don't cap rings to 20
K_AwardPlayerRings(mo->player, rings,
(line->flags & ML_NOCLIMB) == ML_NOCLIMB);
}
}
}
break;
@ -4040,8 +4076,10 @@ sector_t *P_MobjTouchingSectorSpecial(mobj_t *mo, INT32 section, INT32 number, b
msecnode_t *node;
ffloor_t *rover;
if (!mo)
if (mo == NULL || P_MobjWasRemoved(mo) == true)
{
return NULL;
}
// Check default case first
if (GETSECSPECIAL(mo->subsector->sector->special, section) == number)
@ -5884,6 +5922,11 @@ void P_InitSpecials(void)
// Set the default gravity. Custom gravity overrides this setting.
gravity = mapheaderinfo[gamemap-1]->gravity;
// Set map lighting settings.
maplighting.contrast = mapheaderinfo[gamemap-1]->light_contrast;
maplighting.directional = mapheaderinfo[gamemap-1]->use_light_angle;
maplighting.angle = mapheaderinfo[gamemap-1]->light_angle;
// Defaults in case levels don't have them set.
sstimer = mapheaderinfo[gamemap-1]->sstimer*TICRATE + 6;
ssspheres = mapheaderinfo[gamemap-1]->ssspheres;
@ -6950,6 +6993,12 @@ void P_SpawnSpecialsThatRequireObjects(boolean fromnetsave)
for (i = 0; i < numlines; i++)
{
if (P_IsLineDisabled(&lines[i]))
{
/* remove the special so it can't even be found during the level */
lines[i].special = 0;
}
switch (lines[i].special)
{
case 30: // Polyobj_Flag
@ -6963,29 +7012,7 @@ void P_SpawnSpecialsThatRequireObjects(boolean fromnetsave)
case 32: // Polyobj_RotDisplace
PolyRotDisplace(&lines[i]);
break;
}
}
if (!fromnetsave)
P_RunLevelLoadExecutors();
}
/** Fuck ML_NONET
*/
void P_SpawnSpecialsAfterSlopes(void)
{
size_t i;
for (i = 0; i < numlines; ++i)
{
if (P_IsLineDisabled(&lines[i]))
{
/* remove the special so it can't even be found during the level */
lines[i].special = 0;
}
switch (lines[i].special)
{
case 80: // Raise tagged things by type to this FOF
{
mtag_t tag = Tag_FGet(&lines[i].tags);
@ -6998,6 +7025,9 @@ void P_SpawnSpecialsAfterSlopes(void)
break;
}
}
if (!fromnetsave)
P_RunLevelLoadExecutors();
}
/** Adds 3Dfloors as appropriate based on a common control linedef.

View file

@ -42,7 +42,6 @@ void P_SetupLevelFlatAnims(void);
// at map load
void P_InitSpecials(void);
void P_SpawnSpecials(boolean fromnetsave);
void P_SpawnSpecialsAfterSlopes(void);
void P_SpawnSpecialsThatRequireObjects(boolean fromnetsave);
// every tic
@ -67,7 +66,7 @@ void P_CrossSpecialLine(line_t *ld, INT32 side, mobj_t *thing);
void P_SetupSignExit(player_t *player);
boolean P_IsFlagAtBase(mobjtype_t flag);
void P_SwitchWeather(UINT8 newWeather);
void P_SwitchWeather(preciptype_t newWeather);
boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller);
void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller);

View file

@ -198,7 +198,7 @@ void P_CalcHeight(player_t *player)
fixed_t bob = 0;
fixed_t pviewheight;
mobj_t *mo = player->mo;
fixed_t bobmul = FRACUNIT - FixedDiv(FixedHypot(player->rmomx, player->rmomy), K_GetKartSpeed(player, false));
fixed_t bobmul = FRACUNIT - FixedDiv(FixedHypot(player->rmomx, player->rmomy), K_GetKartSpeed(player, false, false));
// Regular movement bobbing.
// Should not be calculated when not on ground (FIXTHIS?)
@ -873,7 +873,7 @@ void P_RestoreMusic(player_t *player)
#if 0
// Event - Final Lap
// Still works for GME, but disabled for consistency
if ((gametyperules & GTR_CIRCUIT) && player->laps >= (UINT8)(cv_numlaps.value))
if ((gametyperules & GTR_CIRCUIT) && player->laps >= numlaps)
S_SpeedMusic(1.2f);
#endif
if (mapmusresume && cv_resume.value)
@ -1939,7 +1939,7 @@ static void P_3dMovement(player_t *player)
// Make rubberbanding bots slow down faster
if (K_PlayerUsesBotMovement(player))
{
fixed_t rubberband = K_BotRubberband(player) - FRACUNIT;
fixed_t rubberband = player->botvars.rubberband - FRACUNIT;
if (rubberband > 0)
{
@ -1969,11 +1969,12 @@ static void P_3dMovement(player_t *player)
// allow for being able to change direction on spring jumps without being accelerated into the void - Sryder
if (!P_IsObjectOnGround(player->mo))
{
fixed_t topspeed = K_GetKartSpeed(player, true, true);
newMagnitude = R_PointToDist2(player->mo->momx - player->cmomx, player->mo->momy - player->cmomy, 0, 0);
if (newMagnitude > K_GetKartSpeed(player, true)) //topspeed)
if (newMagnitude > topspeed)
{
fixed_t tempmomx, tempmomy;
if (oldMagnitude > K_GetKartSpeed(player, true))
if (oldMagnitude > topspeed)
{
if (newMagnitude > oldMagnitude)
{
@ -1986,8 +1987,8 @@ static void P_3dMovement(player_t *player)
}
else
{
tempmomx = FixedMul(FixedDiv(player->mo->momx - player->cmomx, newMagnitude), K_GetKartSpeed(player, true)); //topspeed)
tempmomy = FixedMul(FixedDiv(player->mo->momy - player->cmomy, newMagnitude), K_GetKartSpeed(player, true)); //topspeed)
tempmomx = FixedMul(FixedDiv(player->mo->momx - player->cmomx, newMagnitude), topspeed);
tempmomy = FixedMul(FixedDiv(player->mo->momy - player->cmomy, newMagnitude), topspeed);
player->mo->momx = tempmomx + player->cmomx;
player->mo->momy = tempmomy + player->cmomy;
}
@ -2256,8 +2257,8 @@ void P_MovePlayer(player_t *player)
&& (player->speed > runspd)
&& player->mo->momz == 0 && player->carry != CR_SLIDING && !player->spectator)
{
fixed_t trailScale = FixedMul(FixedDiv(player->speed - runspd, K_GetKartSpeed(player, false) - runspd), mapobjectscale);
fixed_t playerTopSpeed = K_GetKartSpeed(player, false);
fixed_t playerTopSpeed = K_GetKartSpeed(player, false, false);
fixed_t trailScale = FixedMul(FixedDiv(player->speed - runspd, playerTopSpeed - runspd), mapobjectscale);
if (playerTopSpeed > runspd)
trailScale = FixedMul(FixedDiv(player->speed - runspd, playerTopSpeed - runspd), mapobjectscale);
@ -3852,6 +3853,7 @@ void P_DoTimeOver(player_t *player)
}
player->pflags |= PF_NOCONTEST;
K_UpdatePowerLevelsOnFailure(player);
if (G_GametypeUsesLives())
{

View file

@ -67,40 +67,6 @@ boolean R_IsRipplePlane(sector_t *sector, ffloor_t *rover, int ceiling)
sector->flags & (SF_RIPPLE_FLOOR << ceiling);
}
static void R_PlaneLightOverride(sector_t *sector, boolean ceiling, INT32 *lightlevel)
{
terrain_t *t = NULL;
if (ceiling == true)
{
t = K_GetTerrainForFlatNum(sector->ceilingpic);
}
else
{
t = K_GetTerrainForFlatNum(sector->floorpic);
}
if (t != NULL)
{
if (t->flags & TRF_SNEAKERPANEL)
{
*lightlevel = 255;
}
}
else
{
// Sector effect sneaker panels (DEPRECATED)
if (GETSECSPECIAL(sector->special, 4) == 6)
{
if ((ceiling && (sector->flags & SF_FLIPSPECIAL_CEILING))
|| (!ceiling && (sector->flags & SF_FLIPSPECIAL_FLOOR)))
{
*lightlevel = 255;
}
}
}
}
//
// R_ClearDrawSegs
//
@ -968,16 +934,18 @@ static void R_Subsector(size_t num)
sub->sector->extra_colormap = frontsector->extra_colormap;
R_PlaneLightOverride(frontsector, false, &floorlightlevel);
R_PlaneLightOverride(frontsector, true, &ceilinglightlevel);
if (P_GetSectorFloorZAt(frontsector, viewx, viewy) < viewz
|| frontsector->floorpic == skyflatnum
|| (frontsector->heightsec != -1 && sectors[frontsector->heightsec].ceilingpic == skyflatnum))
{
floorplane = R_FindPlane(frontsector->floorheight, frontsector->floorpic, floorlightlevel,
frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle, floorcolormap, NULL, NULL, frontsector->f_slope,
R_NoEncore(frontsector, false), R_IsRipplePlane(frontsector, NULL, false));
floorplane = R_FindPlane(
frontsector->floorheight, frontsector->floorpic, floorlightlevel,
frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle,
floorcolormap, NULL, NULL, frontsector->f_slope,
R_NoEncore(frontsector, false),
R_IsRipplePlane(frontsector, NULL, false),
false
);
}
else
floorplane = NULL;
@ -986,10 +954,14 @@ static void R_Subsector(size_t num)
|| frontsector->ceilingpic == skyflatnum
|| (frontsector->heightsec != -1 && sectors[frontsector->heightsec].floorpic == skyflatnum))
{
ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic,
ceilinglightlevel, frontsector->ceiling_xoffs, frontsector->ceiling_yoffs, frontsector->ceilingpic_angle,
ceilingplane = R_FindPlane(
frontsector->ceilingheight, frontsector->ceilingpic, ceilinglightlevel,
frontsector->ceiling_xoffs, frontsector->ceiling_yoffs, frontsector->ceilingpic_angle,
ceilingcolormap, NULL, NULL, frontsector->c_slope,
R_NoEncore(frontsector, true), R_IsRipplePlane(frontsector, NULL, true));
R_NoEncore(frontsector, true),
R_IsRipplePlane(frontsector, NULL, true),
true
);
}
else
ceilingplane = NULL;
@ -1027,19 +999,17 @@ static void R_Subsector(size_t num)
&& ((viewz < heightcheck && (rover->flags & FF_BOTHPLANES || !(rover->flags & FF_INVERTPLANES)))
|| (viewz > heightcheck && (rover->flags & FF_BOTHPLANES || rover->flags & FF_INVERTPLANES))))
{
INT32 newlightlevel;
light = R_GetPlaneLight(frontsector, planecenterz,
viewz < heightcheck);
newlightlevel = *frontsector->lightlist[light].lightlevel;
R_PlaneLightOverride(rover->master->frontsector, true, &newlightlevel);
ffloor[numffloors].plane = R_FindPlane(*rover->bottomheight, *rover->bottompic,
newlightlevel, *rover->bottomxoffs,
ffloor[numffloors].plane = R_FindPlane(
*rover->bottomheight, *rover->bottompic,
*frontsector->lightlist[light].lightlevel, *rover->bottomxoffs,
*rover->bottomyoffs, *rover->bottomangle, *frontsector->lightlist[light].extra_colormap, rover, NULL, *rover->b_slope,
R_NoEncore(rover->master->frontsector, true),
R_IsRipplePlane(rover->master->frontsector, rover, true));
R_IsRipplePlane(rover->master->frontsector, rover, true),
true
);
ffloor[numffloors].slope = *rover->b_slope;
@ -1064,18 +1034,16 @@ static void R_Subsector(size_t num)
&& ((viewz > heightcheck && (rover->flags & FF_BOTHPLANES || !(rover->flags & FF_INVERTPLANES)))
|| (viewz < heightcheck && (rover->flags & FF_BOTHPLANES || rover->flags & FF_INVERTPLANES))))
{
INT32 newlightlevel;
light = R_GetPlaneLight(frontsector, planecenterz, viewz < heightcheck);
newlightlevel = *frontsector->lightlist[light].lightlevel;
R_PlaneLightOverride(rover->master->frontsector, false, &newlightlevel);
ffloor[numffloors].plane = R_FindPlane(*rover->topheight, *rover->toppic,
ffloor[numffloors].plane = R_FindPlane(
*rover->topheight, *rover->toppic,
*frontsector->lightlist[light].lightlevel, *rover->topxoffs, *rover->topyoffs, *rover->topangle,
*frontsector->lightlist[light].extra_colormap, rover, NULL, *rover->t_slope,
R_NoEncore(rover->master->frontsector, false),
R_IsRipplePlane(rover->master->frontsector, rover, false));
R_IsRipplePlane(rover->master->frontsector, rover, false),
false
);
ffloor[numffloors].slope = *rover->t_slope;
@ -1114,19 +1082,18 @@ static void R_Subsector(size_t num)
&& polysec->floorheight >= floorcenterz
&& (viewz < polysec->floorheight))
{
INT32 newlightlevel;
light = R_GetPlaneLight(frontsector, polysec->floorheight, viewz < polysec->floorheight);
newlightlevel = (light == -1 ? frontsector->lightlevel : *frontsector->lightlist[light].lightlevel);
R_PlaneLightOverride(polysec, false, &newlightlevel);
ffloor[numffloors].plane = R_FindPlane(polysec->floorheight, polysec->floorpic,
ffloor[numffloors].plane = R_FindPlane(
polysec->floorheight, polysec->floorpic,
(light == -1 ? frontsector->lightlevel : *frontsector->lightlist[light].lightlevel), polysec->floor_xoffs, polysec->floor_yoffs,
polysec->floorpic_angle-po->angle,
(light == -1 ? frontsector->extra_colormap : *frontsector->lightlist[light].extra_colormap), NULL, po,
NULL, // will ffloors be slopable eventually?
R_NoEncore(polysec, false), false);/* TODO: wet polyobjects? */
R_NoEncore(polysec, false),
false, /* TODO: wet polyobjects? */
true
);
ffloor[numffloors].height = polysec->floorheight;
ffloor[numffloors].polyobj = po;
@ -1145,18 +1112,17 @@ static void R_Subsector(size_t num)
&& polysec->ceilingheight <= ceilingcenterz
&& (viewz > polysec->ceilingheight))
{
INT32 newlightlevel;
light = R_GetPlaneLight(frontsector, polysec->floorheight, viewz < polysec->floorheight);
newlightlevel = (light == -1 ? frontsector->lightlevel : *frontsector->lightlist[light].lightlevel);
R_PlaneLightOverride(polysec, true, &newlightlevel);
ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic,
ffloor[numffloors].plane = R_FindPlane(
polysec->ceilingheight, polysec->ceilingpic,
(light == -1 ? frontsector->lightlevel : *frontsector->lightlist[light].lightlevel), polysec->ceiling_xoffs, polysec->ceiling_yoffs, polysec->ceilingpic_angle-po->angle,
(light == -1 ? frontsector->extra_colormap : *frontsector->lightlist[light].extra_colormap), NULL, po,
NULL, // will ffloors be slopable eventually?
R_NoEncore(polysec, true), false);/* TODO: wet polyobjects? */
R_NoEncore(polysec, true),
false, /* TODO: wet polyobjects? */
false
);
ffloor[numffloors].polyobj = po;
ffloor[numffloors].height = polysec->ceilingheight;

View file

@ -251,6 +251,12 @@ typedef struct pslope_s
// SRB2Kart: For P_VeryTopOfFOF & P_VeryBottomOfFOF
fixed_t lowz;
fixed_t highz;
// Light offsets (see seg_t)
SINT8 lightOffset;
#ifdef HWRENDER
INT16 hwLightOffset;
#endif
} pslope_t;
typedef enum

View file

@ -836,13 +836,14 @@ void R_DrawSpan_8 (void)
bit = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift);
if (brightmap != NULL && brightmap[bit] == BRIGHTPIXEL)
{
*dest++ = fullbright[source[bit]];
*dest = fullbright[source[bit]];
}
else
{
*dest++ = colormap[source[bit]];
*dest = colormap[source[bit]];
}
dest++;
xposition += xstep;
yposition += ystep;
}
@ -933,10 +934,11 @@ void R_DrawTiltedSpan_8(void)
}
else
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
colormap = planezlight[tiltlighting[ds_x1]] + (ds_colormap - colormaps);
*dest = colormap[source[bit]];
}
dest++;
ds_x1++;
iz += ds_szp->x;
uz += ds_sup->x;
vz += ds_svp->x;
@ -975,10 +977,11 @@ void R_DrawTiltedSpan_8(void)
}
else
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
colormap = planezlight[tiltlighting[ds_x1]] + (ds_colormap - colormaps);
*dest = colormap[source[bit]];
}
dest++;
ds_x1++;
u += stepu;
v += stepv;
}
@ -999,9 +1002,10 @@ void R_DrawTiltedSpan_8(void)
}
else
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
colormap = planezlight[tiltlighting[ds_x1]] + (ds_colormap - colormaps);
*dest = colormap[source[bit]];
}
ds_x1++;
}
else
{
@ -1028,10 +1032,11 @@ void R_DrawTiltedSpan_8(void)
}
else
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
colormap = planezlight[tiltlighting[ds_x1]] + (ds_colormap - colormaps);
*dest = colormap[source[bit]];
}
dest++;
ds_x1++;
u += stepu;
v += stepv;
}
@ -1103,10 +1108,11 @@ void R_DrawTiltedTranslucentSpan_8(void)
}
else
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
colormap = planezlight[tiltlighting[ds_x1]] + (ds_colormap - colormaps);
*dest = *(ds_transmap + (colormap[source[bit]] << 8) + *dest);
}
dest++;
ds_x1++;
iz += ds_szp->x;
uz += ds_sup->x;
vz += ds_svp->x;
@ -1145,10 +1151,11 @@ void R_DrawTiltedTranslucentSpan_8(void)
}
else
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
colormap = planezlight[tiltlighting[ds_x1]] + (ds_colormap - colormaps);
*dest = *(ds_transmap + (colormap[source[bit]] << 8) + *dest);
}
dest++;
ds_x1++;
u += stepu;
v += stepv;
}
@ -1169,9 +1176,10 @@ void R_DrawTiltedTranslucentSpan_8(void)
}
else
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
colormap = planezlight[tiltlighting[ds_x1]] + (ds_colormap - colormaps);
*dest = *(ds_transmap + (colormap[source[bit]] << 8) + *dest);
}
ds_x1++;
}
else
{
@ -1198,10 +1206,11 @@ void R_DrawTiltedTranslucentSpan_8(void)
}
else
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
colormap = planezlight[tiltlighting[ds_x1]] + (ds_colormap - colormaps);
*dest = *(ds_transmap + (colormap[source[bit]] << 8) + *dest);
}
dest++;
ds_x1++;
u += stepu;
v += stepv;
}
@ -1270,14 +1279,16 @@ void R_DrawTiltedTranslucentWaterSpan_8(void)
bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift);
if (brightmap != NULL && brightmap[bit] == BRIGHTPIXEL)
{
*dest = *(ds_transmap + (fullbright[source[bit]] << 8) + *dsrc++);
*dest = *(ds_transmap + (fullbright[source[bit]] << 8) + *dsrc);
}
else
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
*dest = *(ds_transmap + (colormap[source[bit]] << 8) + *dsrc++);
colormap = planezlight[tiltlighting[ds_x1]] + (ds_colormap - colormaps);
*dest = *(ds_transmap + (colormap[source[bit]] << 8) + *dsrc);
}
dest++;
ds_x1++;
dsrc++;
iz += ds_szp->x;
uz += ds_sup->x;
vz += ds_svp->x;
@ -1312,14 +1323,16 @@ void R_DrawTiltedTranslucentWaterSpan_8(void)
bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift);
if (brightmap != NULL && brightmap[bit] == BRIGHTPIXEL)
{
*dest = *(ds_transmap + (fullbright[source[bit]] << 8) + *dsrc++);
*dest = *(ds_transmap + (fullbright[source[bit]] << 8) + *dsrc);
}
else
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
*dest = *(ds_transmap + (colormap[source[bit]] << 8) + *dsrc++);
colormap = planezlight[tiltlighting[ds_x1]] + (ds_colormap - colormaps);
*dest = *(ds_transmap + (colormap[source[bit]] << 8) + *dsrc);
}
dest++;
ds_x1++;
dsrc++;
u += stepu;
v += stepv;
}
@ -1336,13 +1349,14 @@ void R_DrawTiltedTranslucentWaterSpan_8(void)
bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift);
if (brightmap != NULL && brightmap[bit] == BRIGHTPIXEL)
{
*dest = *(ds_transmap + (fullbright[source[bit]] << 8) + *dsrc++);
*dest = *(ds_transmap + (fullbright[source[bit]] << 8) + *dsrc);
}
else
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
*dest = *(ds_transmap + (colormap[source[bit]] << 8) + *dsrc++);
colormap = planezlight[tiltlighting[ds_x1]] + (ds_colormap - colormaps);
*dest = *(ds_transmap + (colormap[source[bit]] << 8) + *dsrc);
}
ds_x1++;
}
else
{
@ -1365,14 +1379,16 @@ void R_DrawTiltedTranslucentWaterSpan_8(void)
bit = ((v >> nflatyshift) & nflatmask) | (u >> nflatxshift);
if (brightmap != NULL && brightmap[bit] == BRIGHTPIXEL)
{
*dest = *(ds_transmap + (fullbright[source[bit]] << 8) + *dsrc++);
*dest = *(ds_transmap + (fullbright[source[bit]] << 8) + *dsrc);
}
else
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
*dest = *(ds_transmap + (colormap[source[bit]] << 8) + *dsrc++);
colormap = planezlight[tiltlighting[ds_x1]] + (ds_colormap - colormaps);
*dest = *(ds_transmap + (colormap[source[bit]] << 8) + *dsrc);
}
dest++;
ds_x1++;
dsrc++;
u += stepu;
v += stepv;
}
@ -1446,12 +1462,13 @@ void R_DrawTiltedSplat_8(void)
}
else
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
colormap = planezlight[tiltlighting[ds_x1]] + (ds_colormap - colormaps);
*dest = colormap[val];
}
}
dest++;
ds_x1++;
iz += ds_szp->x;
uz += ds_sup->x;
vz += ds_svp->x;
@ -1493,11 +1510,12 @@ void R_DrawTiltedSplat_8(void)
}
else
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
colormap = planezlight[tiltlighting[ds_x1]] + (ds_colormap - colormaps);
*dest = colormap[val];
}
}
dest++;
ds_x1++;
u += stepu;
v += stepv;
}
@ -1521,9 +1539,10 @@ void R_DrawTiltedSplat_8(void)
}
else
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
colormap = planezlight[tiltlighting[ds_x1]] + (ds_colormap - colormaps);
*dest = colormap[val];
}
ds_x1++;
}
}
else
@ -1554,11 +1573,12 @@ void R_DrawTiltedSplat_8(void)
}
else
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
colormap = planezlight[tiltlighting[ds_x1]] + (ds_colormap - colormaps);
*dest = colormap[val];
}
}
dest++;
ds_x1++;
u += stepu;
v += stepv;
}
@ -2338,17 +2358,18 @@ void R_DrawTranslucentWaterSpan_8(void)
bit = ((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift);
if (brightmap != NULL && brightmap[bit] == BRIGHTPIXEL)
{
dest[i] = fullbright[*(ds_transmap + (source[bit] << 8) + *dsrc++)];
dest[i] = fullbright[*(ds_transmap + (source[bit] << 8) + dsrc[i])];
}
else
{
dest[i] = colormap[*(ds_transmap + (source[bit] << 8) + *dsrc++)];
dest[i] = colormap[*(ds_transmap + (source[bit] << 8) + dsrc[i])];
}
xposition += xstep;
yposition += ystep;
}
dest += 8;
dsrc += 8;
count -= 8;
}
while (count--)
@ -2356,12 +2377,14 @@ void R_DrawTranslucentWaterSpan_8(void)
bit = ((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift);
if (brightmap != NULL && brightmap[bit] == BRIGHTPIXEL)
{
*dest++ = fullbright[*(ds_transmap + (source[bit] << 8) + *dsrc++)];
*dest = fullbright[*(ds_transmap + (source[bit] << 8) + *dsrc)];
}
else
{
*dest++ = colormap[*(ds_transmap + (source[bit] << 8) + *dsrc++)];
*dest = colormap[*(ds_transmap + (source[bit] << 8) + *dsrc)];
}
dest++;
dsrc++;
xposition += xstep;
yposition += ystep;
}

View file

@ -316,7 +316,7 @@ void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjst
out->x = mobj->x;
out->y = mobj->y;
out->z = mobj->z;
out->scale = FRACUNIT;
out->scale = mapobjectscale;
out->subsector = mobj->subsector;
out->angle = mobj->angle;
out->spritexscale = mobj->spritexscale;
@ -329,7 +329,7 @@ void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjst
out->x = R_LerpFixed(mobj->old_x, mobj->x, frac);
out->y = R_LerpFixed(mobj->old_y, mobj->y, frac);
out->z = R_LerpFixed(mobj->old_z, mobj->z, frac);
out->scale = FRACUNIT;
out->scale = mapobjectscale;
out->spritexscale = R_LerpFixed(mobj->old_spritexscale, mobj->spritexscale, frac);
out->spriteyscale = R_LerpFixed(mobj->old_spriteyscale, mobj->spriteyscale, frac);
out->spritexoffset = R_LerpFixed(mobj->old_spritexoffset, mobj->spritexoffset, frac);

View file

@ -1322,6 +1322,8 @@ void R_SkyboxFrame(int s)
R_SetupAimingFrame(s);
newview->angle += r_viewmobj->angle;
newview->x = r_viewmobj->x;
newview->y = r_viewmobj->y;
newview->z = r_viewmobj->z; // 26/04/17: use actual Z position instead of spawnpoint angle!

View file

@ -349,7 +349,7 @@ static visplane_t *new_visplane(unsigned hash)
visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
fixed_t xoff, fixed_t yoff, angle_t plangle, extracolormap_t *planecolormap,
ffloor_t *pfloor, polyobj_t *polyobj, pslope_t *slope, boolean noencore,
boolean ripple)
boolean ripple, boolean reverseLight)
{
visplane_t *check;
unsigned hash;
@ -386,6 +386,18 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
}
}
if (slope != NULL && P_ApplyLightOffset(lightlevel >> LIGHTSEGSHIFT))
{
if (reverseLight && maplighting.directional == true)
{
lightlevel -= slope->lightOffset * 8;
}
else
{
lightlevel += slope->lightOffset * 8;
}
}
// This appears to fix the Nimbus Ruins sky bug.
if (picnum == skyflatnum && pfloor)
{

View file

@ -84,7 +84,7 @@ void R_ClearFFloorClips (void);
void R_DrawPlanes(void);
visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, fixed_t xoff, fixed_t yoff, angle_t plangle,
extracolormap_t *planecolormap, ffloor_t *ffloor, polyobj_t *polyobj, pslope_t *slope, boolean noencore,
boolean ripple);
boolean ripple, boolean reverseLight);
visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop);
void R_ExpandPlane(visplane_t *pl, INT32 start, INT32 stop);
void R_PlaneBounds(visplane_t *plane);

View file

@ -286,7 +286,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
if (rlight->extra_colormap && (rlight->extra_colormap->flags & CMF_FOG))
;
else
else if (P_ApplyLightOffset(lightnum))
lightnum += curline->lightOffset;
rlight->lightnum = lightnum;
@ -303,7 +303,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
if ((R_CheckColumnFunc(COLDRAWFUNC_FOG) == true)
|| (frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG)))
;
else
else if (P_ApplyLightOffset(lightnum))
lightnum += curline->lightOffset;
if (lightnum < 0)
@ -770,7 +770,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
if (pfloor->flags & FF_FOG || rlight->flags & FF_FOG || (rlight->extra_colormap && (rlight->extra_colormap->flags & CMF_FOG)))
;
else
else if (P_ApplyLightOffset(rlight->lightnum))
rlight->lightnum += curline->lightOffset;
p++;
@ -793,7 +793,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
if (pfloor->flags & FF_FOG || (frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG)))
;
else
else if (P_ApplyLightOffset(lightnum))
lightnum += curline->lightOffset;
if (lightnum < 0)
@ -1383,7 +1383,7 @@ static void R_RenderSegLoop (void)
if (dc_lightlist[i].extra_colormap)
;
else
else if (P_ApplyLightOffset(lightnum))
lightnum += curline->lightOffset;
if (lightnum < 0)
@ -2436,7 +2436,8 @@ void R_StoreWallRange(INT32 start, INT32 stop)
// OPTIMIZE: get rid of LIGHTSEGSHIFT globally
lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT);
lightnum += curline->lightOffset;
if (P_ApplyLightOffset(lightnum))
lightnum += curline->lightOffset;
if (lightnum < 0)
walllights = scalelight[0];

View file

@ -86,6 +86,35 @@ static spriteframe_t sprtemp[64];
static size_t maxframe;
static const char *spritename;
//
// Clipping against drawsegs optimization, from prboom-plus
//
// TODO: This should be done with proper subsector pass through
// sprites which would ideally remove the need to do it at all.
// Unfortunately, SRB2's drawing loop has lots of annoying
// changes from Doom for portals, which make it hard to implement.
typedef struct drawseg_xrange_item_s
{
INT16 x1, x2;
drawseg_t *user;
} drawseg_xrange_item_t;
typedef struct drawsegs_xrange_s
{
drawseg_xrange_item_t *items;
INT32 count;
} drawsegs_xrange_t;
#define DS_RANGES_COUNT 3
static drawsegs_xrange_t drawsegs_xranges[DS_RANGES_COUNT];
static drawseg_xrange_item_t *drawsegs_xrange;
static size_t drawsegs_xrange_size = 0;
static INT32 drawsegs_xrange_count = 0;
#define CLIP_UNDEF -2
// ==========================================================================
//
// Sprite loading routines: support sprites in pwad, dehacked sprite renaming,
@ -1034,6 +1063,7 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis)
#endif
fixed_t frac;
patch_t *patch;
fixed_t this_scale = vis->thingscale;
INT64 overflow_test;
//Fab : R_InitSprites now sets a wad lump number
@ -1061,7 +1091,7 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis)
}
dc_iscale = FixedDiv(FRACUNIT, vis->scale);
dc_texturemid = vis->texturemid;
dc_texturemid = FixedDiv(vis->texturemid, this_scale);
dc_texheight = 0;
frac = vis->startfrac;
@ -2187,6 +2217,10 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
//SoM: 3/17/2000
fixed_t gz, gzt;
fixed_t this_scale;
UINT32 blendmode;
UINT32 trans;
// uncapped/interpolation
interpmobjstate_t interp = {0};
@ -2201,6 +2235,8 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
R_InterpolatePrecipMobjState(thing, FRACUNIT, &interp);
}
this_scale = interp.scale;
// transform the origin point
tr_x = interp.x - viewx;
tr_y = interp.y - viewy;
@ -2208,7 +2244,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); // near/far distance
// thing is behind view plane?
if (tz < MINZ)
if (tz < FixedMul(MINZ, this_scale))
return;
tx = FixedMul(tr_x, viewsin) - FixedMul(tr_y, viewcos); // sideways distance
@ -2247,14 +2283,14 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
lump = sprframe->lumpid[0]; //Fab: see note above
// calculate edges of the shape
tx -= spritecachedinfo[lump].offset;
tx -= FixedMul(spritecachedinfo[lump].offset, this_scale);
x1 = (centerxfrac + FixedMul (tx,xscale)) >>FRACBITS;
// off the right side?
if (x1 > viewwidth)
return;
tx += spritecachedinfo[lump].width;
tx += FixedMul(spritecachedinfo[lump].width, this_scale);
x2 = ((centerxfrac + FixedMul (tx,xscale)) >>FRACBITS) - 1;
// off the left side
@ -2272,8 +2308,8 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
}
//SoM: 3/17/2000: Disregard sprites that are out of view..
gzt = interp.z + spritecachedinfo[lump].topoffset;
gz = gzt - spritecachedinfo[lump].height;
gzt = interp.z + FixedMul(spritecachedinfo[lump].topoffset, this_scale);
gz = gzt - FixedMul(spritecachedinfo[lump].height, this_scale);
if (thing->subsector->sector->cullheight)
{
@ -2281,9 +2317,22 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
goto weatherthink;
}
// Determine the blendmode and translucency value
{
blendmode = (thing->frame & FF_BLENDMASK) >> FF_BLENDSHIFT;
if (blendmode)
blendmode++; // realign to constants
trans = (thing->frame & FF_TRANSMASK) >> FF_TRANSSHIFT;
if (trans >= NUMTRANSMAPS)
goto weatherthink; // cap
}
// store information in a vissprite
vis = R_NewVisSprite();
vis->scale = vis->sortscale = yscale; //<<detailshift;
vis->scale = FixedMul(yscale, this_scale);
vis->sortscale = yscale; //<<detailshift;
vis->thingscale = interp.scale;
vis->dispoffset = 0; // Monster Iestyn: 23/11/15
vis->gx = interp.x;
vis->gy = interp.y;
@ -2309,7 +2358,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
iscale = FixedDiv(FRACUNIT, xscale);
vis->startfrac = 0;
vis->xiscale = iscale;
vis->xiscale = FixedDiv(iscale, this_scale);
if (vis->x1 > x1)
vis->startfrac += vis->xiscale*(vis->x1-x1);
@ -2318,12 +2367,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
// than lumpid for sprites-in-pwad : the graphics are patched
vis->patch = W_CachePatchNum(sprframe->lumppat[0], PU_SPRITE);
// specific translucency
// (no draw flags)
if (thing->frame & FF_TRANSMASK)
vis->transmap = ((thing->frame & FF_TRANSMASK) - FF_TRANS10) + transtables;
else
vis->transmap = NULL;
vis->transmap = R_GetBlendTable(blendmode, trans);
vis->mobj = (mobj_t *)thing;
vis->mobjflags = 0;
@ -2918,7 +2962,7 @@ static void R_DrawPrecipitationSprite(vissprite_t *spr)
// R_ClipVisSprite
// Clips vissprites without drawing, so that portals can work. -Red
void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, portal_t* portal)
void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, portal_t* portal)
{
drawseg_t *ds;
INT32 x;
@ -2929,7 +2973,9 @@ void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, p
INT32 silhouette;
for (x = x1; x <= x2; x++)
spr->clipbot[x] = spr->cliptop[x] = -2;
{
spr->clipbot[x] = spr->cliptop[x] = CLIP_UNDEF;
}
// Scan drawsegs from end to start for obscuring segs.
// The first drawseg that has a greater scale
@ -2938,82 +2984,90 @@ void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, p
// Pointer check was originally nonportable
// and buggy, by going past LEFT end of array:
// for (ds = ds_p-1; ds >= drawsegs; ds--) old buggy code
for (ds = ds_p; ds-- > dsstart;)
// e6y: optimization
if (drawsegs_xrange_size)
{
// determine if the drawseg obscures the sprite
if (ds->x1 > x2 ||
ds->x2 < x1 ||
(!ds->silhouette
&& !ds->maskedtexturecol))
const drawseg_xrange_item_t *last = &drawsegs_xrange[drawsegs_xrange_count - 1];
drawseg_xrange_item_t *curr = &drawsegs_xrange[-1];
while (++curr <= last)
{
// does not cover sprite
continue;
}
if (ds->portalpass != 66)
{
if (ds->portalpass > 0 && ds->portalpass <= portalrender)
continue; // is a portal
if (ds->scale1 > ds->scale2)
// determine if the drawseg obscures the sprite
if (curr->x1 > spr->x2 || curr->x2 < spr->x1)
{
lowscale = ds->scale2;
scale = ds->scale1;
}
else
{
lowscale = ds->scale1;
scale = ds->scale2;
}
if (scale < spr->sortscale ||
(lowscale < spr->sortscale &&
!R_PointOnSegSide (spr->gx, spr->gy, ds->curline)))
{
// masked mid texture?
/*if (ds->maskedtexturecol)
R_RenderMaskedSegRange (ds, r1, r2);*/
// seg is behind sprite
// does not cover sprite
continue;
}
}
r1 = ds->x1 < x1 ? x1 : ds->x1;
r2 = ds->x2 > x2 ? x2 : ds->x2;
ds = curr->user;
// clip this piece of the sprite
silhouette = ds->silhouette;
if (spr->gz >= ds->bsilheight)
silhouette &= ~SIL_BOTTOM;
if (spr->gzt <= ds->tsilheight)
silhouette &= ~SIL_TOP;
if (silhouette == SIL_BOTTOM)
{
// bottom sil
for (x = r1; x <= r2; x++)
if (spr->clipbot[x] == -2)
spr->clipbot[x] = ds->sprbottomclip[x];
}
else if (silhouette == SIL_TOP)
{
// top sil
for (x = r1; x <= r2; x++)
if (spr->cliptop[x] == -2)
spr->cliptop[x] = ds->sprtopclip[x];
}
else if (silhouette == (SIL_TOP|SIL_BOTTOM))
{
// both
for (x = r1; x <= r2; x++)
if (ds->portalpass != 66) // unused?
{
if (spr->clipbot[x] == -2)
spr->clipbot[x] = ds->sprbottomclip[x];
if (spr->cliptop[x] == -2)
spr->cliptop[x] = ds->sprtopclip[x];
if (ds->portalpass > 0 && ds->portalpass <= portalrender)
continue; // is a portal
if (ds->scale1 > ds->scale2)
{
lowscale = ds->scale2;
scale = ds->scale1;
}
else
{
lowscale = ds->scale1;
scale = ds->scale2;
}
if (scale < spr->sortscale ||
(lowscale < spr->sortscale &&
!R_PointOnSegSide (spr->gx, spr->gy, ds->curline)))
{
// masked mid texture?
/*
if (ds->maskedtexturecol)
R_RenderMaskedSegRange (ds, r1, r2);
*/
// seg is behind sprite
continue;
}
}
r1 = ds->x1 < x1 ? x1 : ds->x1;
r2 = ds->x2 > x2 ? x2 : ds->x2;
// clip this piece of the sprite
silhouette = ds->silhouette;
if (spr->gz >= ds->bsilheight)
silhouette &= ~SIL_BOTTOM;
if (spr->gzt <= ds->tsilheight)
silhouette &= ~SIL_TOP;
if (silhouette == SIL_BOTTOM)
{
// bottom sil
for (x = r1; x <= r2; x++)
if (spr->clipbot[x] == CLIP_UNDEF)
spr->clipbot[x] = ds->sprbottomclip[x];
}
else if (silhouette == SIL_TOP)
{
// top sil
for (x = r1; x <= r2; x++)
if (spr->cliptop[x] == CLIP_UNDEF)
spr->cliptop[x] = ds->sprtopclip[x];
}
else if (silhouette == (SIL_TOP|SIL_BOTTOM))
{
// both
for (x = r1; x <= r2; x++)
{
if (spr->clipbot[x] == CLIP_UNDEF)
spr->clipbot[x] = ds->sprbottomclip[x];
if (spr->cliptop[x] == CLIP_UNDEF)
spr->cliptop[x] = ds->sprtopclip[x];
}
}
}
}
@ -3029,13 +3083,13 @@ void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, p
if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight))
{ // clip bottom
for (x = x1; x <= x2; x++)
if (spr->clipbot[x] == -2 || h < spr->clipbot[x])
if (spr->clipbot[x] == CLIP_UNDEF || h < spr->clipbot[x])
spr->clipbot[x] = (INT16)h;
}
else // clip top
{
for (x = x1; x <= x2; x++)
if (spr->cliptop[x] == -2 || h > spr->cliptop[x])
if (spr->cliptop[x] == CLIP_UNDEF || h > spr->cliptop[x])
spr->cliptop[x] = (INT16)h;
}
}
@ -3047,13 +3101,13 @@ void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, p
if (phs != -1 && viewz >= sectors[phs].ceilingheight)
{ // clip bottom
for (x = x1; x <= x2; x++)
if (spr->clipbot[x] == -2 || h < spr->clipbot[x])
if (spr->clipbot[x] == CLIP_UNDEF || h < spr->clipbot[x])
spr->clipbot[x] = (INT16)h;
}
else // clip top
{
for (x = x1; x <= x2; x++)
if (spr->cliptop[x] == -2 || h > spr->cliptop[x])
if (spr->cliptop[x] == CLIP_UNDEF || h > spr->cliptop[x])
spr->cliptop[x] = (INT16)h;
}
}
@ -3062,10 +3116,10 @@ void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, p
{
for (x = x1; x <= x2; x++)
{
if (spr->cliptop[x] == -2 || spr->szt > spr->cliptop[x])
if (spr->cliptop[x] == CLIP_UNDEF || spr->szt > spr->cliptop[x])
spr->cliptop[x] = spr->szt;
if (spr->clipbot[x] == -2 || spr->sz < spr->clipbot[x])
if (spr->clipbot[x] == CLIP_UNDEF || spr->sz < spr->clipbot[x])
spr->clipbot[x] = spr->sz;
}
}
@ -3073,7 +3127,7 @@ void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, p
{
for (x = x1; x <= x2; x++)
{
if (spr->cliptop[x] == -2 || spr->szt > spr->cliptop[x])
if (spr->cliptop[x] == CLIP_UNDEF || spr->szt > spr->cliptop[x])
spr->cliptop[x] = spr->szt;
}
}
@ -3081,7 +3135,7 @@ void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, p
{
for (x = x1; x <= x2; x++)
{
if (spr->clipbot[x] == -2 || spr->sz < spr->clipbot[x])
if (spr->clipbot[x] == CLIP_UNDEF || spr->sz < spr->clipbot[x])
spr->clipbot[x] = spr->sz;
}
}
@ -3091,10 +3145,10 @@ void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, p
// check for unclipped columns
for (x = x1; x <= x2; x++)
{
if (spr->clipbot[x] == -2)
if (spr->clipbot[x] == CLIP_UNDEF)
spr->clipbot[x] = (INT16)viewheight;
if (spr->cliptop[x] == -2)
if (spr->cliptop[x] == CLIP_UNDEF)
//Fab : 26-04-98: was -1, now clips against console bottom
spr->cliptop[x] = (INT16)con_clipviewtop;
}
@ -3125,12 +3179,89 @@ void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, p
void R_ClipSprites(drawseg_t* dsstart, portal_t* portal)
{
const size_t maxdrawsegs = ds_p - dsstart;
const INT32 cx = viewwidth / 2;
drawseg_t* ds;
INT32 i;
// e6y
// Reducing of cache misses in the following R_DrawSprite()
// Makes sense for scenes with huge amount of drawsegs.
// ~12% of speed improvement on epic.wad map05
for (i = 0; i < DS_RANGES_COUNT; i++)
{
drawsegs_xranges[i].count = 0;
}
if (visspritecount - clippedvissprites <= 0)
{
return;
}
if (drawsegs_xrange_size < maxdrawsegs)
{
drawsegs_xrange_size = 2 * maxdrawsegs;
for (i = 0; i < DS_RANGES_COUNT; i++)
{
drawsegs_xranges[i].items = Z_Realloc(
drawsegs_xranges[i].items,
drawsegs_xrange_size * sizeof(drawsegs_xranges[i].items[0]),
PU_STATIC, NULL
);
}
}
for (ds = ds_p; ds-- > dsstart;)
{
if (ds->silhouette || ds->maskedtexturecol)
{
drawsegs_xranges[0].items[drawsegs_xranges[0].count].x1 = ds->x1;
drawsegs_xranges[0].items[drawsegs_xranges[0].count].x2 = ds->x2;
drawsegs_xranges[0].items[drawsegs_xranges[0].count].user = ds;
// e6y: ~13% of speed improvement on sunder.wad map10
if (ds->x1 < cx)
{
drawsegs_xranges[1].items[drawsegs_xranges[1].count] =
drawsegs_xranges[0].items[drawsegs_xranges[0].count];
drawsegs_xranges[1].count++;
}
if (ds->x2 >= cx)
{
drawsegs_xranges[2].items[drawsegs_xranges[2].count] =
drawsegs_xranges[0].items[drawsegs_xranges[0].count];
drawsegs_xranges[2].count++;
}
drawsegs_xranges[0].count++;
}
}
for (; clippedvissprites < visspritecount; clippedvissprites++)
{
vissprite_t *spr = R_GetVisSprite(clippedvissprites);
INT32 x1 = (spr->cut & SC_SPLAT) ? 0 : spr->x1;
INT32 x2 = (spr->cut & SC_SPLAT) ? viewwidth : spr->x2;
R_ClipVisSprite(spr, x1, x2, dsstart, portal);
if (x2 < cx)
{
drawsegs_xrange = drawsegs_xranges[1].items;
drawsegs_xrange_count = drawsegs_xranges[1].count;
}
else if (x1 >= cx)
{
drawsegs_xrange = drawsegs_xranges[2].items;
drawsegs_xrange_count = drawsegs_xranges[2].count;
}
else
{
drawsegs_xrange = drawsegs_xranges[0].items;
drawsegs_xrange_count = drawsegs_xranges[0].count;
}
R_ClipVisSprite(spr, x1, x2, portal);
}
}

View file

@ -218,7 +218,7 @@ typedef struct vissprite_s
extern UINT32 visspritecount;
void R_ClipSprites(drawseg_t* dsstart, portal_t* portal);
void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, portal_t* portal);
void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, portal_t* portal);
UINT8 *R_GetSpriteTranslation(vissprite_t *vis);

View file

@ -678,6 +678,14 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume)
if (!sfx->data)
{
sfx->data = I_GetSfx(sfx);
if (!sfx->data)
{
CONS_Alert(CONS_WARNING,
"Tried to load invalid sfx_%s\n",
sfx->name);
return;/* don't play it */
}
}
// increase the usefulness

View file

@ -79,11 +79,11 @@ if(${SDL2_FOUND})
endif()
if(${CMAKE_SYSTEM} MATCHES Windows)
set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME srb2win)
set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME srb2kart)
elseif(${CMAKE_SYSTEM} MATCHES Linux)
set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME lsdlsrb2)
set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME lsdlsrb2kart)
else()
set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME srb2)
set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME srb2kart)
endif()
if(${CMAKE_SYSTEM} MATCHES Darwin)
@ -124,6 +124,14 @@ if(${SDL2_FOUND})
endif()
endif()
if(${CMAKE_SYSTEM} MATCHES Windows AND ${CMAKE_C_COMPILER_ID} MATCHES "GNU" AND ${SRB2_SYSTEM_BITS} EQUAL 32)
target_link_libraries(SRB2SDL2 PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/../../libs/drmingw/lib/win32/libexchndl.a"
"${CMAKE_CURRENT_SOURCE_DIR}/../../libs/drmingw/lib/win32/libmgwhelp.a"
)
target_include_directories(SRB2SDL2 PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../libs/drmingw/include")
endif()
#target_link_libraries(SRB2SDL2 PRIVATE SRB2Core)
if(${SRB2_USEASM})
@ -168,24 +176,9 @@ if(${SDL2_FOUND})
target_compile_definitions(SRB2SDL2 PRIVATE
-DDIRECTFULLSCREEN -DHAVE_SDL
-DHAVE_THREADS
)
## strip debug symbols into separate file when using gcc.
## to be consistent with Makefile, don't generate for OS X.
if((CMAKE_COMPILER_IS_GNUCC) AND NOT (${CMAKE_SYSTEM} MATCHES Darwin))
if((${CMAKE_BUILD_TYPE} MATCHES Debug) OR (${CMAKE_BUILD_TYPE} MATCHES RelWithDebInfo))
if(${CMAKE_BUILD_TYPE} MATCHES Debug)
set(OBJCOPY_ONLY_KEEP_DEBUG "--only-keep-debug")
endif()
message(STATUS "Will make separate debug symbols in *.debug")
add_custom_command(TARGET SRB2SDL2 POST_BUILD
COMMAND ${OBJCOPY} ${OBJCOPY_ONLY_KEEP_DEBUG} $<TARGET_FILE:SRB2SDL2> $<TARGET_FILE:SRB2SDL2>.debug
COMMAND ${OBJCOPY} --strip-debug $<TARGET_FILE:SRB2SDL2>
COMMAND ${OBJCOPY} --add-gnu-debuglink=$<TARGET_FILE:SRB2SDL2>.debug $<TARGET_FILE:SRB2SDL2>
)
endif()
endif()
#### Installation ####
if(${CMAKE_SYSTEM} MATCHES Darwin)
install(TARGETS SRB2SDL2

Some files were not shown because too many files have changed in this diff Show more