Files
Client/GameTools/WORLDCREATOR/PageTriggerContainer.cpp
LGram16 dd97ddec92 Restructure repository to include all source folders
Move git root from Client/ to src/ to track all source code:
- Client: Game client source (moved to Client/Client/)
- Server: Game server source
- GameTools: Development tools
- CryptoSource: Encryption utilities
- database: Database scripts
- Script: Game scripts
- rylCoder_16.02.2008_src: Legacy coder tools
- GMFont, Game: Additional resources

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 20:17:20 +09:00

808 lines
18 KiB
C++

// PageTriggerContainer.cpp : implementation file
//
#include "stdafx.h"
#include "worldcreator.h"
#include "PageTriggerContainer.h"
#include "resource.h"
#include "DlgTriggerPoint.h"
#include "DlgTriggerProperty.h"
#include "MainFrm.h"
#include "WorldCreatorView.h"
#include <BGMController.h>
#include <TriggerEvent.h>
#include <assert.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
typedef unsigned char byte;
/////////////////////////////////////////////////////////////////////////////
//
enum eNodeType
{
TYPE_CATEGORY = 0,
TYPE_TRIGGER = 1,
TYPE_POINTS = 2,
TYPE_POINT = 3,
TYPE_EVENTS = 4,
TYPE_EVENT = 5,
};
/////////////////////////////////////////////////////////////////////////////
//
struct SNodeData
{
union
{
struct
{
DWORD type : 4;
DWORD index1 : 14;
DWORD index2 : 14;
};
DWORD value;
};
operator DWORD() { return value; }
SNodeData();
SNodeData( eNodeType Type );
SNodeData( DWORD nodeValue );
SNodeData( int eventID, const char * szArg );
SNodeData( float x, float y, float z, long objID );
void Delete();
void GetPoint( float & x, float & y, float & z, long & objID ) const;
void GetEvent( int & eventID, char * szArg ) const;
void SetEvent( int eventID, const char * szArg );
bool operator=( const SNodeData & rhs ) const { return value == rhs.value; }
void Select() const;
};
/////////////////////////////////////////////////////////////////////////////
//
SNodeData::SNodeData()
: type( TYPE_CATEGORY )
, index1( 0 )
, index2( 0 )
{}
SNodeData::SNodeData( eNodeType Type )
: type( Type )
, index1( 0 )
, index2( 0 )
{
if( type == TYPE_TRIGGER )
{
CBGMController & BGMC = CBGMController::GetInstance();
index1 = BGMC.AddTrigger();
}
}
SNodeData::SNodeData( DWORD nodeValue )
: value( nodeValue )
{}
SNodeData::SNodeData( int eventID, const char * szArg )
: type( TYPE_EVENT )
{
CBGMController & BGMC = CBGMController::GetInstance();
index1 = BGMC.GetSelectTrigger();
index2 = BGMC.AddEvent( eventID, szArg );
}
SNodeData::SNodeData( float x, float y, float z, long objID )
: type( TYPE_POINT )
{
CBGMController & BGMC = CBGMController::GetInstance();
index1 = BGMC.GetSelectTrigger();
index2 = BGMC.AddPoint( x, y, z, objID );
}
void SNodeData::Delete()
{
CBGMController & BGMC = CBGMController::GetInstance();
switch( type )
{
case TYPE_TRIGGER :
BGMC.SelectTrigger( index1 );
BGMC.DeleteTrigger();
break;
case TYPE_CATEGORY :
case TYPE_POINTS :
case TYPE_EVENTS :
break;
case TYPE_POINT :
BGMC.SelectPoint( index1, index2 );
BGMC.DeletePoint();
break;
case TYPE_EVENT :
BGMC.SelectTrigger( index1 );
BGMC.DeleteEvent( index2 );
break;
}
}
void SNodeData::GetPoint( float & x, float & y, float & z, long & objID ) const
{
CBGMController & BGMC = CBGMController::GetInstance();
BGMC.SelectPoint( index1, index2 );
BGMC.GetPoint( x, y, z, objID );
}
void SNodeData::GetEvent( int & eventID, char * szArg ) const
{
CBGMController & BGMC = CBGMController::GetInstance();
BGMC.SelectTrigger( index1 );
BGMC.GetEvent( index2, eventID, szArg );
}
void SNodeData::SetEvent( int eventID, const char * szArg )
{
CBGMController & BGMC = CBGMController::GetInstance();
BGMC.SelectTrigger( index1 );
BGMC.SetEvent( index2, eventID, szArg );
}
void SNodeData::Select() const
{
CBGMController & BGMC = CBGMController::GetInstance();
if( type == TYPE_TRIGGER )
{
BGMC.SelectTrigger( index1 );
}
else if( type == TYPE_POINT )
{
BGMC.SelectPoint( index1, index2 );
}
}
/////////////////////////////////////////////////////////////////////////////
// CPageTriggerContainer property page
IMPLEMENT_DYNCREATE(CPageTriggerContainer, CPropertyPage)
CPageTriggerContainer::CPageTriggerContainer() : CPropertyPage(CPageTriggerContainer::IDD)
{
//{{AFX_DATA_INIT(CPageTriggerContainer)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
CPageTriggerContainer::~CPageTriggerContainer()
{
}
void CPageTriggerContainer::DoDataExchange(CDataExchange* pDX)
{
CPropertyPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CPageTriggerContainer)
DDX_Control(pDX, IDC_EDIT_EPSILON, m_editEpsilon);
DDX_Control(pDX, IDC_TREE1, m_Tree);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CPageTriggerContainer, CPropertyPage)
//{{AFX_MSG_MAP(CPageTriggerContainer)
ON_NOTIFY(NM_RCLICK, IDC_TREE1, OnRclickTree1)
ON_COMMAND(MENU_NEWTRIGGER, OnNewtrigger)
ON_COMMAND(MENU_ADDPOINT, OnAddpoint)
ON_COMMAND(MENU_ADDCATEGORY, OnAddcategory)
ON_COMMAND(MENU_TRIGGERPROPERTY, OnTriggerproperty)
ON_COMMAND(MENU_DELETENODE, OnDeletenode)
ON_NOTIFY(TVN_ENDLABELEDIT, IDC_TREE1, OnEndlabeleditTree1)
ON_COMMAND(MENU_LOADTRIGGER, OnLoadtrigger)
ON_COMMAND(MENU_SAVETRIGGER, OnSavetrigger)
ON_COMMAND(MENU_BUILDTRIGGER, OnBuildtrigger)
ON_NOTIFY(TVN_BEGINDRAG, IDC_TREE1, OnBegindragTree1)
ON_COMMAND(ID_ADDEVENT, OnAddevent)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CPageTriggerContainer message handlers
float CPageTriggerContainer::GetEpsilon()
{
char szEpsilon[1024];
m_editEpsilon.GetWindowText( szEpsilon, 1024 );
float epsilon;
epsilon = (float)strtod( szEpsilon, NULL );
return epsilon;
}
int CPageTriggerContainer::GetChildCount( HTREEITEM hItem )
{
if( hItem == NULL )
return 0;
HTREEITEM hChild = m_Tree.GetChildItem( hItem );
int i = 0;
while( hChild != NULL )
{
i++;
hChild = m_Tree.GetNextItem( hChild, TVGN_NEXT );
}
return i;
}
void CPageTriggerContainer::SetPos( HTREEITEM hItem, float x, float y, float z, long objID )
{
SNodeData nodeData = m_Tree.GetItemData( hItem );
CBGMController & BGMC = CBGMController::GetInstance();
if( nodeData.type == TYPE_POINT )
{
nodeData.Select();
BGMC.MovePoint( x, y, z );
BGMC.SetObjID( objID );
}
}
void CPageTriggerContainer::GetPos( HTREEITEM hItem, float & x, float & y, float & z, long & objID )
{
if( hItem == NULL )
{
x = y = z = 0.0f;
objID = 0;
}
SNodeData nodeData = m_Tree.GetItemData( hItem );
CBGMController & BGMC = CBGMController::GetInstance();
if( nodeData.type == TYPE_POINT )
{
nodeData.GetPoint( x, y, z, objID );
}
}
void CPageTriggerContainer::OnRclickTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
CPoint point;
GetCursorPos(&point);
CMenu menu;
menu.LoadMenu(IDR_MENU_TRIGGER);
menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN,point.x,point.y,this);
*pResult = 0;
}
void CPageTriggerContainer::OnNewtrigger()
{
HTREEITEM selected = m_Tree.GetSelectedItem();
if( selected == NULL )
return;
SNodeData nodeData = m_Tree.GetItemData( selected );
//선택된 아이템이 종류 노드일 경우에만...
if( nodeData.type != TYPE_CATEGORY )
return;
HTREEITEM added = m_Tree.InsertItem( "트리거", selected );
m_Tree.Expand( selected, TVE_EXPAND );
m_Tree.SetItemData( added, SNodeData( TYPE_TRIGGER ) );
HTREEITEM vertexes = m_Tree.InsertItem( "정점", added, NULL );
m_Tree.SetItemData( vertexes, SNodeData( TYPE_POINTS ) );
HTREEITEM events = m_Tree.InsertItem( "이벤트", added, NULL );
m_Tree.SetItemData( events, SNodeData( TYPE_EVENTS ) );
HTREEITEM hItem = m_Tree.InsertItem( "점 #1", vertexes, NULL );
m_Tree.SetItemData( hItem, SNodeData( 0.0f, 0.0f, 0.0f, 0 ) );
hItem = m_Tree.InsertItem( "점 #2", vertexes, NULL );
m_Tree.SetItemData( hItem, SNodeData( 0.0f, 0.0f, 0.0f, 0 ) );
hItem = m_Tree.InsertItem( "점 #3", vertexes, NULL );
m_Tree.SetItemData( hItem, SNodeData( 0.0f, 0.0f, 0.0f, 0 ) );
hItem = m_Tree.InsertItem( "이벤트 #1", events, NULL );
m_Tree.SetItemData( hItem, SNodeData( EVENT_NONE, "" ) );
m_Tree.Expand( added, TVE_EXPAND );
}
void CPageTriggerContainer::OnAddpoint()
{
HTREEITEM selected = m_Tree.GetSelectedItem();
if( selected != NULL )
{
SNodeData nodeData = m_Tree.GetItemData( selected );
if( nodeData.type == TYPE_POINTS )
{
int ItemNum = GetChildCount( selected ) + 1;
CString itemText;
itemText.Format( "점 #%d", ItemNum );
nodeData.Select();
HTREEITEM added = m_Tree.InsertItem( itemText, selected );
m_Tree.SetItemData( added, SNodeData( 0.0f, 0.0f, 0.0f, 0 ) );
m_Tree.Expand( selected, TVE_EXPAND );
}
}
}
void CPageTriggerContainer::OnAddcategory()
{
HTREEITEM selected = m_Tree.GetSelectedItem();
if( selected != NULL )
{
SNodeData nodeData = m_Tree.GetItemData( selected );
//선택된 아이템이 종류 노드일 경우에만...
if( nodeData.type == TYPE_CATEGORY )
{
HTREEITEM added = m_Tree.InsertItem( "종류", selected );
m_Tree.SetItemData( added, SNodeData( TYPE_CATEGORY ) );
m_Tree.Expand( selected, TVE_EXPAND );
}
}
}
void CPageTriggerContainer::OnAddevent()
{
HTREEITEM selected = m_Tree.GetSelectedItem();
if( selected != NULL )
{
SNodeData nodeData = m_Tree.GetItemData( selected );
if( nodeData.type == TYPE_EVENTS )
{
int ItemNum = GetChildCount( selected ) + 1;
CString itemText;
itemText.Format( "이벤트 #%d", ItemNum );
SNodeData parentNode = m_Tree.GetItemData( m_Tree.GetParentItem( selected ) );
assert( parentNode.type == TYPE_TRIGGER );
parentNode.Select();
HTREEITEM added = m_Tree.InsertItem( itemText, selected );
m_Tree.SetItemData( added, SNodeData( EVENT_NONE, "" ) );
m_Tree.Expand( selected, TVE_EXPAND );
}
}
}
void CPageTriggerContainer::OnDeletenode()
{
HTREEITEM selected = m_Tree.GetSelectedItem();
if( selected == NULL )
return;
SNodeData nodeData = m_Tree.GetItemData( selected );
switch( nodeData.type )
{
case TYPE_POINT :
{
if( GetChildCount( m_Tree.GetParentItem( selected ) ) <= 3 )
{
MessageBox( "트리거를 이루는 점들이 3개 이상이 되어야 하므로 주어진 노드를 지울 수 없습니다." );
return;
}
float x, y, z;
long objID;
nodeData.GetPoint( x, y, z, objID );
CMainFrame *mf=(CMainFrame*)AfxGetApp()->m_pMainWnd;
CWorldCreatorView *av=(CWorldCreatorView *)mf->GetActiveView();
av->m_SceneManager->m_MapStorage.DelMeshMap( x, y, z, objID );
m_Tree.DeleteItem( selected );
nodeData.Delete();
break;
}
case TYPE_POINTS :
case TYPE_EVENTS :
break;
case TYPE_EVENT :
m_Tree.DeleteItem( selected );
nodeData.Delete();
break;
case TYPE_TRIGGER :
{
nodeData.Select();
CBGMController & BGMC = CBGMController::GetInstance();
CMainFrame *mf=(CMainFrame*)AfxGetApp()->m_pMainWnd;
CWorldCreatorView *av=(CWorldCreatorView *)mf->GetActiveView();
int i = 0;
float x, y, z;
long objID;
while( BGMC.SelectPoint( nodeData.index1, i ) )
{
BGMC.GetPoint( x, y, z, objID );
av->m_SceneManager->m_MapStorage.DelMeshMap( x, y, z, objID );
i++;
}
nodeData.Delete();
m_Tree.DeleteItem( selected );
break;
}
case TYPE_CATEGORY :
if( GetChildCount( selected ) == 0 )
m_Tree.DeleteItem( selected );
break;
}
}
BOOL CPageTriggerContainer::OnInitDialog()
{
CPropertyPage::OnInitDialog();
HTREEITEM added = m_Tree.InsertItem( "일반 트리거" );
SNodeData nodeData( TYPE_CATEGORY );
m_Tree.SetItemData( added, nodeData );
m_editEpsilon.SetWindowText( "1000.0" );
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CPageTriggerContainer::OnTriggerproperty()
{
HTREEITEM selected = m_Tree.GetSelectedItem();
if( selected == NULL )
return;
SNodeData nodeData = m_Tree.GetItemData( selected );
switch( nodeData.type )
{
case TYPE_CATEGORY :
case TYPE_TRIGGER :
case TYPE_POINTS :
case TYPE_EVENTS :
break;
case TYPE_POINT :
{
CDlgTriggerPoint dlg;
long objID;
nodeData.GetPoint( dlg.m_xPos, dlg.m_yPos, dlg.m_zPos, objID );
dlg.DoModal();
break;
}
case TYPE_EVENT :
{
CDlgTriggerProperty dlg;
char szArgBuf[1024];
int eventType;
nodeData.GetEvent( eventType, szArgBuf );
dlg.m_strEventArg = szArgBuf;
dlg.SetEventType( eventType );
if( dlg.DoModal() == IDOK )
{
nodeData.SetEvent( dlg.GetEventType(), dlg.m_strEventArg );
m_Tree.SetItemData( selected, nodeData );
}
break;
}
}
}
void CPageTriggerContainer::OnEndlabeleditTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
*pResult = 1;
}
void CPageTriggerContainer::OnLoadtrigger()
{
CBGMController & BGMC = CBGMController::GetInstance();
CFileDialog FileDlg( TRUE, NULL, NULL, OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
, "Trigger Files (*.Trg)|*.trg|AllFiles (*.*)|*.*||", this );
if( FileDlg.DoModal() == IDOK )
{
m_Tree.DeleteAllItems();
FILE * fp = fopen( FileDlg.GetPathName(), "rb" );
LoadAllItems( fp );
BGMC.Create( fp, true );
fclose( fp );
RenderAllObjects();
}
}
void CPageTriggerContainer::OnSavetrigger()
{
CBGMController & BGMC = CBGMController::GetInstance();
CFileDialog FileDlg( TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT
, "Trigger Files (*.trg)|*.trg|AllFiles (*.*)|*.*||", this );
if( FileDlg.DoModal() == IDOK )
{
BGMC.Rebuild( GetEpsilon() );
FILE * fp = fopen( FileDlg.GetPathName(), "wb" );
SaveAllItems( fp );
BGMC.Save( fp );
fclose( fp );
}
}
void CPageTriggerContainer::LoadItem( HTREEITEM hItem, FILE * fp )
{
if( hItem == NULL )
return;
DWORD value;
int textLen = 0;
char szBuffer[1024];
fread( &value, sizeof( DWORD ), 1, fp );
fread( &textLen, sizeof( int ), 1, fp );
fread( szBuffer, sizeof( char ), textLen, fp );
szBuffer[ textLen ] = '\0';
m_Tree.SetItemData( hItem, value );
m_Tree.SetItemText( hItem, szBuffer );
}
void CPageTriggerContainer::SaveItem( HTREEITEM hItem, FILE * fp )
{
if( hItem == NULL )
return;
SNodeData nodeData = m_Tree.GetItemData( hItem );
CString itemText = m_Tree.GetItemText( hItem );
int textLen = itemText.GetLength();
fwrite( &nodeData.value, sizeof( DWORD ), 1, fp );
fwrite( &textLen, sizeof( int ), 1, fp );
fwrite( (const char*)itemText, sizeof( char ), textLen, fp );
}
void CPageTriggerContainer::LoadAllItems( FILE * fp )
{
if( fp == NULL )
return;
typedef pair<HTREEITEM,int> QueueNode;
queue<QueueNode> ItemQueue; //아이템 핸들, 자식 개수
int nChild = 0;
//1. 루트 노드가 있는지를 읽어온다.
fread( &nChild, sizeof( int ), 1, fp );
//2. 읽어온 값이 0이면 끝낸다.
if( nChild == 0 )
return;
//3. 루트 노드를 추가하고 읽어온다.
HTREEITEM hItem = m_Tree.InsertItem( "" );
LoadItem( hItem, fp );
fread( &nChild, sizeof( int ), 1, fp );
//4. 루트 노드를 큐에 삽입한다.
ItemQueue.push( QueueNode( hItem, nChild ) );
//5. 아이템큐가 비어있지 않은 동안
while( !ItemQueue.empty() )
{
//5-1. 큐에서 하나를 빼와서 현재 노드로 세팅한다.
QueueNode node = ItemQueue.front();
ItemQueue.pop();
//5-3. 자식 개수만큼
for( int i = 0; i < node.second; i++ )
{
//5-3-1. 노드정보를 읽어와서 노드를 추가한다.
HTREEITEM hChildItem = m_Tree.InsertItem( "", node.first );
m_Tree.SetItemData( hChildItem, 0 );
LoadItem( hChildItem, fp );
//5-2. 자식 개수를 읽어온다.
fread( &nChild, sizeof( int ), 1, fp );
//5-3-2. 추가한 노드를 큐에 삽입한다.
ItemQueue.push( QueueNode( hChildItem, nChild ) );
}
}
}
void CPageTriggerContainer::SaveAllItems( FILE * fp )
{
if( fp == NULL )
return;
queue<HTREEITEM> ItemQueue;
//1.루트 노드를 큐에 push
HTREEITEM hItem = m_Tree.GetRootItem();
int nChild = 0;
if( hItem != NULL )
{
nChild = 1;
ItemQueue.push( hItem );
}
fwrite( &nChild, sizeof( int ), 1, fp );
//2.큐가 비어있지 않은 동안
while( !ItemQueue.empty() )
{
//2-1.큐에서 하나를 pop해와서 현재 노드에 설정
hItem = ItemQueue.front();
ItemQueue.pop();
//2-2.현재 노드를 저장
SaveItem( hItem, fp );
//2-3.현재 노드의 자식 개수를 저장
nChild = GetChildCount( hItem );
fwrite( &nChild, sizeof( int ), 1, fp );
//2-4.현재 노드의 자식 노드들을 큐에 push
HTREEITEM hChild = m_Tree.GetChildItem( hItem );
while( hChild != NULL )
{
ItemQueue.push( hChild );
hChild = m_Tree.GetNextItem( hChild, TVGN_NEXT );
}
}
}
void CPageTriggerContainer::RenderAllObjects()
{
CBGMController & BGMC = CBGMController::GetInstance();
CMainFrame *mf=(CMainFrame*)AfxGetApp()->m_pMainWnd;
CWorldCreatorView *av=(CWorldCreatorView *)mf->GetActiveView();
int nPolygon = BGMC.GetPolygonCount();
for( int i = 0; i < nPolygon; i++ )
{
int nVertex = BGMC.GetVertexCount( i );
for( int j = 0; j < nVertex; j++ )
{
float x, y, z;
BGMC.GetVertex( i, j, x, y, z );
mf->m_MeshContainerBar.m_MeshContainerSheet->m_PageObjectContainer.AddObject(vector3( x, y, z ),"Cube.R3S");
long objID=av->m_SceneManager->m_MapStorage.m_TotalObjectSceneCount-1;
BGMC.SelectPoint( i, j );
BGMC.SetObjID( objID );
CSectorScene * pSector=av->m_SceneManager->PickTerrain( x, y, z );
if( pSector )
pSector->GenerateObject();
}
}
}
void CPageTriggerContainer::OnBuildtrigger()
{
CBGMController & BGMC = CBGMController::GetInstance();
BGMC.Rebuild( GetEpsilon() );
}
void CPageTriggerContainer::OnBegindragTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
HTREEITEM CurrentSelected = m_Tree.GetSelectedItem();
SNodeData nodeData = m_Tree.GetItemData( CurrentSelected );
if( nodeData.type == TYPE_POINT )
{
CMainFrame *mf=(CMainFrame*)AfxGetApp()->m_pMainWnd;
CWorldCreatorView *av=(CWorldCreatorView *)mf->GetActiveView();
av->ChangeMouseInterface(90);
}
*pResult = 0;
}
void CPageTriggerContainer::DeleteNode( unsigned index )
{
HTREEITEM item = m_Tree.GetRootItem();
SNodeData node;
node.type = TYPE_POINT;
node.index1 = ( index & 0xfffc000 ) >> 14;
node.index2 = index & 0x00003fff;
HTREEITEM finded = SearchItem( item, node );
if( finded != NULL )
{
m_Tree.DeleteItem( finded );
}
}
HTREEITEM CPageTriggerContainer::SearchItem( HTREEITEM item, DWORD nodeData )
{
item = m_Tree.GetChildItem( item );
SNodeData node = nodeData;
while( item != NULL )
{
SNodeData tempNode = m_Tree.GetItemData( item );
if( tempNode == node )
return item;
HTREEITEM hItemFinded = SearchItem( item, nodeData );
if( hItemFinded != NULL )
return hItemFinded;
item = m_Tree.GetNextItem( item, TVGN_NEXT );
}
return NULL;
}