areaeditor/
/*
** AreaEditor - a program for editing SMAUG and ROM area files.
** Author: Nick Gammon
** http://www.gammon.com.au/
** See Copyright Notice at the end of AreaEditor.h
*/

// RoomSummaryPage.cpp : implementation file
//

#include "stdafx.h"
#include "AreaEditor.h"
#include "AreaEditorDoc.h"
#include "defaults.h"

#include "RoomSummaryPage.h"

#include "ChooseMobDlg.h"
#include "ChooseObjectDlg.h"
#include "ChooseRoomDlg.h"
#include "WearFlagsDlg.h"
#include "AddExitDlg.h"

#include "AreaEditorView.h"
#include "ResetView.h"
#include "RoomView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CRoomSummaryPage dialog


CRoomSummaryPage::CRoomSummaryPage(CWnd* pParent /*=NULL*/)
	: CDialog(CRoomSummaryPage::IDD, pParent)
{
	//{{AFX_DATA_INIT(CRoomSummaryPage)
	m_name = _T("");
	m_sector_type = _T("");
	m_vnum = 0;
	m_strFlags = _T("");
	//}}AFX_DATA_INIT

  m_room = NULL;
  m_pDoc = NULL;

}

#undef LOAD_VALUE
#define LOAD_VALUE(field, value)  \
  field = m_room->value


void CRoomSummaryPage::DoDataExchange(CDataExchange* pDX)
{

  if (!pDX->m_bSaveAndValidate)
    {
    m_strFlags = convert_room_flags (m_room->room_flags);
    m_sector_type = RoomSectorList.ReturnName (m_room->sector_type, true);

    LOAD_VALUE (m_vnum, vnum);
	  LOAD_VALUE (m_name, name);
    }   // end of not saving and validating

	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CRoomSummaryPage)
	DDX_Control(pDX, IDC_REMOVE, m_ctlRemove);
	DDX_Control(pDX, IDC_GIVE, m_ctlGive);
	DDX_Control(pDX, IDC_EQUIP, m_ctlEquip);
	DDX_Control(pDX, IDC_OBJECTS, m_ctlObjects);
	DDX_Control(pDX, IDC_GOTO_OBJECT, m_ctlGoToObject);
	DDX_Control(pDX, IDC_GOTO_ENTRANCE, m_ctlGoToEntrance);
	DDX_Control(pDX, IDC_ENTRANCES, m_ctlEntrances);
	DDX_Text(pDX, IDC_NAME, m_name);
	DDX_Text(pDX, IDC_TYPE, m_sector_type);
	DDX_Text(pDX, IDC_VNUM, m_vnum);
	DDX_Text(pDX, IDC_FLAGS, m_strFlags);
	//}}AFX_DATA_MAP

  if (!pDX->m_bSaveAndValidate)
    AddEntrances ();

}


BEGIN_MESSAGE_MAP(CRoomSummaryPage, CDialog)
	//{{AFX_MSG_MAP(CRoomSummaryPage)
	ON_LBN_DBLCLK(IDC_ENTRANCES, OnDblclkEntrances)
	ON_BN_CLICKED(IDC_GOTO_ENTRANCE, OnGotoEntrance)
	ON_LBN_SELCHANGE(IDC_ENTRANCES, OnSelchangeEntrances)
	ON_LBN_SELCANCEL(IDC_ENTRANCES, OnSelcancelEntrances)
	ON_BN_CLICKED(IDC_GOTO_OBJECT, OnGotoObject)
	ON_LBN_DBLCLK(IDC_OBJECTS, OnDblclkObjects)
	ON_LBN_SELCHANGE(IDC_OBJECTS, OnSelchangeObjects)
	ON_LBN_SELCANCEL(IDC_OBJECTS, OnSelcancelObjects)
	ON_BN_CLICKED(IDC_ADD_MOB, OnAddMob)
	ON_BN_CLICKED(IDC_ADD_OBJECT, OnAddObject)
	ON_BN_CLICKED(IDC_REMOVE, OnRemove)
	ON_BN_CLICKED(IDC_EQUIP, OnEquip)
	ON_BN_CLICKED(IDC_GIVE, OnGive)
	ON_BN_CLICKED(IDC_ADD_EXIT, OnAddExit)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CRoomSummaryPage message handlers


void CRoomSummaryPage::AddEntrances (void)
  {

  CString strExitDirection;

  POSITION roomPos;
  CRoom * room;

  POSITION exitPos;
  CExit * exit;

  m_ctlEntrances.ResetContent ();
  m_ctlObjects.ResetContent ();

  // scan all open areas for exits and resets

  for (POSITION docPos = App.m_pDocTemplate->GetFirstDocPosition();
      docPos != NULL; )
    {

    CAreaEditorDoc * pDoc = (CAreaEditorDoc *) App.m_pDocTemplate->GetNextDoc(docPos);

    // scan each room

    for (roomPos = pDoc->m_RoomList.GetHeadPosition (); roomPos; )
      {
      room = pDoc->m_RoomList.GetNext (roomPos);


      // for each room see if we have an exit to *this* room

      for (exitPos = room->exitlist.GetHeadPosition (); exitPos; )
        {
        exit = room->exitlist.GetNext (exitPos);

        // forget it, if the wrong room
        if (exit->vnum != m_room->vnum)
          continue;

        strExitDirection = RoomDirectionList.ReturnName (exit->vdir, false);

        room->AddToListBox (m_ctlEntrances, 
                            CFormat ("%s from #%i (%s)", 
                                        (LPCTSTR) strExitDirection,
                                        room->vnum, 
                                        (LPCTSTR) room->name));


        }

      }


    POSITION resetPos;
    CReset * reset;

    CMobile * mob;
    CMUDObject * object;
    bool bThisRoom = false;

      // process each reset

    for (resetPos = pDoc->m_ResetList.GetHeadPosition (); resetPos; )
      {
      reset = pDoc->m_ResetList.GetNext (resetPos);

      switch (reset->command)
        {
        case 'M': // load mobile
          bThisRoom = reset->arg3 == m_room->vnum;

          if (!bThisRoom)
            break;    // wrong room - forget it

          if ((mob = FindMob ( reset->arg1)) == NULL)
            break;    // mob not found

          // aha! - add to list of references
          reset->AddToListBox (m_ctlObjects, 
                              CFormat ("Mobile: %s", (LPCTSTR) mob->Summary ()));

          break;

        case 'O': // load object
          if (reset->arg3 != m_room->vnum)
            break;    // wrong room - forget it

          if ((object = FindObj ( reset->arg1)) == NULL)
            break;    // object not found

          // aha! - add to list of objects
          reset->AddToListBox (m_ctlObjects, 
                              CFormat ("Object: %s", (LPCTSTR) object->Summary ()));

          break;

        case 'G': // give object
        case 'E': // equip object
          if (!bThisRoom)   // not given to a mob in this room
            break;    // wrong room - forget it

          if ((object = FindObj ( reset->arg1)) == NULL)
            break;    // object not found

          // aha! - add to list of objects
          reset->AddToListBox (m_ctlObjects, reset->Summary ());

          break;

        } // end of switch

      }   // end of processing each reset


    // now look for program cross-references

    // process each mob

    CMUDprogram * program;
    CString strErrorMessage;

    for (POSITION mobPos = pDoc->m_MobList.GetHeadPosition (); mobPos; )
      {
      mob = pDoc->m_MobList.GetNext (mobPos);
      for (POSITION progPos = mob->programlist.GetHeadPosition (); progPos; )
        {
        POSITION pos;

        program = mob->programlist.GetNext (progPos);

        for (pos = program->xref_rooms.GetHeadPosition (); pos; )
          if (program->xref_rooms.GetNext (pos) == m_room->vnum)
            {
            // aha! - add to list of resets
            program->AddToListBox (m_ctlObjects,
              CFormat ("Program: %s <%s>", 
                        (LPCTSTR) mob->Summary (),
                        (LPCTSTR) program->Summary ()));
          }   // end of cross-reference found

        }   // end of each program
    
      } // end of each mob

    // process each room

    for (POSITION RoomPos = pDoc->m_RoomList.GetHeadPosition (); RoomPos; )
      {
      room = pDoc->m_RoomList.GetNext (RoomPos);
      for (POSITION progPos = room->programlist.GetHeadPosition (); progPos; )
        {
        POSITION pos;

        program = room->programlist.GetNext (progPos);

        for (pos = program->xref_rooms.GetHeadPosition (); pos; )
          if (program->xref_rooms.GetNext (pos) == m_room->vnum)
            program->AddToListBox (m_ctlObjects,
              CFormat ("Room prog: %s <%s>", 
                        (LPCTSTR) room->Summary (),
                        (LPCTSTR) program->Summary ()));

        }   // end of each program
    
      } // end of each room

    // process each object

    for (POSITION ObjectPos = pDoc->m_ObjectList.GetHeadPosition (); ObjectPos; )
      {
      object = pDoc->m_ObjectList.GetNext (ObjectPos);
      for (POSITION progPos = object->programlist.GetHeadPosition (); progPos; )
        {
        POSITION pos;

        program = object->programlist.GetNext (progPos);

        for (pos = program->xref_rooms.GetHeadPosition (); pos; )
          if (program->xref_rooms.GetNext (pos) == m_room->vnum)
            program->AddToListBox (m_ctlObjects,
              CFormat ("Object prog: %s <%s>", 
                        (LPCTSTR) object->Summary (),
                        (LPCTSTR) program->Summary ()));
        }   // end of each program
    
      } // end of each object

    } // end of doing each document

  OnSelchangeEntrances ();
  OnSelchangeObjects ();

  }

void CRoomSummaryPage::OnDblclkEntrances() 
{
OnGotoEntrance ();
}


void CRoomSummaryPage::OnGotoEntrance() 
{
// find which item they selected, and go to it

int nItem =  m_ctlEntrances.GetCurSel( );

if (nItem != LB_ERR)
  ((CMUDitem *) m_ctlEntrances.GetItemData (nItem))->GoTo ();
	
}

void CRoomSummaryPage::OnSelchangeEntrances() 
{
// find which item they selected

int nItem =  m_ctlEntrances.GetCurSel( );
	
m_ctlGoToEntrance.EnableWindow (nItem != LB_ERR);

}

void CRoomSummaryPage::OnSelcancelEntrances() 
{
OnSelchangeEntrances ();	
}

void CRoomSummaryPage::OnGotoObject() 
{
// find which item they selected, and go to it

int nItem =  m_ctlObjects.GetCurSel( );

if (nItem != LB_ERR)
  ((CMUDitem *) m_ctlObjects.GetItemData (nItem))->GoTo ();
	
}

void CRoomSummaryPage::OnDblclkObjects() 
{
OnGotoObject ();
}

void CRoomSummaryPage::OnSelchangeObjects() 
{
// find which item they selected

int nItem =  m_ctlObjects.GetCurSel( );
	
m_ctlGoToObject.EnableWindow (nItem != LB_ERR);
m_ctlRemove.EnableWindow (nItem != LB_ERR);

if (nItem != LB_ERR)
  {
  CMUDitem * pItem =  (CMUDitem *) m_ctlObjects.GetItemData (nItem);
  CReset * pReset = (CReset *) pItem;
  // we can only equip or give if we have highlighted a mob reset
  if (pItem && strcmp (pItem->Type (), "reset") == 0 && pReset->command == 'M')
    {
    m_ctlGive.EnableWindow (TRUE);
    m_ctlEquip.EnableWindow (TRUE);
    }
  else
    {
    m_ctlGive.EnableWindow (FALSE);
    m_ctlEquip.EnableWindow (FALSE);
    }
  }
else
  {
  m_ctlGive.EnableWindow (FALSE);
  m_ctlEquip.EnableWindow (FALSE);
  }

}

void CRoomSummaryPage::OnSelcancelObjects() 
{
OnSelchangeObjects ();
}

void CRoomSummaryPage::OnAddMob() 
{
CChooseMobDlg mob_dlg;

  mob_dlg.m_pDoc = m_pDoc;
  
  CRoomView * wndParent = (CRoomView *) GetParent ();
  wndParent->m_bEditingText = true;

  if (mob_dlg.DoModal () == IDOK) 
    if (mob_dlg.m_iSelectedMob != -1)
      {
      CReset * reset = new CReset (RUNTIME_CLASS(CResetView), m_pDoc);
      m_pDoc->m_ResetList.AddTail (reset);    // and add it to our list
      m_pLHview->AddTreeItem (reset, m_pLHview->m_hdlTreeResets, TVI_LAST);
      m_pDoc->SetModifiedFlag ();

      reset->command = 'M';   // load mob
      reset->arg1 = mob_dlg.m_iSelectedMob;   // what what
      reset->arg2 = 1;    // limit
      reset->arg3 = m_room->vnum;   // which room (ie, this one)
      reset->m_pTreeCtrl->SetItemText (reset->m_hdlTreeItem, reset->Summary ());
      AddEntrances ();    // redraw list
      }

  wndParent->m_bEditingText = false;
    
}

void CRoomSummaryPage::OnAddObject() 
{
CChooseObjectDlg object_dlg;

  object_dlg.m_pDoc = m_pDoc;
  
  CRoomView * wndParent = (CRoomView *) GetParent ();
  wndParent->m_bEditingText = true;

  if (object_dlg.DoModal () == IDOK) 
    if (object_dlg.m_iSelectedObject != -1)
      {
      CReset * reset = new CReset (RUNTIME_CLASS(CResetView), m_pDoc);
      m_pDoc->m_ResetList.AddTail (reset);    // and add it to our list
      m_pLHview->AddTreeItem (reset, m_pLHview->m_hdlTreeResets, TVI_LAST);
      m_pDoc->SetModifiedFlag ();

      reset->command = 'O';   // load object
      reset->arg1 = object_dlg.m_iSelectedObject;   // what object
      reset->arg2 = 1;    // limit
      reset->arg3 = m_room->vnum;   // which room (ie, this one)
      reset->m_pTreeCtrl->SetItemText (reset->m_hdlTreeItem, reset->Summary ());
      AddEntrances ();    // redraw list
      }

  wndParent->m_bEditingText = false;
    
}

void CRoomSummaryPage::OnRemove() 
{
// find which item they selected, and remove it

int nItem =  m_ctlObjects.GetCurSel( );

if (nItem == LB_ERR)
  return;

 CMUDitem * pItem =  (CMUDitem *) m_ctlObjects.GetItemData (nItem);

// ask if they want to delete it

  if (::AfxMessageBox (CFormat ("OK to delete %s %s?", 
                    pItem->Type (),
                    (LPCTSTR) pItem->Summary ()), 
                    MB_ICONQUESTION | MB_YESNO) != IDYES)
                    return;

  pItem->Delete ();
  AddEntrances ();    // redraw list
	
}

#undef LOAD_FLAG
#define LOAD_FLAG(field, flag)  \
  field = IS_SET (arg3, flag);

#undef UNLOAD_FLAG
#define UNLOAD_FLAG(field, flag)  \
  if (field)                      \
    SET_BIT (arg3, flag);\
  else                            \
    REMOVE_BIT (arg3, flag)

void CRoomSummaryPage::GiveOrEquip (const char cResetCommand)
  {
int nItem =  m_ctlObjects.GetCurSel( );
	

if (nItem == LB_ERR)
return;

  CMUDitem * pItem =  (CMUDitem *) m_ctlObjects.GetItemData (nItem);
  CReset * pReset = (CReset *) pItem;

  if (!pItem || 
      strcmp (pItem->Type (), "reset") != 0 || 
      pReset->command != 'M')
    return;

  CChooseObjectDlg object_dlg;

  object_dlg.m_pDoc = m_pDoc;
  object_dlg.m_iItemType = cResetCommand == 'E' ? eWearItem : eTakeItem;
  
  CRoomView * wndParent = (CRoomView *) GetParent ();
  wndParent->m_bEditingText = true;

  if (object_dlg.DoModal () == IDOK) 
    if (object_dlg.m_iSelectedObject != -1)
      {

      int arg3 = WEAR_HOLD;

// for an equip, get the wear flags

      if (cResetCommand == 'E')
       {
        CWearFlagsDlg wear_dlg;

        EXT_BV iWearFlags = FindObj (object_dlg.m_iSelectedObject)->wear_flags;
        wear_dlg.m_strWearLocations = convert_wear_flags (iWearFlags);
        wear_dlg.m_strObject = FindObj (object_dlg.m_iSelectedObject)->Summary ();

        wear_dlg.m_iWearLocation = arg3;

        if (wear_dlg.DoModal () != IDOK)
          {
          wndParent->m_bEditingText = false;
          return;
          }

        arg3 = wear_dlg.m_iWearLocation;
   
       }    // end of an equip reset

      CReset * reset = (CReset *) pReset->Add (m_pLHview, false);
      reset->command = cResetCommand;
      reset->arg1 = object_dlg.m_iSelectedObject;   // what object
      reset->arg2 = 1;    // limit
      reset->arg3 = cResetCommand == 'E' ? arg3 : 0;    // wear flags
      reset->extra = 1;   // not sure what this does ...
      reset->m_pTreeCtrl->SetItemText (reset->m_hdlTreeItem, reset->Summary ());
      AddEntrances ();    // redraw list
      }

    wndParent->m_bEditingText = false;
  } // end of CRoomSummaryPage::GiveOrEquip

void CRoomSummaryPage::OnEquip() 
{
	GiveOrEquip ('E');
}

void CRoomSummaryPage::OnGive() 
{
	GiveOrEquip ('G');
}

// table to work out the reverse of a given direction
int iReverseDirections [] = 
  {
     DIR_SOUTH,     // from north
     DIR_WEST,      // from east
     DIR_NORTH,     // from south
     DIR_EAST,      // from west
     DIR_DOWN,      // from up
     DIR_UP,        // from down
     DIR_SOUTHWEST, // from ne
     DIR_SOUTHEAST, // from nw
     DIR_NORTHWEST, // from se
     DIR_NORTHEAST, // from sw
     DIR_SOMEWHERE  // from somewhere
  };


// have a static flag so we remember the "make reverse" switch
static BOOL bMakeReverse = FALSE;

void CRoomSummaryPage::OnAddExit() 
{

POSITION exitPos;
CExit * exit;

CRoomView * wndParent = (CRoomView *) GetParent ();

  wndParent->m_bEditingText = true;

// First, find which direction they want to go

CAddExitDlg directionDlg;

  directionDlg.m_room = m_room;
  directionDlg.m_bMakeReverse = bMakeReverse;

  if (directionDlg.DoModal () != IDOK)
    {
    wndParent->m_bEditingText = false;
    return;
    }

  // remember for next time if they wanted a reverse exit
  bMakeReverse = directionDlg.m_bMakeReverse;

  // warn if already an exit in that direction
  for (exitPos = m_room->exitlist.GetHeadPosition (); exitPos; )
    {
    exit = m_room->exitlist.GetNext (exitPos);

    if (exit->vdir == directionDlg.m_iDirection)
      {
      if (::AfxMessageBox (CFormat ("There is already an exit in the direction: %s\n\n"
                                "Do you want to add another \"%s\" exit?",
                                (LPCTSTR) exit->Summary (),
                                RoomDirectionList.ReturnName (directionDlg.m_iDirection, false)), 
                                MB_YESNO | MB_ICONQUESTION)
                                != IDYES)
                                {
                                wndParent->m_bEditingText = false;
                                return;
                                }
      break;    // don't query twice if they already have two exits in that direction
      }   // end of another exit in that direction
    }   // end of looping through exits

// Then, find which room they want to go to
CChooseRoomDlg roomDlg;

  roomDlg.m_pDoc = m_pDoc;
  roomDlg.m_iSelectedRoom = -1;
  if (roomDlg.DoModal () != IDOK) 
    {
    wndParent->m_bEditingText = false;
    return;
    }

  // if a reverse exit wanted, create that too

  if (directionDlg.m_bMakeReverse)
    {

    // look up room - make sure it exists
    CRoom * room = FindRoom (roomDlg.m_iSelectedRoom);

    if (!room)
      ::AfxMessageBox ("Cannot create reverse exit - destination room not selected",
                        MB_ICONEXCLAMATION);
    else
      {

      // warn if already an exit in that direction
      for (exitPos = room->exitlist.GetHeadPosition (); exitPos; )
        {
        exit = room->exitlist.GetNext (exitPos);

        if (exit->vdir == iReverseDirections [directionDlg.m_iDirection])
          {
          if (::AfxMessageBox (CFormat ("Room %s already has an exit in the direction: %s\n\n"
                                    "Do you want to add another \"%s\" exit?",
                                    (LPCTSTR) room->Summary (),
                                    (LPCTSTR) exit->Summary (),
                                    RoomDirectionList.ReturnName (iReverseDirections [directionDlg.m_iDirection], false)),
                                    MB_YESNO | MB_ICONQUESTION)
                                    != IDYES)
                                    {
                                    wndParent->m_bEditingText = false;
                                    return;
                                    }
          break;    // don't query twice if they already have two exits in that direction
          }   // end of another exit in that direction
        }   // end of looping through exits
      
      
      // If wanted, create the reverse exit

      exit = room->AddExit (m_pLHview);
      exit->vdir = iReverseDirections [directionDlg.m_iDirection];    // direction is reverse direction
      exit->vnum = m_room->vnum;    // exit to current room vnum
      exit->m_pTreeCtrl->SetItemText (exit->m_hdlTreeItem, exit->Summary ()); // amend description

      } // end of reverse room found
    } // end of reverse exit wanted

// If all went well, create the forwards exit

  exit = m_room->AddExit (m_pLHview);

// Fill in the answers from above
  exit->vdir = directionDlg.m_iDirection;   // direction is selected direction
  exit->vnum = roomDlg.m_iSelectedRoom;     // room to go to is selected room
  exit->m_pTreeCtrl->SetItemText (exit->m_hdlTreeItem, exit->Summary ()); // amend description

// And take them to the exit so they can fill in the description and keywords
  exit->GoTo ();
	
}