/*
** 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 .
*/
/***********************************************************************************************
*** 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
#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< 0.5f ) {
control_move |= 1< 0.5f ) {
control_move |= 1< 0.5f ) {
control_move |= 1< 0.5f ) {
control_move |= 1< 0.5f ) {
control_move |= 1< 0.5f ) {
control_move |= 1< 0.5f ) {
control_move |= 1< 0.5f ) {
control_move |= 1< 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);
*/
}