/* ** 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); */ }