source-engine/hammer/op_flags.cpp

317 lines
7.8 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements the spawnflags page of the Entity Properties dialog.
//
//=============================================================================//
#include "stdafx.h"
#include "hammer.h"
#include "OP_Flags.h"
#include "OP_Entity.h"
#include "ObjectProperties.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
/////////////////////////////////////////////////////////////////////////////
// COP_Flags property page
IMPLEMENT_DYNCREATE(COP_Flags, CObjectPage)
COP_Flags::COP_Flags() : CObjectPage(COP_Flags::IDD)
{
//{{AFX_DATA_INIT(COP_Flags)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_pEditObjectRuntimeClass = RUNTIME_CLASS(editCEditGameClass);
m_nNumSelectedObjects = 0;
m_pEntityPage = NULL;
}
COP_Flags::~COP_Flags()
{
}
void COP_Flags::SetEntityPage( COP_Entity *pPage )
{
m_pEntityPage = pPage;
}
void COP_Flags::DoDataExchange(CDataExchange* pDX)
{
CObjectPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(COP_Flags)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(COP_Flags, CObjectPage)
//{{AFX_MSG_MAP(COP_Flags)
ON_CLBN_CHKCHANGE(IDC_CHECKLIST, OnCheckListChange)
ON_WM_SIZE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// COP_Flags message handlers
void COP_Flags::UpdateData( int Mode, PVOID pData, bool bCanEdit )
{
__super::UpdateData( Mode, pData, bCanEdit );
if(!IsWindow(m_hWnd) || !pData)
{
return;
}
CEditGameClass *pObj = (CEditGameClass*) pData;
if (Mode == LoadFirstData)
{
UpdateForClass(pObj);
}
else if (Mode == LoadData)
{
MergeForClass(pObj);
}
CreateCheckList();
m_CheckList.EnableWindow( m_bCanEdit ? TRUE : FALSE );
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool COP_Flags::SaveData(void)
{
if (!IsWindow(m_hWnd))
{
return(false);
}
//
// Apply the dialog data to all the objects being edited.
//
FOR_EACH_OBJ( *m_pObjectList, pos )
{
CMapClass *pObject = m_pObjectList->Element(pos);
CEditGameClass *pEdit = dynamic_cast <CEditGameClass *>(pObject);
Assert(pEdit != NULL);
if ( pEdit != NULL )
{
for ( int i = 0; i < m_CheckListItems.Count(); i++ )
{
CheckListItem currentItem = m_CheckListItems.Element( i );
// don't save tri-stated bit
if ( m_CheckList.GetCheck(i) != 2 )
{
pEdit->SetSpawnFlag( currentItem.nItemBit, m_CheckList.GetCheck(i) ? TRUE : FALSE );
}
}
}
}
return(true);
}
//-----------------------------------------------------------------------------
// Purpose: This function is used to initialize the flag checklist.
// It is called to place all the flags belonging to the first
// selected object into the temporary CheckListItems vector
//-----------------------------------------------------------------------------
void COP_Flags::UpdateForClass(CEditGameClass* pObj)
{
extern GameData *pGD;
GDclass * pClass = pGD->ClassForName(pObj->GetClassName());
if(!IsWindow(m_hWnd))
return;
m_nNumSelectedObjects = 1;
m_CheckListItems.RemoveAll();
if(pClass)
{
GDinputvariable *pVar = pClass->VarForName("spawnflags");
if (pVar)
{
int nItems = pVar->GetFlagCount();
for ( int i = 0; i < nItems; i++ )
{
CheckListItem newItem;
newItem.nItemBit = pVar->GetFlagMask( i );
newItem.pszItemString = pVar->GetFlagCaption( i );
newItem.state = pObj->GetSpawnFlag( newItem.nItemBit ) ? 1 : 0;
m_CheckListItems.AddToTail( newItem );
}
}
}
Assert( m_CheckListItems.Count() <= 32 );
for ( int i = 0; i < 32; i++ )
{
int nBitPattern = 1 << i;
// is spawnflag for this bit set?
if ( pObj->GetSpawnFlag(nBitPattern) )
{
int j;
// then see if its allowed to be
for ( j = 0; j < m_CheckListItems.Count(); j ++ )
{
int nCheckListPattern = m_CheckListItems.Element(j).nItemBit;
if ( nCheckListPattern == nBitPattern )
break;
}
// we fail to find it?
if ( j == m_CheckListItems.Count() )
{
CheckListItem newItem;
newItem.nItemBit = nBitPattern;
newItem.pszItemString = "????";
newItem.state = 1;
m_CheckListItems.AddToTail( newItem );
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: This function is called to combine flags when multiple objects are selected
// It removes flags from the CheckListItem vector that are not present in all selected objects
//-----------------------------------------------------------------------------
void COP_Flags::MergeForClass(CEditGameClass* pObj)
{
extern GameData *pGD;
GDclass * pClass = pGD->ClassForName(pObj->GetClassName());
if( !IsWindow(m_hWnd) )
return;
m_nNumSelectedObjects++;
if( pClass )
{
GDinputvariable *pVar = pClass->VarForName("spawnflags");
for ( int i = m_CheckListItems.Count() - 1; i >= 0; i-- )
{
bool bFound = false;
CheckListItem currentItem = m_CheckListItems.Element( i );
if ( pVar )
{
for ( int j = 0; j < pVar->GetFlagCount(); j++ )
{
CheckListItem newItem;
newItem.nItemBit = pVar->GetFlagMask(j);
newItem.pszItemString = pVar->GetFlagCaption(j);
if ( newItem == currentItem )
{
bFound = true;
int nNewState = pObj->GetSpawnFlag( newItem.nItemBit ) ? 1 : 0;
if ( currentItem.state != nNewState )
{
m_CheckListItems.Element( i ).state = 2;
}
break;
}
}
}
if ( !bFound )
{
m_CheckListItems.FastRemove( i );
}
}
}
Assert( m_CheckListItems.Count() <= 32 );
}
//-----------------------------------------------------------------------------
// Purpose: Creates the checklist by stepping through the CheckListItems vector that
// was created during Update/MergeForClass
//-----------------------------------------------------------------------------
void COP_Flags::CreateCheckList()
{
m_CheckList.ResetContent();
if ( m_nNumSelectedObjects > 1 )
{
m_CheckList.SetCheckStyle(BS_AUTO3STATE);
}
for ( int i = 0; i < m_CheckListItems.Count(); i++ )
{
CheckListItem newItem = m_CheckListItems.Element(i);
m_CheckList.InsertString(i, newItem.pszItemString);
m_CheckList.SetCheck(i, newItem.state);
}
}
void COP_Flags::OnUpdateSpawnFlags( unsigned long value )
{
for ( int i=0; i < m_CheckListItems.Count(); i++ )
{
CheckListItem &item = m_CheckListItems[i];
m_CheckList.SetCheck( i, (value & item.nItemBit) != 0 );
}
}
BOOL COP_Flags::OnInitDialog()
{
CObjectPage::OnInitDialog();
m_nNumSelectedObjects = 0;
// Subclass checklistbox
m_CheckList.SubclassDlgItem(IDC_CHECKLIST, this);
m_CheckList.SetCheckStyle(BS_AUTOCHECKBOX);
m_CheckList.ResetContent();
CAnchorDef anchorDefs[] =
{
CAnchorDef( IDC_CHECKLIST, k_eSimpleAnchorAllSides )
};
m_AnchorMgr.Init( GetSafeHwnd(), anchorDefs, ARRAYSIZE( anchorDefs ) );
return TRUE;
}
void COP_Flags::OnCheckListChange()
{
if ( !m_pEntityPage )
return;
unsigned long bitsSet = 0;
unsigned long triStateMask = 0;
// This is just like SaveData.. collect the state of all the checks.
for ( int i = 0; i < m_CheckListItems.Count(); i++ )
{
CheckListItem currentItem = m_CheckListItems.Element( i );
// If multiple of the selected entities have a different value for this flag,
// note that. The entity page will use triStateMask to denote flags that
// it should leave alone.
if ( m_CheckList.GetCheck(i) == 2 )
triStateMask |= currentItem.nItemBit;
else if ( m_CheckList.GetCheck( i ) )
bitsSet |= currentItem.nItemBit;
}
m_pEntityPage->OnUpdateSpawnFlags( triStateMask, bitsSet );
}
void COP_Flags::OnSize( UINT nType, int cx, int cy )
{
m_AnchorMgr.OnSize();
}