/* ** 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 . */ /*********************************************************************************************** *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** *********************************************************************************************** * * * Project Name : Combat * * * * $Archive:: /Commando/Code/Combat/conversation.cpp $* * * * Author:: Patrick Smith * * * * $Modtime:: 10/29/01 10:23p $* * * * $Revision:: 8 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "conversation.h" #include "chunkio.h" #include "soldier.h" //////////////////////////////////////////////////////////////// // Constants //////////////////////////////////////////////////////////////// enum { CHUNKID_BASE_CLASS = 0x08090315, CHUNKID_VARIABLES, CHUNKID_ORATOR, CHUNKID_REMARK }; enum { VARID_NAME = 0, VARID_ID, XXXX_VARID_REMARK, VARID_OLD_PTR, XXXXX_PLAYERTYPE, VARID_ISINNATE, VARID_PROBABILITY, VARID_AI_STATE, VARID_CATEGORY_ID, VARID_LOOKAT_OBJID, VARID_PRIORITY, VARID_MAXDIST, VARID_IS_INTERRUPTABLE, VARID_ISKEY }; //////////////////////////////////////////////////////////////// // // ConversationClass // //////////////////////////////////////////////////////////////// ConversationClass::ConversationClass (void) : ID (0), IsInnate (true), IsKey (false), Probability (1.0F), AIState (AI_STATE_IDLE), CategoryID (0), LookAtObjID (0), Priority (30), MaxDist (0), IsInterruptable (true) { return ; } //////////////////////////////////////////////////////////////// // // ConversationClass // //////////////////////////////////////////////////////////////// ConversationClass::ConversationClass (const ConversationClass &src) : ID (0), IsInnate (true), IsKey (false), Probability (1.0F), AIState (AI_STATE_IDLE), CategoryID (0), LookAtObjID (0), Priority (30), MaxDist (0), IsInterruptable (true) { (*this) = src; return ; } //////////////////////////////////////////////////////////////// // // ~ConversationClass // //////////////////////////////////////////////////////////////// ConversationClass::~ConversationClass (void) { Clear_Remarks (); Clear_Orators (); return ; } //////////////////////////////////////////////////////////////// // // operator= // //////////////////////////////////////////////////////////////// const ConversationClass & ConversationClass::operator= (const ConversationClass &src) { // // Start fresh // Clear_Remarks (); Clear_Orators (); // // Copy the simple data // Name = src.Name; ID = src.ID; LookAtObjID = src.LookAtObjID; Priority = src.Priority; MaxDist = src.MaxDist; IsInterruptable = src.IsInterruptable; // // Copy the remark list // for (int index = 0; index < src.RemarkList.Count (); index ++) { const ConversationRemarkClass &remark = src.RemarkList[index]; Add_Remark (remark); } // // Copy the orator list // for (index = 0; index < src.OratorList.Count (); index ++) { const OratorClass &orator = src.OratorList[index]; Add_Orator (orator); } return (*this); } //////////////////////////////////////////////////////////////// // // Clear_Orators // //////////////////////////////////////////////////////////////// void ConversationClass::Clear_Orators (void) { OratorList.Delete_All (); return ; } //////////////////////////////////////////////////////////////// // // Clear_Remarks // //////////////////////////////////////////////////////////////// void ConversationClass::Clear_Remarks (void) { RemarkList.Delete_All (); return ; } //////////////////////////////////////////////////////////////// // // Get_Orator_Count // //////////////////////////////////////////////////////////////// int ConversationClass::Get_Orator_Count (void) const { return OratorList.Count (); } //////////////////////////////////////////////////////////////// // // Add_Orator // //////////////////////////////////////////////////////////////// void ConversationClass::Add_Orator (const OratorClass &orator) { OratorList.Add (orator); return ; } //////////////////////////////////////////////////////////////// // // Add_Remark // //////////////////////////////////////////////////////////////// void ConversationClass::Add_Remark (const ConversationRemarkClass &remark) { RemarkList.Add (remark); return ; } //////////////////////////////////////////////////////////////// // // Get_Remark_Info // //////////////////////////////////////////////////////////////// bool ConversationClass::Get_Remark_Info (int index, ConversationRemarkClass &remark) { bool retval = false; WWASSERT (index >= 0 && index < RemarkList.Count ()); if (index >= 0 && index < RemarkList.Count ()) { // // Return the remark information to the caller // remark = RemarkList[index]; retval = true; } return retval; } //////////////////////////////////////////////////////////////// // // Save // //////////////////////////////////////////////////////////////// bool ConversationClass::Save (ChunkSaveClass &csave) { csave.Begin_Chunk (CHUNKID_VARIABLES); WRITE_MICRO_CHUNK_WWSTRING (csave, VARID_NAME, Name); WRITE_MICRO_CHUNK (csave, VARID_ID, ID); WRITE_MICRO_CHUNK (csave, VARID_ISINNATE, IsInnate); WRITE_MICRO_CHUNK (csave, VARID_ISKEY, IsKey); WRITE_MICRO_CHUNK (csave, VARID_PROBABILITY, Probability); WRITE_MICRO_CHUNK (csave, VARID_AI_STATE, AIState); WRITE_MICRO_CHUNK (csave, VARID_CATEGORY_ID, CategoryID); WRITE_MICRO_CHUNK (csave, VARID_LOOKAT_OBJID, LookAtObjID); WRITE_MICRO_CHUNK (csave, VARID_PRIORITY, Priority); WRITE_MICRO_CHUNK (csave, VARID_MAXDIST, MaxDist); WRITE_MICRO_CHUNK (csave, VARID_IS_INTERRUPTABLE, IsInterruptable); // // Save our current pointer so we can remap it on load // ConversationClass *old_ptr = this; WRITE_MICRO_CHUNK (csave, VARID_OLD_PTR, old_ptr); csave.End_Chunk (); // // Save the orator list // for (int index = 0; index < OratorList.Count (); index ++) { OratorClass &orator = OratorList[index]; // // Save this orator to its own chunk // csave.Begin_Chunk (CHUNKID_ORATOR); orator.Save (csave); csave.End_Chunk (); } // // Save the remark list // for (index = 0; index < RemarkList.Count (); index ++) { ConversationRemarkClass &remark = RemarkList[index]; // // Save this remark to its own chunk // csave.Begin_Chunk (CHUNKID_REMARK); remark.Save (csave); csave.End_Chunk (); } return true; } //////////////////////////////////////////////////////////////// // // Load // //////////////////////////////////////////////////////////////// bool ConversationClass::Load (ChunkLoadClass &cload) { OratorList.Resize (10); while (cload.Open_Chunk ()) { switch (cload.Cur_Chunk_ID ()) { case CHUNKID_VARIABLES: Load_Variables (cload); break; case CHUNKID_ORATOR: { OratorList.Add (OratorClass ()); OratorList[OratorList.Count () - 1].Load (cload); } break; case CHUNKID_REMARK: { ConversationRemarkClass remark; remark.Load (cload); RemarkList.Add (remark); } break; } cload.Close_Chunk (); } return true; } /////////////////////////////////////////////////////////////////////// // // Load_Variables // /////////////////////////////////////////////////////////////////////// void ConversationClass::Load_Variables (ChunkLoadClass &cload) { ConversationClass *old_ptr = NULL; // // Loop through all the microchunks that define the variables // while (cload.Open_Micro_Chunk ()) { switch (cload.Cur_Micro_Chunk_ID ()) { READ_MICRO_CHUNK_WWSTRING (cload, VARID_NAME, Name); READ_MICRO_CHUNK (cload, VARID_ID, ID); READ_MICRO_CHUNK (cload, VARID_OLD_PTR, old_ptr); READ_MICRO_CHUNK (cload, VARID_ISINNATE, IsInnate); READ_MICRO_CHUNK (cload, VARID_ISKEY, IsKey); READ_MICRO_CHUNK (cload, VARID_PROBABILITY, Probability); READ_MICRO_CHUNK (cload, VARID_AI_STATE, AIState); READ_MICRO_CHUNK (cload, VARID_CATEGORY_ID, CategoryID); READ_MICRO_CHUNK (cload, VARID_LOOKAT_OBJID, LookAtObjID); READ_MICRO_CHUNK (cload, VARID_PRIORITY, Priority); READ_MICRO_CHUNK (cload, VARID_MAXDIST, MaxDist); READ_MICRO_CHUNK (cload, VARID_IS_INTERRUPTABLE, IsInterruptable); // // Old-style remark (for backwards compatiblility) // case XXXX_VARID_REMARK: { struct { int OratorID; int TextID; } OldRemarkStruct; // // Read the old data from the chunk // cload.Read (&OldRemarkStruct, sizeof (OldRemarkStruct)); // // Convert the data // ConversationRemarkClass remark; remark.Set_Orator_ID (OldRemarkStruct.OratorID); remark.Set_Text_ID (OldRemarkStruct.TextID); // // Add this remark to our list // Add_Remark (remark); } break; } cload.Close_Micro_Chunk (); } // // Register our old pointer so other objects can safely remap to it // WWASSERT (old_ptr != NULL); SaveLoadSystemClass::Register_Pointer (old_ptr, this); return ; } /////////////////////////////////////////////////////////////////////// // // Get_Orator // /////////////////////////////////////////////////////////////////////// OratorClass * ConversationClass::Get_Orator (int index) { OratorClass *orator = NULL; if (index >= 0 && index < OratorList.Count ()) { orator = &OratorList[index]; } return orator; } /////////////////////////////////////////////////////////////////////// // // Find_Orator // /////////////////////////////////////////////////////////////////////// OratorClass * ConversationClass::Find_Orator (int orator_id) { OratorClass *orator = NULL; for (int index = 0; index < OratorList.Count (); index ++) { OratorClass *curr_orator = &OratorList[index]; // // Is this the orator we are looking for? // if (curr_orator->Get_ID () == orator_id) { orator = curr_orator; break; } } return orator; }