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

525 lines
13 KiB
C++

/*
** 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/>.
*/
/***********************************************************************************************
*** 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/messagewindow.cpp $*
* *
* Author:: Patrick Smith *
* *
* $Modtime:: 1/07/02 10:43a $*
* *
* $Revision:: 19 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "messagewindow.h"
#include "assetmgr.h"
#include "texture.h"
#include "font3d.h"
#include "objectives.h"
#include "translatedb.h"
#include "scene.h"
#include "timemgr.h"
#include "assets.h"
#include "globalsettings.h"
#include "smartgameobj.h"
#include "evasettings.h"
#include "soldier.h"
#include "dynamicspeechanim.h"
#include "combat.h"
#include "camera.h"
#include "scene.h"
#include "ww3d.h"
#include "wwmemlog.h"
////////////////////////////////////////////////////////////////
// Constants
////////////////////////////////////////////////////////////////
static const char *FONT_NAME = "FONT6X8.TGA";
static const char *HEADER_FONT_NAME = "FONT8X8.TGA";
////////////////////////////////////////////////////////////////
//
// MessageWindowClass
//
////////////////////////////////////////////////////////////////
MessageWindowClass::MessageWindowClass (void) :
TextWindow (NULL),
DecayTime (6000),
Scene (NULL),
Camera (NULL),
HeadModel (NULL),
IsRectangleDirty (true)
{
MessageLog.Set_Growth_Step (1000);
MessageLogColor.Set_Growth_Step (1000);
return ;
}
////////////////////////////////////////////////////////////////
//
// ~MessageWindowClass
//
////////////////////////////////////////////////////////////////
MessageWindowClass::~MessageWindowClass (void)
{
REF_PTR_RELEASE (Scene);
REF_PTR_RELEASE (Camera);
return ;
}
////////////////////////////////////////////////////////////////
//
// Shutdown
//
////////////////////////////////////////////////////////////////
void
MessageWindowClass::Shutdown (void)
{
if (TextWindow != NULL) {
delete TextWindow;
TextWindow = NULL;
}
if (HeadModel != NULL) {
HeadModel->Remove ();
}
REF_PTR_RELEASE (HeadModel);
Clear_Log ();
return ;
}
////////////////////////////////////////////////////////////////
//
// Initialize
//
////////////////////////////////////////////////////////////////
void
MessageWindowClass::Initialize (void)
{
WWMEMLOG(MEM_GAMEDATA);
//
// Allocate the new text window
//
TextWindow = new TextWindowClass;
EvaSettingsDefClass *settings = EvaSettingsDefClass::Get_Instance ();
//
// Configure the backdrop for the text window
//
CurrentRect = settings->Get_Messages_Screen_Rect ();
CurrentRect.Bottom = CurrentRect.Top + 1;
TextWindow->Set_Backdrop ("hud_6x4_Messages.tga", CurrentRect,
settings->Get_Messages_Texture_Size (), settings->Get_Messages_Endcap_Rect (),
settings->Get_Messages_Fadeout_Rect (), settings->Get_Messages_Background_Rect ());
//
// Configure the area where text can be displayed in the window
//
RectClass text_rect = settings->Get_Messages_Text_Rect ();
text_rect.Bottom = text_rect.Top + 1;
TextWindow->Set_Text_Area (text_rect);
//
// Configure the fonts for the window
//
TextWindow->Set_Heading_Font (HEADER_FONT_NAME);
TextWindow->Set_Text_Font (FONT_NAME);
//
// Configure the columns
//
TextWindow->Add_Column (L"", 1.0F, Vector3 (1, 1, 1));
TextWindow->Display_Columns (false);
//
// Configure the icon renderer
//
//IconRenderer.Reset ();
//IconRenderer.Set_Hidden (true);
//IconRenderer.Set_Coordinate_Range (Render2DClass::Get_Screen_Resolution ());
//
// Create a scene to use for the head model
//
Scene = new SimpleSceneClass;
Scene->Set_Ambient_Light(Vector3(1,1,1));
//
// Create a camera to use in the "head-scene"
//
Camera = new CameraClass ();
Camera->Set_Position (Vector3 (0, 0, 2.0F));
Camera->Set_View_Plane (DEG_TO_RADF (107.0), DEG_TO_RADF (74.0));
Camera->Set_Clip_Planes (0.1F, 100.0F);
Camera->Set_Projection_Type (CameraClass::ORTHO);
//
// Lookup the head model we'll use for conversations
//
//HeadModel = WW3DAssetManager::Get_Instance ()->Create_Render_Obj ("CX_HAVOC_HEAD");
if (HeadModel != NULL) {
HeadModel->Set_Hidden (true);
//
// Position the head model
//
Matrix3D tm (1);
tm.Rotate_Z (DEG_TO_RADF (90));
tm.Rotate_X (DEG_TO_RADF (90));
tm.Set_Translation (Vector3 (-1.22F, 0.53F, 0));
HeadModel->Set_Transform (tm);
//
// Add the head model to the scene
//
Scene->Add_Render_Object (HeadModel);
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Render
//
////////////////////////////////////////////////////////////////
void
MessageWindowClass::Render (void)
{
WWMEMLOG(MEM_GAMEDATA);
//
// Update the window rectangle as necessary
//
if (IsRectangleDirty) {
Update_Window_Rectangle ();
}
if (TextWindow != NULL) {
TextWindow->Render ();
}
//IconRenderer.Render ();
WW3D::Render (Scene, Camera);
return ;
}
////////////////////////////////////////////////////////////////
//
// On_Frame_Update
//
////////////////////////////////////////////////////////////////
void
MessageWindowClass::On_Frame_Update (void)
{
WWMEMLOG(MEM_GAMEDATA);
if (TextWindow == NULL || TextWindow->Is_Displayed () == false) {
return ;
}
if (TextWindow->Get_Item_Count () == 0) {
TextWindow->Display (false);
//IconRenderer.Set_Hidden (true);
if (HeadModel != NULL) {
HeadModel->Set_Hidden (true);
}
Reset_Current_Rect ();
} else {
int items_to_remove = TextWindow->Get_Item_Count () - TextWindow->Get_Display_Count ();
//
// Remove messages from the top of the list if we have more then we
// can display
//
for (int index = 0; index < items_to_remove; index ++) {
TextWindow->Delete_Item (0);
}
//
// Decay the entries
//
for (index = TextWindow->Get_Item_Count () - 1; index >= 0; index --) {
//
// Decay the time remaining on this message
//
int time_left = (int)TextWindow->Get_Item_Data (index);
time_left -= TimeManager::Get_Frame_Ticks ();
TextWindow->Set_Item_Data (index, (uint32)time_left);
//
// Should we remove this message?
//
if (time_left <= 0) {
TextWindow->Delete_Item (index);
}
}
}
TextWindow->On_Frame_Update ();
return ;
}
////////////////////////////////////////////////////////////////
//
// Add_Message
//
////////////////////////////////////////////////////////////////
void
MessageWindowClass::Add_Message
(
const WideStringClass & message,
const Vector3 & color,
SmartGameObj * game_obj,
float decay_time
)
{
WWMEMLOG(MEM_GAMEDATA);
if (TextWindow == NULL) {
return ;
}
//
// Determine how long we should display the message for...
//
int decay_time_in_ms = DecayTime;
if (decay_time != 0) {
decay_time_in_ms = int(decay_time * 1000);
}
//
// Add the message to the end of the list
//
if (message.Get_Length () > 0) {
int item_index = TextWindow->Insert_Item (TextWindow->Get_Item_Count (), message);
if (item_index != -1) {
TextWindow->Set_Item_Color (item_index, 0, color);
TextWindow->Set_Item_Data (item_index, decay_time_in_ms);
}
}
//
// Resize the window as necessary
//
Update_Window_Rectangle ();
//
// Make sure the window is displayed
//
if (message.Get_Length () > 0) {
TextWindow->Display (true);
}
//
// Get the name of the icon file we'll use
//
StringClass filename("hud_6x4_icon_default.tga",true);
if (game_obj != NULL) {
Strip_Path_From_Filename (filename, game_obj->Get_Info_Icon_Texture_Filename ());
//
// Try to play an animation on the head model
//
if (HeadModel != NULL) {
SoldierGameObj *soldier = game_obj->As_SoldierGameObj ();
if (soldier != NULL) {
DynamicSpeechAnimClass *speech_anim = soldier->Get_Facial_Anim ();
if (speech_anim != NULL) {
HeadModel->Set_Animation( speech_anim, 0, RenderObjClass::ANIM_MODE_ONCE );
}
}
}
}
//
// Configure the icon renderer
//
//IconRenderer.Reset ();
//IconRenderer.Set_Hidden (false);
if (HeadModel != NULL) {
HeadModel->Set_Hidden (false);
}
//
// Log the message
//
MessageLog.Add (message);
MessageLogColor.Add (color);
//
// Calculate the display rectangle of the icon
//
/*const HUDGlobalSettingsDef *hud_settings = HUDGlobalSettingsDef::Get_Instance ();
RectClass icon_rect (Vector2 (0, 0), hud_settings->TargetIconSize);
icon_rect += Render2DClass::Get_Screen_Resolution().Upper_Left () + settings->Get_Messages_Icon_Position ();*/
//
// Build the icon mesh
//
//IconRenderer.Set_Texture ( filename );
//IconRenderer.Add_Quad (icon_rect, 0xFFFFFFFF);
return ;
}
////////////////////////////////////////////////////////////////
//
// Update_Window_Rectangle
//
////////////////////////////////////////////////////////////////
void
MessageWindowClass::Update_Window_Rectangle (void)
{
//
// Get the dimensions of the text window
//
EvaSettingsDefClass *settings = EvaSettingsDefClass::Get_Instance ();
if (settings == NULL || TextWindow == NULL) {
return;
}
WWASSERT(settings != NULL);
RectClass screen_rect = settings->Get_Messages_Screen_Rect ();
RectClass text_rect = settings->Get_Messages_Text_Rect ();
float top_border = text_rect.Top - screen_rect.Top;
float bottom_border = screen_rect.Bottom - text_rect.Bottom;
float vert_border = top_border + bottom_border;
//
// Resize the area (if needs be)
//
WWASSERT(TextWindow != NULL);
float total_height = TextWindow->Get_Total_Display_Height ();
if (IsRectangleDirty || (total_height > (CurrentRect.Height () - vert_border))) {
CurrentRect.Bottom = WWMath::Clamp (CurrentRect.Top + total_height + vert_border, 0, screen_rect.Bottom);
//
// Resize the backdrop area
//
TextWindow->Set_Backdrop ("hud_6x4_Messages.tga", CurrentRect,
settings->Get_Messages_Texture_Size (), settings->Get_Messages_Endcap_Rect (),
settings->Get_Messages_Fadeout_Rect (), settings->Get_Messages_Background_Rect ());
//
// Resize the text area
//
text_rect.Top = CurrentRect.Top + top_border;
text_rect.Bottom = CurrentRect.Bottom - bottom_border;
TextWindow->Set_Text_Area (text_rect);
}
IsRectangleDirty = false;
return ;
}
////////////////////////////////////////////////////////////////
//
// Clear
//
////////////////////////////////////////////////////////////////
void
MessageWindowClass::Clear (void)
{
if (TextWindow != NULL) {
TextWindow->Delete_All_Items ();
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Force_Display
//
////////////////////////////////////////////////////////////////
void
MessageWindowClass::Force_Display (bool onoff)
{
if (TextWindow != NULL) {
TextWindow->Display (onoff);
}
//IconRenderer.Set_Hidden (!onoff);
if (HeadModel != NULL) {
HeadModel->Set_Hidden (!onoff);
}
Reset_Current_Rect ();
return ;
}
////////////////////////////////////////////////////////////////
//
// Has_Data
//
////////////////////////////////////////////////////////////////
bool
MessageWindowClass::Has_Data (void) const
{
return (TextWindow != NULL && TextWindow->Get_Item_Count () > 0);
}
////////////////////////////////////////////////////////////////
//
// Reset_Current_Rect
//
////////////////////////////////////////////////////////////////
void
MessageWindowClass::Reset_Current_Rect (void)
{
EvaSettingsDefClass *settings = EvaSettingsDefClass::Get_Instance ();
//
// Shrink the rectangle so its only 1 pixel high (this will force
// it to grow to the right size later on).
//
CurrentRect = settings->Get_Messages_Screen_Rect ();
CurrentRect.Bottom = CurrentRect.Top + 1;
return ;
}