This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/Combat/control.cpp

481 lines
15 KiB
C++
Raw Permalink Normal View History

/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/***********************************************************************************************
*** Confidential - Westwood Studios ***
***********************************************************************************************
* *
* Project Name : Commando *
* *
* $Archive:: /Commando/Code/Combat/control.cpp $*
* *
* $Author:: Byon_g $*
* *
* $Modtime:: 2/21/02 5:08p $*
* *
* $Revision:: 34 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "control.h"
#include "wwdebug.h"
#include "input.h"
#include "wwmath.h"
#include "wwpacket.h"
#include "chunkio.h"
#include "debug.h"
#include <memory.h>
#include "combat.h"
//#include "clientinterpmodels.h"
#include "encoderlist.h"
#include "bitpackids.h"
// Should pack analogs of 1 and -1 into single bit
//
// TSS 03/08/99: I have scaled the floats down to bytes.... more optimisation later!
//
ControlClass & ControlClass::operator = (const ControlClass & src)
{
OneTimeBooleanBits = src.OneTimeBooleanBits;
ContinuousBooleanBits = src.ContinuousBooleanBits;
memcpy( AnalogValues, src.AnalogValues, sizeof(AnalogValues) );
return *this;
}
/*
**
*/
enum {
CHUNKID_VARIABLES = 914991110,
MICROCHUNKID_ONE_TIME_BOOL = 1,
MICROCHUNKID_CONTINUOUS_BOOL,
MICROCHUNKID_ANALOG,
MICROCHUNKID_PENDING_ONE_TIME_BOOL,
MICROCHUNKID_PENDING_CONTINUOUS_BOOL,
};
bool ControlClass::Save( ChunkSaveClass & csave )
{
csave.Begin_Chunk( CHUNKID_VARIABLES );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_ONE_TIME_BOOL, OneTimeBooleanBits );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_CONTINUOUS_BOOL, ContinuousBooleanBits );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_PENDING_ONE_TIME_BOOL, PendingOneTimeBooleanBits );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_PENDING_CONTINUOUS_BOOL, PendingContinuousBooleanBits );
csave.Begin_Micro_Chunk(MICROCHUNKID_ANALOG);
csave.Write(&AnalogValues[0],sizeof(AnalogValues));
csave.End_Micro_Chunk();
csave.End_Chunk();
return true;
}
bool ControlClass::Load( ChunkLoadClass &cload )
{
while (cload.Open_Chunk()) {
switch(cload.Cur_Chunk_ID()) {
case CHUNKID_VARIABLES:
while (cload.Open_Micro_Chunk()) {
switch(cload.Cur_Micro_Chunk_ID()) {
READ_MICRO_CHUNK( cload, MICROCHUNKID_ONE_TIME_BOOL, OneTimeBooleanBits );
READ_MICRO_CHUNK( cload, MICROCHUNKID_CONTINUOUS_BOOL, ContinuousBooleanBits );
READ_MICRO_CHUNK( cload, MICROCHUNKID_PENDING_ONE_TIME_BOOL, PendingOneTimeBooleanBits );
READ_MICRO_CHUNK( cload, MICROCHUNKID_PENDING_CONTINUOUS_BOOL, PendingContinuousBooleanBits );
case MICROCHUNKID_ANALOG:
cload.Read( &AnalogValues[0],sizeof(AnalogValues) );
break;
default:
Debug_Say(( "Unrecognized Control Variable chunkID\n" ));
break;
}
cload.Close_Micro_Chunk();
}
break;
default:
Debug_Say(( "Unrecognized Control chunkID\n" ));
break;
}
cload.Close_Chunk();
}
return true;
}
//JITTER
void ControlClass::Clear_Boolean( void )
{
WWASSERT( (8 * sizeof(ControlClass::OneTimeBooleanBits)) >= ControlClass::NUM_BOOLEAN_ONE_TIME );
WWASSERT( (8 * sizeof(ControlClass::ContinuousBooleanBits)) >= ControlClass::NUM_BOOLEAN_CONTINUOUS );
OneTimeBooleanBits = 0;
ContinuousBooleanBits = 0;
}
void ControlClass::Clear_Control( void )
{
WWASSERT( (8 * sizeof(ControlClass::OneTimeBooleanBits)) >= ControlClass::NUM_BOOLEAN_ONE_TIME );
WWASSERT( (8 * sizeof(ControlClass::ContinuousBooleanBits)) >= ControlClass::NUM_BOOLEAN_CONTINUOUS );
OneTimeBooleanBits = 0;
ContinuousBooleanBits = 0;
memset( AnalogValues, 0, sizeof(AnalogValues) );
}
enum {
CONTROL_MOVE_FORWARD = 0,
CONTROL_MOVE_BACKWARD,
CONTROL_MOVE_LEFT,
CONTROL_MOVE_RIGHT,
CONTROL_MOVE_UP,
CONTROL_MOVE_DOWN,
CONTROL_TURN_LEFT,
CONTROL_TURN_RIGHT,
} CONTROL_MOVE_BITS;
//-----------------------------------------------------------------------------
void ControlClass::Import_Cs( BitStreamClass & packet )
{
// Or in the new one time bits
ULONG otb_bits = packet.Get(otb_bits, BITPACK_ONE_TIME_BOOLEAN_BITS);
OneTimeBooleanBits |= otb_bits;
packet.Get(ContinuousBooleanBits, BITPACK_CONTINUOUS_BOOLEAN_BITS);
#if 01
packet.Get(AnalogValues[ANALOG_MOVE_FORWARD], BITPACK_ANALOG_VALUES);
packet.Get(AnalogValues[ANALOG_MOVE_LEFT], BITPACK_ANALOG_VALUES);
packet.Get(AnalogValues[ANALOG_MOVE_UP], BITPACK_ANALOG_VALUES);
packet.Get(AnalogValues[ANALOG_TURN_LEFT], BITPACK_ANALOG_VALUES);
#else
int control_move;
packet.Get( control_move, BITPACK_CONTROL_MOVES_CS);
AnalogValues[ANALOG_MOVE_FORWARD] = 0.0f;
AnalogValues[ANALOG_MOVE_LEFT] = 0.0f;
AnalogValues[ANALOG_MOVE_UP] = 0.0f;
AnalogValues[ANALOG_TURN_LEFT] = 0.0f;
if ( control_move & (1<<CONTROL_MOVE_FORWARD) ) {
AnalogValues[ANALOG_MOVE_FORWARD] = 1.0f;
}
if ( control_move & (1<<CONTROL_MOVE_BACKWARD) ) {
AnalogValues[ANALOG_MOVE_FORWARD] = -1.0f;
}
if ( control_move & (1<<CONTROL_MOVE_LEFT) ) {
AnalogValues[ANALOG_MOVE_LEFT] = 1.0f;
}
if ( control_move & (1<<CONTROL_MOVE_RIGHT) ) {
AnalogValues[ANALOG_MOVE_LEFT] = -1.0f;
}
if ( control_move & (1<<CONTROL_MOVE_UP) ) {
AnalogValues[ANALOG_MOVE_UP] = 1.0f;
}
if ( control_move & (1<<CONTROL_MOVE_DOWN) ) {
AnalogValues[ANALOG_MOVE_UP] = -1.0f;
}
if ( control_move & (1<<CONTROL_TURN_LEFT) ) {
AnalogValues[ANALOG_TURN_LEFT] = 1.0f;
}
if ( control_move & (1<<CONTROL_TURN_RIGHT) ) {
AnalogValues[ANALOG_TURN_LEFT] = -1.0f;
}
#endif
for (int i = 0; i < ANALOG_CONTROL_COUNT; i++) {
if (fabs(AnalogValues[i]) < 0.005) {
//
// The code elsewhere has no tolerance for precision error on this
// value around zero...
//
AnalogValues[i] = 0;
}
}
}
//-----------------------------------------------------------------------------
void ControlClass::Export_Cs( BitStreamClass & packet )
{
// packet.Add(OneTimeBooleanBits, BITPACK_ONE_TIME_BOOLEAN_BITS);
packet.Add(PendingOneTimeBooleanBits, BITPACK_ONE_TIME_BOOLEAN_BITS);
PendingOneTimeBooleanBits = 0;
// packet.Add(ContinuousBooleanBits, BITPACK_CONTINUOUS_BOOLEAN_BITS);
packet.Add(PendingContinuousBooleanBits, BITPACK_CONTINUOUS_BOOLEAN_BITS);
PendingContinuousBooleanBits = 0;
#if 01
packet.Add(AnalogValues[ANALOG_MOVE_FORWARD], BITPACK_ANALOG_VALUES);
packet.Add(AnalogValues[ANALOG_MOVE_LEFT], BITPACK_ANALOG_VALUES);
packet.Add(AnalogValues[ANALOG_MOVE_UP], BITPACK_ANALOG_VALUES);
packet.Add(AnalogValues[ANALOG_TURN_LEFT], BITPACK_ANALOG_VALUES);
#else
int control_move = 0;
if ( AnalogValues[ANALOG_MOVE_FORWARD] > 0.5f ) {
control_move |= 1<<CONTROL_MOVE_FORWARD;
}
if ( AnalogValues[ANALOG_MOVE_FORWARD] < -0.5f ) {
control_move |= 1<<CONTROL_MOVE_BACKWARD;
}
if ( AnalogValues[ANALOG_MOVE_LEFT] > 0.5f ) {
control_move |= 1<<CONTROL_MOVE_LEFT;
}
if ( AnalogValues[ANALOG_MOVE_LEFT] < -0.5f ) {
control_move |= 1<<CONTROL_MOVE_RIGHT;
}
if ( AnalogValues[ANALOG_MOVE_UP] > 0.5f ) {
control_move |= 1<<CONTROL_MOVE_UP;
}
if ( AnalogValues[ANALOG_MOVE_UP] < -0.5f ) {
control_move |= 1<<CONTROL_MOVE_DOWN;
}
if ( AnalogValues[ANALOG_TURN_LEFT] > 0.5f ) {
control_move |= 1<<CONTROL_TURN_LEFT;
}
if ( AnalogValues[ANALOG_TURN_LEFT] < -0.5f ) {
control_move |= 1<<CONTROL_TURN_RIGHT;
}
packet.Add( control_move, BITPACK_CONTROL_MOVES_CS);
#endif
}
//-----------------------------------------------------------------------------
void ControlClass::Import_Sc(BitStreamClass & packet)
{
packet.Get(ContinuousBooleanBits, BITPACK_CONTINUOUS_BOOLEAN_BITS);
#if 01
packet.Get(AnalogValues[ANALOG_MOVE_FORWARD], BITPACK_ANALOG_VALUES);
packet.Get(AnalogValues[ANALOG_MOVE_LEFT], BITPACK_ANALOG_VALUES);
packet.Get(AnalogValues[ANALOG_MOVE_UP], BITPACK_ANALOG_VALUES);
packet.Get(AnalogValues[ANALOG_TURN_LEFT], BITPACK_ANALOG_VALUES);
#else
int control_move;
packet.Get( control_move, BITPACK_CONTROL_MOVES_SC);
AnalogValues[ANALOG_MOVE_FORWARD] = 0.0f;
AnalogValues[ANALOG_MOVE_LEFT] = 0.0f;
AnalogValues[ANALOG_MOVE_UP] = 0.0f;
if ( control_move & (1<<CONTROL_MOVE_FORWARD) ) {
AnalogValues[ANALOG_MOVE_FORWARD] = 1.0f;
}
if ( control_move & (1<<CONTROL_MOVE_BACKWARD) ) {
AnalogValues[ANALOG_MOVE_FORWARD] = -1.0f;
}
if ( control_move & (1<<CONTROL_MOVE_LEFT) ) {
AnalogValues[ANALOG_MOVE_LEFT] = 1.0f;
}
if ( control_move & (1<<CONTROL_MOVE_RIGHT) ) {
AnalogValues[ANALOG_MOVE_LEFT] = -1.0f;
}
if ( control_move & (1<<CONTROL_MOVE_UP) ) {
AnalogValues[ANALOG_MOVE_UP] = 1.0f;
}
if ( control_move & (1<<CONTROL_MOVE_DOWN) ) {
AnalogValues[ANALOG_MOVE_UP] = -1.0f;
}
/* if ( control_move & (1<<CONTROL_TURN_LEFT) ) {
AnalogValues[ANALOG_TURN_LEFT] = 1.0f;
}
if ( control_move & (1<<CONTROL_TURN_RIGHT) ) {
AnalogValues[ANALOG_TURN_LEFT] = -1.0f;
}*/
#endif
for (int i = 0; i < ANALOG_CONTROL_COUNT; i++) {
if (fabs(AnalogValues[i]) < 0.005) {
//
// The code elsewhere has no tolerance for precision error on this
// value around zero...
//
AnalogValues[i] = 0;
}
}
}
//-----------------------------------------------------------------------------
void ControlClass::Export_Sc(BitStreamClass & packet)
{
packet.Add(ContinuousBooleanBits, BITPACK_CONTINUOUS_BOOLEAN_BITS);
#if 01
packet.Add(AnalogValues[ANALOG_MOVE_FORWARD], BITPACK_ANALOG_VALUES);
packet.Add(AnalogValues[ANALOG_MOVE_LEFT], BITPACK_ANALOG_VALUES);
packet.Add(AnalogValues[ANALOG_MOVE_UP], BITPACK_ANALOG_VALUES);
packet.Add(AnalogValues[ANALOG_TURN_LEFT], BITPACK_ANALOG_VALUES);
#else
int control_move = 0;
if ( AnalogValues[ANALOG_MOVE_FORWARD] > 0.5f ) {
control_move |= 1<<CONTROL_MOVE_FORWARD;
}
if ( AnalogValues[ANALOG_MOVE_FORWARD] < -0.5f ) {
control_move |= 1<<CONTROL_MOVE_BACKWARD;
}
if ( AnalogValues[ANALOG_MOVE_LEFT] > 0.5f ) {
control_move |= 1<<CONTROL_MOVE_LEFT;
}
if ( AnalogValues[ANALOG_MOVE_LEFT] < -0.5f ) {
control_move |= 1<<CONTROL_MOVE_RIGHT;
}
if ( AnalogValues[ANALOG_MOVE_UP] > 0.5f ) {
control_move |= 1<<CONTROL_MOVE_UP;
}
if ( AnalogValues[ANALOG_MOVE_UP] < -0.5f ) {
control_move |= 1<<CONTROL_MOVE_DOWN;
}
/* if ( AnalogValues[ANALOG_TURN_LEFT] > 0.5f ) {
control_move |= 1<<CONTROL_TURN_LEFT;
}
if ( AnalogValues[ANALOG_TURN_LEFT] < -0.5f ) {
control_move |= 1<<CONTROL_TURN_RIGHT;
}*/
packet.Add( control_move, BITPACK_CONTROL_MOVES_SC);
#endif
}
//-----------------------------------------------------------------------------
/*
float ControlClass::Get_Clamp(AnalogControl control)
{
//
// This will definitely need improving...
//
float clamp;
switch (control) {
case ANALOG_MOVE_FORWARD :
clamp = Input::Get_Clamp(INPUT_FUNCTION_RUN_FORWARD);
break;
case ANALOG_MOVE_LEFT :
clamp = Input::Get_Clamp(INPUT_FUNCTION_RUN_LEFT);
break;
case ANALOG_MOVE_UP :
clamp = Input::Get_Clamp(INPUT_FUNCTION_RUN_FORWARD);
break;
case ANALOG_TURN_LEFT :
clamp = Input::Get_Clamp(INPUT_FUNCTION_TURN_LEFT);
break;
case ANALOG_WEAPON_UP :
clamp = Input::Get_Clamp(INPUT_FUNCTION_WEAPON_UP);
break;
case ANALOG_WEAPON_LEFT :
// clamp = 1.0f;
clamp = Input::Get_Clamp(INPUT_FUNCTION_WEAPON_LEFT);
break;
default:
WWASSERT(0);
}
WWASSERT(clamp > 0);
return clamp;
}
*/
/*
BYTE ControlClass::Scale_Analog(float clamp, float unscaled)
{
WWASSERT(unscaled > -clamp - WWMATH_EPSILON);
WWASSERT(unscaled < +clamp + WWMATH_EPSILON);
return (BYTE) (255 * WWMath::Clamp((unscaled + clamp) / (2 * clamp)));
}
float ControlClass::Unscale_Analog(float clamp, BYTE scaled)
{
float unscaled;
if (scaled == 127) { // scaling perturbs zero, special-case it
unscaled = 0;
} else {
unscaled = scaled / 255.0f * 2 * clamp - clamp;
}
WWASSERT(unscaled > -clamp - WWMATH_EPSILON);
WWASSERT(unscaled < +clamp + WWMATH_EPSILON);
return unscaled;
}
*/
void ControlClass::Set_Boolean( BooleanControl bcontrol, bool state )
{
int control = bcontrol;
if ( control >= BOOLEAN_CONTINUOUS_FIRST ) {
control -= BOOLEAN_CONTINUOUS_FIRST;
if (state) ContinuousBooleanBits |= (1 << control);
else ContinuousBooleanBits &= ~(1 << control);
PendingContinuousBooleanBits |= ContinuousBooleanBits;
} else {
control -= BOOLEAN_ONE_TIME_FIRST;
if (state) OneTimeBooleanBits |= (1 << control);
else OneTimeBooleanBits &= ~(1 << control);
PendingOneTimeBooleanBits |= OneTimeBooleanBits;
}
}
bool ControlClass::Get_Boolean( BooleanControl bcontrol )
{
int control = bcontrol;
if ( control >= BOOLEAN_CONTINUOUS_FIRST ) {
control -= BOOLEAN_CONTINUOUS_FIRST;
return ( ContinuousBooleanBits & (1 << control ) ) ? true : false;
} else {
control -= BOOLEAN_ONE_TIME_FIRST;
return ( OneTimeBooleanBits & (1 << control ) ) ? true : false;
}
}
void ControlClass::Set_Precision(void)
{
cEncoderList::Set_Precision(BITPACK_ONE_TIME_BOOLEAN_BITS, NUM_BOOLEAN_ONE_TIME);
cEncoderList::Set_Precision(BITPACK_CONTINUOUS_BOOLEAN_BITS, NUM_BOOLEAN_CONTINUOUS);
cEncoderList::Set_Precision(BITPACK_CONTROL_MOVES_CS, CONTROL_TURN_RIGHT+1); // 8
cEncoderList::Set_Precision(BITPACK_CONTROL_MOVES_SC, CONTROL_MOVE_DOWN+1); // 6
//
// TSS: I think that analog values are within this range, except for
// DEBUG_RAPID_MOVE...
//
cEncoderList::Set_Precision(BITPACK_ANALOG_VALUES, -1.0, 1.0, 0.01);
/*
//
// Proof that zero does not map to zero...
//
cPacket test;
float zero = 0.0f;
test.Add(zero, BITPACK_ANALOG_VALUES);
float zero2 = -999;
test.Get(zero2, BITPACK_ANALOG_VALUES);
*/
}