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