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/weaponbag.cpp

501 lines
13 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/weaponbag.cpp $*
* *
* $Author:: Tom_s $*
* *
* $Modtime:: 1/02/02 4:21p $*
* *
* $Revision:: 55 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "weaponbag.h"
#include "weapons.h"
#include "debug.h"
#include "weaponmanager.h"
#include "wwpacket.h"
#include "armedgameobj.h"
#include "inventory.h"
/*
**
*/
WeaponBagClass::WeaponBagClass( ArmedGameObj * owner ) :
Owner( owner ),
WeaponIndex( 0 ),
IsChanged( true ),
HUDIsChanged( true )
{
Mark_Owner_Dirty();
WeaponList.Add( NULL ); // Index 0 is no weapon
}
WeaponBagClass::~WeaponBagClass( void )
{
while ( WeaponList.Count() ) {
delete WeaponList[0];
WeaponList.Delete( 0 );
}
}
/*
** WeaponBagClass Save and Load
*/
enum {
CHUNKID_VARIABLES = 921991503,
CHUNKID_WEAPON_LIST,
CHUNKID_WEAPON_ENTRY,
MICROCHUNKID_WEAPON_INDEX = 1,
};
bool WeaponBagClass::Save( ChunkSaveClass & csave )
{
int i;
csave.Begin_Chunk( CHUNKID_VARIABLES );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_WEAPON_INDEX, WeaponIndex );
csave.End_Chunk();
csave.Begin_Chunk( CHUNKID_WEAPON_LIST );
for( i = 1; i < WeaponList.Count(); i++ ) {
csave.Begin_Chunk( CHUNKID_WEAPON_ENTRY );
WeaponList[i]->Save( csave );
csave.End_Chunk();
}
csave.End_Chunk();
// Don't need to save Owner or IsChanged;
return true;
}
bool WeaponBagClass::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_WEAPON_INDEX, WeaponIndex );
default:
Debug_Say(("Unhandled Micro Chunk:%d File:%s Line:%d\r\n",cload.Cur_Micro_Chunk_ID(),__FILE__,__LINE__));
break;
}
cload.Close_Micro_Chunk();
}
break;
case CHUNKID_WEAPON_LIST:
WWASSERT( WeaponList.Count() == 1 );
while (cload.Open_Chunk()) {
WWASSERT( cload.Cur_Chunk_ID() == CHUNKID_WEAPON_ENTRY );
WeaponClass *weapon = new WeaponClass;
weapon->Load( cload );
WeaponList.Add( weapon );
cload.Close_Chunk();
}
break;
default:
Debug_Say(("Unhandled Chunk:%d File:%s Line:%d\r\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__));
break;
}
cload.Close_Chunk();
}
IsChanged = true;
HUDIsChanged = true;
return true;
}
/*
**
*/
bool WeaponBagClass::Is_Weapon_Owned( int weapon_id )
{
WeaponClass * weapon = Find_Weapon( WeaponManager::Find_Weapon_Definition( weapon_id ) );
return ( weapon != NULL && weapon->Does_Weapon_Exist() );
}
bool WeaponBagClass::Is_Ammo_Full( int weapon_id )
{
WeaponClass * weapon = Find_Weapon( WeaponManager::Find_Weapon_Definition( weapon_id ) );
return weapon && weapon->Is_Ammo_Maxed();
}
/*
**
*/
void WeaponBagClass::Remove_Weapon( int index )
{
//
// Simply destroy the weapon if its in our list
//
if ( index >= 0 && index < WeaponList.Count() ) {
delete WeaponList[index];
WeaponList.Delete( index );
}
return ;
}
/*
**
*/
void WeaponBagClass::Clear_Weapons( void )
{
// find the next existing weapons
while ( WeaponList.Count() > 1 ) {
int index = WeaponList.Count()-1;
delete WeaponList[index];
WeaponList.Delete( index );
}
Select_Index( 0 );
return ;
}
/*
**
*/
WeaponClass * WeaponBagClass::Add_Weapon( const WeaponDefinitionClass * def, int rounds, bool give_weapon )
{
if ( def == NULL ) {
Debug_Say(( "Failed to create Weapon\n" ));
return NULL;
}
WeaponClass * weapon = Find_Weapon( def );
if ( weapon == NULL ) {
// Debug_Say(( "Adding new weapon %s\n", weapon->Get_Name() ));
weapon = new WeaponClass( def );
if ( weapon ) {
weapon->Set_Owner( Owner );
weapon->Add_Rounds( rounds );
weapon->Set_Weapon_Exists( give_weapon ); // Assume it doesn't exist
// add this weapon to the weapon list in order (0 at end)
int index;
for ( index = 1; index < WeaponList.Count(); index++ ) {
if ( WeaponList[ index ]->Get_Key_Number() > weapon->Get_Key_Number() ) {
break;
}
}
if ( WeaponIndex >= index ) {
WeaponIndex++;
}
WeaponList.Insert( index, weapon );
IsChanged = true;
HUDIsChanged = true;
#if 0 // Don't auto select
bool use = true;
for ( int i = 1; i < WeaponList.Count(); i++ ) {
if ( i != index && WeaponList[ i ]->Does_Weapon_Exist() ) {
use = false;
}
}
// If no current weapon, make this weapon current
if ( give_weapon && use ) {
// Debug_Say(( "Commando selecting first weapon %s\n", weapon->Get_Name() ));
Select_Index( index );
}
#endif
Mark_Owner_Dirty();
}
} else {
if ( give_weapon ) { // Make sure we have it if we are supposed to
weapon->Set_Weapon_Exists( true );
Mark_Owner_Dirty();
}
weapon->Add_Rounds( rounds ); // if we already have this weapon, just take the ammo
if ( rounds != 0 ) {
Mark_Owner_Dirty();
}
}
return weapon;
}
WeaponClass * WeaponBagClass::Add_Weapon( const char *weapon_name, int rounds, bool give_weapon )
{
return Add_Weapon( WeaponManager::Find_Weapon_Definition( weapon_name ), rounds, give_weapon );
}
WeaponClass * WeaponBagClass::Add_Weapon( int id, int rounds, bool give_weapon )
{
return Add_Weapon( WeaponManager::Find_Weapon_Definition( id ), rounds, give_weapon );
}
WeaponClass * WeaponBagClass::Get_Next_Weapon( void )
{
// find the next existing weapons
for ( int i = 0; i < WeaponList.Count(); i++ ) {
int index = ( WeaponIndex + i + 1 ) % WeaponList.Count();
// BMG remove no weapon slot
// if ( WeaponList[ index ] == NULL || WeaponList[ index ]->Does_Weapon_Exist() ) {
if ( WeaponList[ index ] != NULL && WeaponList[ index ]->Does_Weapon_Exist() ) {
return WeaponList[ index ];
}
}
return NULL;
}
void WeaponBagClass::Select_Next( void )
{
// Find the next existing weapons
for ( int i = 1; i < WeaponList.Count(); i++ ) {
int index = ( WeaponIndex + i ) % WeaponList.Count();
// BMG remove no weapon slot
// if ( WeaponList[ index ] == NULL || WeaponList[ index ]->Does_Weapon_Exist() ) {
if ( WeaponList[ index ] != NULL && WeaponList[ index ]->Does_Weapon_Exist() ) {
Select_Index( index );
break;
}
}
}
void WeaponBagClass::Select_Prev( void )
{
// Find the next existing weapons
for ( int i = 1; i < WeaponList.Count(); i++ ) {
int index = ( WeaponIndex - i + WeaponList.Count()) % WeaponList.Count();
// BMG remove no weapon slot
// if ( WeaponList[ index ] == NULL || WeaponList[ index ]->Does_Weapon_Exist() ) {
if ( WeaponList[ index ] != NULL && WeaponList[ index ]->Does_Weapon_Exist() ) {
Select_Index( index );
break;
}
}
}
void WeaponBagClass::Select_Key_Number( int key_number )
{
if ( key_number == -1 ) {
Select_Index( 0 );
} else {
// Start from the current, find the next existing weapon with the right key_number
for ( int i = 1; i < WeaponList.Count(); i++ ) {
int index = ( WeaponIndex + i ) % WeaponList.Count();
if ( WeaponList[ index ] != NULL &&
WeaponList[ index ]->Does_Weapon_Exist() &&
(int)WeaponList[ index ]->Get_Key_Number() == key_number ) {
Select_Index( index );
break;
}
}
}
}
void WeaponBagClass::Select_Weapon_ID( int weapon_id )
{
for( int i = 1; i < WeaponList.Count(); i++ ) {
if ( WeaponList[i]->Get_ID() == weapon_id ) {
Select_Index ( i );
return;
}
}
}
void WeaponBagClass::Select_Weapon_Name( const char * name )
{
if ( ( name == NULL ) || ( *name == 0 ) ) {
Select_Index ( 0 );
} else {
for( int i = 1; i < WeaponList.Count(); i++ ) {
if ( strcmp( WeaponList[i]->Get_Name(), name ) == 0 ) {
Select_Index ( i );
return;
}
}
Debug_Say(( "Unable to select weapon %s\n", name ));
}
}
void WeaponBagClass::Select_Weapon( WeaponClass * weapon )
{
for( int i = 1; i < WeaponList.Count(); i++ ) {
if ( WeaponList[i] == weapon ) {
Select_Index ( i );
return;
}
}
}
void WeaponBagClass::Select_Index( int index )
{
if ( index >= WeaponList.Count() ) {
index = 0;
}
if ( WeaponIndex != index ) {
if ( Get_Weapon() ) {
Get_Weapon()->Deselect();
}
WeaponIndex = index;
IsChanged = true;
HUDIsChanged = true;
if ( Get_Weapon() ) {
Get_Weapon()->Select();
}
Mark_Owner_Dirty();
}
}
void WeaponBagClass::Deselect( void )
{
// Need to be able to tell client to put weapon away
Select_Index( 0 );
}
//-----------------------------------------------------------------------------
void WeaponBagClass::Import_Weapon_List(BitStreamClass & packet)
{
int weapon_count = packet.Get(weapon_count);
int weapon_id;
for (int weapon = 0; weapon < weapon_count; weapon++) {
weapon_id = packet.Get(weapon_id);
int total_rounds = packet.Get(total_rounds);
Add_Weapon(weapon_id, 0);
WeaponClass * weapon = NULL;
for( int i = 1; i < WeaponList.Count(); i++ ) {
if ( (int) WeaponList[i]->Get_Definition()->Get_ID() == weapon_id ) {
weapon = WeaponList[i];
}
}
if ( weapon != NULL ) {
weapon->Set_Total_Rounds( total_rounds );
}
}
}
//-----------------------------------------------------------------------------
void WeaponBagClass::Export_Weapon_List(BitStreamClass & packet)
{
packet.Add((int) (WeaponList.Count() - 1));
for( int i = 1; i < WeaponList.Count(); i++ ) {
packet.Add(WeaponList[i]->Get_ID());
packet.Add(WeaponList[i]->Get_Total_Rounds());
}
}
//-----------------------------------------------------------------------------
WeaponClass * WeaponBagClass::Find_Weapon( const WeaponDefinitionClass * def )
{
if ( def == NULL ) {
return NULL;
}
for( int i = 1; i < WeaponList.Count(); i++ ) {
if ( (unsigned)WeaponList[i]->Get_ID() == def->Get_ID() ) {
return WeaponList[i];
}
}
// Debug_Say(( "Didn't Find weapon %s\n", name ));
return NULL;
}
/*
**
*/
bool WeaponBagClass::Move_Contents( WeaponBagClass * source )
{
// Was anyhting actually moved?
bool moved = false;
// Move all the weapons and ammo from the source to me
// For each weapon in the source bag...
for( int i = 1; i < source->WeaponList.Count(); i++ ) {
WeaponClass * weapon = source->WeaponList[i];
// If I already have it,
WeaponClass * my_weapon = Find_Weapon( weapon->Get_Definition() );
if ( my_weapon ) {
// Copy the ammo and the weapon
if ( !my_weapon->Is_Ammo_Maxed() && weapon->Get_Total_Rounds() != 0 ) {
my_weapon->Add_Rounds( weapon->Get_Total_Rounds() );
moved = true;
}
if ( weapon->Does_Weapon_Exist() && !my_weapon->Does_Weapon_Exist() ) {
my_weapon->Set_Weapon_Exists( true );
moved = true;
}
// Debug_Say(( "Add %s %d\n", weapon->Get_Definition()->Get_Name(), weapon->Get_Total_Rounds() ));
} else {
// else, give it to me
Add_Weapon( weapon->Get_Definition(), weapon->Get_Total_Rounds(), weapon->Does_Weapon_Exist() );
if ( weapon->Does_Weapon_Exist() ) {
moved = true;
}
// Debug_Say(( "Give %s %d\n", weapon->Get_Definition()->Get_Name(), weapon->Get_Total_Rounds() ));
}
}
Mark_Owner_Dirty();
return moved;
}
/*
**
*/
void WeaponBagClass::Store_Inventory( InventoryClass * inventory )
{
for( int i = 1; i < WeaponList.Count(); i++ ) {
WeaponClass * weapon = WeaponList[i];
inventory->Add_Weapon( weapon->Get_ID(), weapon->Get_Total_Rounds(), weapon->Does_Weapon_Exist() );
}
}
/*
**
*/
void WeaponBagClass::Mark_Owner_Dirty( void )
{
if ( Owner != NULL ) {
Owner->Set_Object_Dirty_Bit( NetworkObjectClass::BIT_OCCASIONAL, true );
}
}