/* ** 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 */ #include "stdafx.h" #include "AreaEditor.h" #include "AreaEditorDoc.h" #include "AreaEditorView.h" #include "ObjectView.h" #include "AddToObjectDlg.h" #include "defaults.h" #include "MUDProgramView.h" #include "ObjectAffectView.h" #include "ObjectExtraDescriptionView.h" #include "DeleteXrefDlg.h" // constructor CMUDObject::CMUDObject (CRuntimeClass* pViewClass, CAreaEditorDoc * pDoc) : CMUDitem (pViewClass, pDoc) { name = strObjectDefaultName; short_descr = strObjectDefaultShortDescription; description = strObjectDefaultDescription; vnum = 0; item_type = ITEM_TRASH; extra_flags = 0; magic_flags = 0; wear_flags = 0; weight = 1; cost = 0; value [0] = 0; value [1] = 0; value [2] = 0; value [3] = 0; value [4] = 0; value [5] = 0; layers = 0; rent = 0; // ROM values level = 0; condition = 100; } // end of constructor void CMUDObject::ChangeRHview (CAreaEditorView * pLHview, CView * pwhichView) { CObjectView * pView = (CObjectView *) pwhichView; ASSERT(pView->IsKindOf(RUNTIME_CLASS(CObjectView))); pView->m_object = this; pView->CreatePages (); // add the tab control pages pView->ShowPages (m_pDoc); } CString CMUDObject::Summary (void) { return CFormat ("#%i %s", vnum, (LPCTSTR) short_descr); } CMUDObject::~CMUDObject () { // get rid of programs inside object for (POSITION progPos = programlist.GetHeadPosition (); progPos; ) delete programlist.GetNext (progPos); programlist.RemoveAll (); // pointers are deleted, remove list items // get rid of affects inside object for (POSITION affectPos = affectlist.GetHeadPosition (); affectPos; ) delete affectlist.GetNext (affectPos); affectlist.RemoveAll (); // pointers are deleted, remove list items // get rid of extra descriptions inside object for (POSITION extraPos = extralist.GetHeadPosition (); extraPos; ) delete extralist.GetNext (extraPos); extralist.RemoveAll (); // pointers are deleted, remove list items } // end of destructor void CMUDObject::Delete (void) { // look for things that refer to *this* object and tell them about it CDeleteXrefDlg dlg; CMUDitemList xrefList; CMUDitemList xrefOwnerList; CMobile * refmob = NULL; CMUDitem * noitem = NULL; dlg.m_pxrefList = &xrefList; dlg.m_pxrefOwnerList = &xrefOwnerList; dlg.m_strAboutToDelete = Summary (); for (POSITION ResetPos = m_pDoc->m_ResetList.GetHeadPosition (); ResetPos; ) { CReset * reset = m_pDoc->m_ResetList.GetNext (ResetPos); switch (reset->command) { case 'M': refmob = m_pDoc->get_mob_index (reset->arg1); // remember for owner later break; case 'O': if (reset->arg1 == vnum) { xrefOwnerList.AddTail (noitem); // no owner of reset xrefList.AddTail (reset); // which reset } break; case 'P': if (reset->arg1 == vnum || reset->arg3 == vnum) { xrefOwnerList.AddTail (noitem); // no owner of reset xrefList.AddTail (reset); // which reset } break; case 'G': case 'E': if (reset->arg1 == vnum) { xrefOwnerList.AddTail (refmob); // which mob owns the item xrefList.AddTail (reset); // which reset } break; case 'H': if (reset->arg1 == vnum) { xrefOwnerList.AddTail (noitem); // no owner of reset xrefList.AddTail (reset); // which reset } break; } // end of switch } // end of processing each reset if (!xrefList.IsEmpty ()) // don't bother if no references if (dlg.DoModal () != IDOK) return; // they changed their mind (hope it works better!) // delete referencing items for (POSITION refPos = xrefList.GetHeadPosition (); refPos; ) xrefList.GetNext (refPos)->Delete (); // delete programs inside object for (POSITION progPos = programlist.GetHeadPosition (); progPos; ) programlist.GetNext (progPos)->Delete (); programlist.RemoveAll (); // pointers are deleted, remove list items // delete affects inside object for (POSITION affectPos = affectlist.GetHeadPosition (); affectPos; ) affectlist.GetNext (affectPos)->Delete (); affectlist.RemoveAll (); // pointers are deleted, remove list items // delete extra descriptions inside object for (POSITION extraPos = extralist.GetHeadPosition (); extraPos; ) extralist.GetNext (extraPos)->Delete (); extralist.RemoveAll (); // pointers are deleted, remove list items // delete from list of objects m_pDoc->m_ObjectList.RemoveAt (m_pDoc->m_ObjectList.Find (this, NULL)); CMUDitem::Delete (); } // end of CMUDObject::Delete CMUDitem * CMUDObject::Add (CAreaEditorView * pView, const bool bSelect) { // add program, affect or extra to this object CAddToObjectDlg dlg; dlg.m_iAddType = 0; if (dlg.DoModal () != IDOK) return NULL; // they cancelled, the bastards! CMUDprogram * prog; HTREEITEM hdlItem; CMUDitem * pItem = NULL; switch (dlg.m_iAddType) { case 0: // Affect pItem = AddAffect (pView); break; case 1: // Extra description pItem = AddDescription (pView); break; case 2: // Program prog = new CMUDprogram (RUNTIME_CLASS(CMUDProgramView), m_pDoc); programlist.AddHead (prog); // and add it to our list hdlItem = pView->AddTreeItem (prog, m_hdlTreeItem); if (bSelect) m_pTreeCtrl->Select (hdlItem, TVGN_CARET); // select it m_pDoc->SetModifiedFlag (); pItem = prog; break; } if (bSelect) pItem->GoTo (); return pItem; } // end of CMUDObject::Add CString CMUDObject::AddDescription (void) // description of what add does { return "affect/description/program"; } // end of CMUDObject::AddDescription void CMUDObject::SubItemDeleted (CMUDitem * pItem) { POSITION pos; // a program has been deleted? if (pos = programlist.Find (pItem, NULL)) programlist.RemoveAt (pos); // an affect been deleted? if (pos = affectlist.Find (pItem, NULL)) affectlist.RemoveAt (pos); // an extra description has been deleted? if (pos = extralist.Find (pItem, NULL)) extralist.RemoveAt (pos); } // end of CMUDObject::SubItemDeleted static int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { CMUDprogram * prog1 = (CMUDprogram *) lParam1; CMUDprogram * prog2 = (CMUDprogram *) lParam2; if (prog1->iSortSeq < prog2->iSortSeq) return -1; else if (prog1->iSortSeq > prog2->iSortSeq) return 1; else return 0; } // end of CompareFunc // add for a program adds one after the current one CMUDprogram * CMUDObject::AddProgram (CAreaEditorView * pView, CMUDitem * pItem, const bool bSelect) { TV_SORTCB sortCB; int iSeq = 0; CMUDprogram * prog = new CMUDprogram (RUNTIME_CLASS(CMUDProgramView), m_pDoc); if (pItem) { POSITION pos = programlist.Find (pItem, NULL); programlist.InsertAfter (pos, prog); // and add it to our list } else programlist.AddHead (prog); // add at head HTREEITEM hdlprogItem = pView->AddTreeItem (prog, m_hdlTreeItem); sortCB.hParent = m_hdlTreeItem; sortCB.lpfnCompare = CompareFunc; sortCB.lParam = 0; // give each prog a sequence so we can sort them into list order for (POSITION progPos = programlist.GetHeadPosition (); progPos; ) programlist.GetNext (progPos)->iSortSeq = iSeq++; m_pTreeCtrl->SortChildrenCB (&sortCB); // sort into proper order if (bSelect) m_pTreeCtrl->Select (hdlprogItem, TVGN_CARET); // select it m_pDoc->SetModifiedFlag (); return prog; } // end of CMUDObject::AddProgram // add for a new description CExtraDescription * CMUDObject::AddDescription (CAreaEditorView * pView) { CExtraDescription * extra = new CExtraDescription (RUNTIME_CLASS(CObjectExtraDescriptionView), m_pDoc); extralist.AddHead (extra); // and add it to our list pView->AddTreeItem (extra, m_hdlTreeItem); m_pDoc->SetModifiedFlag (); return extra; } // end of CMUDObject::AddDescription // add for a new affect CAffect * CMUDObject::AddAffect (CAreaEditorView * pView) { CAffect * affect = new CAffect (RUNTIME_CLASS(CObjectAffectView), m_pDoc); affectlist.AddHead (affect); // and add it to our list pView->AddTreeItem (affect, m_hdlTreeItem); m_pDoc->SetModifiedFlag (); return affect; } // end of CMUDObject::CAffect // do a search for this item BOOL CMUDObject::Search (const CString strWanted, const int iFindType, const BOOL bMatchCase) { CString strFound; // switch on find type switch (iFindType) { case eFindVnum: if (isalpha (strWanted [0])) { if (strWanted [0] != 'O') return FALSE; // they aren't looking for objects return atoi (strWanted.Mid (1)) == vnum; } return atoi (strWanted) == vnum; case eFindDetail: SEARCH (name); SEARCH (short_descr); SEARCH (description); SEARCH (action_desc); SEARCH (ObjectItemList.ReturnName (item_type, false)); SEARCH (convert_object_flags (extra_flags)); SEARCH (convert_wear_flags (wear_flags)); SEARCH (ValueSummary ()); return FALSE; default: return CMUDitem::Search (strWanted, iFindType, bMatchCase); } // end of switch } // end of CMUDObject::Search void CMUDObject::Duplicate (CAreaEditorView * pView) { CMUDObject * object = m_pDoc->AddObject (pView, false); if (!object) return; // could not create a new object (no vnums available?) object->Copy (this); object->m_pTreeCtrl->SetItemText (object->m_hdlTreeItem, object->Summary ()); // now duplicate programs in the object CMUDprogram * oldProg, * newProg; CString strMessage; for (POSITION progPos = programlist.GetHeadPosition (); progPos; ) { oldProg = programlist.GetNext (progPos); // get a program newProg = new CMUDprogram (RUNTIME_CLASS(CMUDProgramView), m_pDoc); // make a new one object->programlist.AddTail (newProg); // add to new object pView->AddTreeItem (newProg, object->m_hdlTreeItem); // add to object's tree item newProg->Copy (oldProg); // check syntax so cross-referencing will be correct CheckCommandSyntax (newProg->comlist, strMessage, newProg->xref_objects, newProg->xref_objects, newProg->xref_objects); newProg->m_pTreeCtrl->SetItemText (newProg->m_hdlTreeItem, newProg->Summary ()); } // end of processing each program // now duplicate extra descriptions for the object CExtraDescription * oldDesc, * newDesc; for (POSITION DescPos = extralist.GetHeadPosition (); DescPos; ) { oldDesc = extralist.GetNext (DescPos); // get a description newDesc = new CExtraDescription (RUNTIME_CLASS(CObjectExtraDescriptionView), m_pDoc); // make a new one object->extralist.AddTail (newDesc); // add to new object pView->AddTreeItem (newDesc, object->m_hdlTreeItem); // add to object's tree item newDesc->Copy (oldDesc); newDesc->m_pTreeCtrl->SetItemText (newDesc->m_hdlTreeItem, newDesc->Summary ()); } // end of processing each description // now duplicate Affects for the object CAffect * oldAffect, * newAffect; for (POSITION AffectPos = affectlist.GetHeadPosition (); AffectPos; ) { oldAffect = affectlist.GetNext (AffectPos); // get an Affect newAffect = new CAffect (RUNTIME_CLASS(CObjectAffectView), m_pDoc); // make a new one object->affectlist.AddTail (newAffect); // add to new object pView->AddTreeItem (newAffect, object->m_hdlTreeItem); // add to object's tree item newAffect->Copy (oldAffect); newAffect->m_pTreeCtrl->SetItemText (newAffect->m_hdlTreeItem, newAffect->Summary ()); } // end of processing each Affect object->GoTo (); // select it now it has been set up } // end of CMUDObject::Duplicate #define DUPLICATE(arg) arg = RHside->arg // copy function for duplicating objects void CMUDObject::Copy (const CMUDObject * const RHside) { DUPLICATE (name); DUPLICATE (short_descr); DUPLICATE (description); DUPLICATE (action_desc); // nb - do not duplicate vnum! - that must be unique DUPLICATE (item_type); DUPLICATE (extra_flags); DUPLICATE (magic_flags); DUPLICATE (wear_flags); DUPLICATE (weight); DUPLICATE (cost); DUPLICATE (layers); DUPLICATE (rent); for (int i = 0; i < 6; i++) DUPLICATE (value [i]); } // end of CMUDObject::Copy CString CMUDObject::ValueSummary (void) const // summarises what the values mean { switch (item_type) { case ITEM_ARMOR: return CFormat ("AC: %i, current AC: %i", - value [0], - value [1]); case ITEM_CONTAINER: return CFormat ("Capacity: %i", value [0]); case ITEM_DRINK_CON: return CFormat ("Capacity: %i, quantity %i", value [0], value [1]); case ITEM_FOOD: return CFormat ("Food value: %i", value [0]); case ITEM_PILL: case ITEM_POTION: case ITEM_SCROLL: { CString strResult; if (m_pDoc->skill_name (value[1], true) != "NONE") strResult += "'" + m_pDoc->skill_name (value[1]) + "' "; if (m_pDoc->skill_name (value[2], true) != "NONE") strResult += "'" + m_pDoc->skill_name (value[2]) + "' "; if (m_pDoc->skill_name (value[3], true) != "NONE") strResult += "'" + m_pDoc->skill_name (value[3]) + "' "; if (strResult.IsEmpty ()) strResult = "'NONE'"; return CFormat ("Level %i, spell(s): %s", value[0], (LPCTSTR) strResult); } case ITEM_STAFF: case ITEM_WAND: return CFormat ("Level: %i, charges: %i, max charges: %i, spell: '%s'", value[0], value[1], value[2], (LPCTSTR) m_pDoc->skill_name (value[3], true)); case ITEM_SALVE: { CString strResult; if (m_pDoc->skill_name (value[4], true) != "NONE") strResult += "'" + m_pDoc->skill_name (value[4]) + "' "; if (m_pDoc->skill_name (value[5], true) != "NONE") strResult += "'" + m_pDoc->skill_name (value[5]) + "' "; if (strResult.IsEmpty ()) strResult = "'NONE'"; return CFormat ("Level %i, max charge: %i, charges: %i, delay: %i, spell(s): %s", value[0], value[1], value[2], value[3], (LPCTSTR) strResult); } case ITEM_WEAPON: { CString strResult; strResult = CFormat ("Attack: %id%i, weapon type: %s", value[1], value[2], (LPCTSTR) ObjectAttackList.ReturnName (value[3], false)); if (m_pDoc->m_AreaType == eROM && value [4]) { strResult += ", flags: "; strResult += FlagToString (value[4], ObjectWeaponFlags); } // end of a ROM object with weapon flags return strResult; } case ITEM_LIGHT: if (value[2] == -1) return "Hours left: infinite"; return CFormat ("Hours left: %i", value [2]); } // end of switch return ""; } // end of CMUDObject::ValueSummary