/* ** 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 "MainFrm.h" #include "AreaEditorDoc.h" #include "AreaEditorView.h" #include "defaults.h" #include "genprint.h" static int iPages = 0; static int iLine = 0; static BOOL bShowPrograms; #define BUFFER_SIZE 50000 // =============================================================================== static char * printline_buff = NULL; static void WriteLine (CArchive & ar, int skip, const char * theline, ...) { va_list arglist; if (!printline_buff) ThrowErrorException ("Not enough memory for printing buffer"); // output the message as if it was a PRINTF type message va_start (arglist, theline); _vsnprintf (printline_buff, BUFFER_SIZE, theline, arglist); va_end (arglist); ar.WriteString (printline_buff); // now output the line feeds for (int i = 0; i < skip; i++) ar.WriteString (ENDLINE); } // end of WriteLine // =============================================================================== static void ShowPrograms (CArchive & ar, const CMUDprogramList & programlist) { CMUDprogram * program; int i = 1; if (programlist.IsEmpty ()) return; // blank line before programs list WriteLine (ar, 1, ""); // show programs i = 1; for (POSITION progPos = programlist.GetHeadPosition (); progPos; i++) { program = programlist.GetNext (progPos); if (bShowPrograms && i > 1) WriteLine (ar, 1, ""); // blank line before each program WriteLine (ar, 1, "Program %i: %s", i, (LPCTSTR) program->Summary ()); if (bShowPrograms) { WriteLine (ar, 2, "-----------(begin program %i)--------------------", i); WriteLine (ar, 1, "%s", (LPCTSTR) program->comlist); WriteLine (ar, 1, "------------(end program %i)---------------------", i); } } // end of each program } // =============================================================================== // returns true on error in producing report bool CAreaEditorDoc::ProduceReport (CFile & fOutput) { POSITION pos; POSITION resetPos; CReset * reset; CMobile * mob; CMUDObject * object; // find if they want program contents listed bShowPrograms = App.GetProfileInt (sProfilePreferences, sProfileShowPrograms, 0);; CArchive ar (&fOutput, CArchive::store); printline_buff = new char [BUFFER_SIZE]; try { // area header if (m_Area) { __int64 economy = (__int64) m_Area->high_economy * 1000000000 + // 1 billion (__int64) m_Area->low_economy; WriteLine (ar, 1, "Author: %s", (LPCTSTR) m_Area->strAuthor); WriteLine (ar, 1, "Reset message: %s", (LPCTSTR) m_Area->strResetMsg); WriteLine (ar, 1, "Levels: Soft: %i to %i, Hard: %i to %i", m_Area->low_soft_range, m_Area->hi_soft_range, m_Area->low_hard_range, m_Area->low_hard_range); WriteLine (ar, 1, "Repop frequency: %s", m_Area->reset_frequency > 0 ? (LPCTSTR) CFormat ("%i", m_Area->reset_frequency) : "default"); WriteLine (ar, 1, "Mobile vnums %i to %i", m_Area->mob_low_vnum, m_Area->mob_hi_vnum); WriteLine (ar, 1, "Object vnums %i to %i", m_Area->obj_low_vnum, m_Area->obj_hi_vnum); WriteLine (ar, 1, "Room vnums %i to %i", m_Area->room_low_vnum, m_Area->room_hi_vnum); WriteLine (ar, 1, "Economy: %I64d gold coins", economy); if (m_Area->flags) WriteLine (ar, 1, "Flags: %s", (LPCTSTR) convert_areaflag (m_Area->flags)); } WriteLine (ar, 2, ""); WriteLine (ar, 2, "***** %i room%s *****", PLURAL (m_RoomList.GetCount ())); // rooms **************************************************************** for (POSITION RoomPos = m_RoomList.GetHeadPosition (); RoomPos; ) { CRoom * room = m_RoomList.GetNext (RoomPos); WriteLine (ar, 1, "%s", (LPCTSTR) room->Summary ()); WriteLine (ar, 1, "%s", (LPCTSTR) room->description); if (room->room_flags) WriteLine (ar, 1, "Flags: %s", (LPCTSTR) convert_room_flags (room->room_flags)); WriteLine (ar, 2, "Sector type: %s", RoomSectorList.ReturnName (room->sector_type, false)); // show all exits if (!room->exitlist.IsEmpty ()) { WriteLine (ar, 1, "Exits: "); for (pos = room->exitlist.GetHeadPosition (); pos; ) { CExit * exit = room->exitlist.GetNext (pos); WriteLine (ar, 1, "%s %s", (LPCTSTR) exit->Summary (), (LPCTSTR) convert_exit_flags (exit->exit_info)); if (IS_SET (exit->exit_info, EX_LOCKED)) { object = FindObj (exit->key); if (object) WriteLine (ar, 1, "... key: %s", (LPCTSTR) object->Summary ()); } // end of exit being locked } // end of processing each exit WriteLine (ar, 1, ""); // wrap up line after exits } // end of having some exits // process each reset to show mobs and objects in the room bool bThisRoom = false; for (resetPos = m_ResetList.GetHeadPosition (); resetPos; ) { reset = m_ResetList.GetNext (resetPos); switch (reset->command) { case 'M': // load mobile bThisRoom = reset->arg3 == room->vnum; if (!bThisRoom) break; // wrong room - forget it if ((mob = FindMob( reset->arg1)) == NULL) break; // mob not found WriteLine (ar, 1, "Mobile %s", (LPCTSTR) mob->Summary ()); WriteLine (ar, 1, "%s", (LPCTSTR) mob->long_descr); break; case 'O': // load object if (reset->arg3 != room->vnum) break; // wrong room - forget it if ((object = FindObj ( reset->arg1)) == NULL) break; // object not found WriteLine (ar, 1, "Object %s", (LPCTSTR) object->Summary ()); WriteLine (ar, 1, "%s", (LPCTSTR) object->description); 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 WriteLine (ar, 1, "%s", (LPCTSTR) reset->Summary ()); break; } // end of switch } // end of processing each reset WriteLine (ar, 1, ""); // now add extra descriptions for (POSITION extraPos = room->extralist.GetHeadPosition (); extraPos; ) { CExtraDescription * extra = room->extralist.GetNext (extraPos); WriteLine (ar, 1, "%s", (LPCTSTR) extra->Summary ()); WriteLine (ar, 2, "%s", (LPCTSTR) extra->description); } // now print all programs ShowPrograms (ar, room->programlist); WriteLine (ar, 2, "----------------------------------------------------------------------"); // line of 70 hyphens, then blank line after room } // end of each room WriteLine (ar, 2, ""); WriteLine (ar, 2, "***** %i mobile%s *****", PLURAL (m_MobList.GetCount ())); // mobiles **************************************************************** for (POSITION mobPos = m_MobList.GetHeadPosition (); mobPos; ) { mob = m_MobList.GetNext (mobPos); WriteLine (ar, 1, "%s", (LPCTSTR) mob->Summary ()); WriteLine (ar, 2, "%s", (LPCTSTR) mob->long_descr); WriteLine (ar, 2, "Mobile #%i \'%s\' is a level %i %s %s %s", mob->vnum, (LPCTSTR) mob->player_name, mob->level, (LPCTSTR) MobSexList.ReturnName (mob->sex, false), (LPCTSTR) MobRaceList.ReturnName (mob->race, false), (LPCTSTR) MobRaceList.ReturnName (mob->mobclass, false) ); if (!mob->description.IsEmpty ()) WriteLine (ar, 1, "%s", (LPCTSTR) mob->description); WriteLine (ar, 1, "Str: %i, Int: %i, Wis: %i, Dex: %i, Con: %i, Cha: %i, Lck: %i", mob->perm_str, mob->perm_int, mob->perm_wis, mob->perm_dex, mob->perm_con, mob->perm_cha, mob->perm_lck); if (mob->act) WriteLine (ar, 1, "Actions: %s", (LPCTSTR) convert_actflag (mob->act)); if (mob->affected_by) WriteLine (ar, 1, "Affected by: %s", (LPCTSTR) convert_affectflag (mob->affected_by)); if (mob->xflags) WriteLine (ar, 1, "Body parts: %s", (LPCTSTR) convert_partflag (mob->xflags)); if (mob->attacks) WriteLine (ar, 1, "Attacks: %s", (LPCTSTR) convert_attackflag (mob->attacks)); if (mob->defenses) WriteLine (ar, 1, "Defenses: %s", (LPCTSTR) convert_defenseflag (mob->defenses)); if (mob->form) WriteLine (ar, 1, "Form: %s", (LPCTSTR) convert_formflag (mob->form)); if (mob->resistant) WriteLine (ar, 1, "Resistant: %s", (LPCTSTR) convert_risflag (mob->resistant)); if (mob->immune) WriteLine (ar, 1, "Immune: %s", (LPCTSTR) convert_risflag (mob->immune)); if (mob->susceptible) WriteLine (ar, 1, "Susceptible: %s", (LPCTSTR) convert_risflag (mob->susceptible)); if (mob->speaks) WriteLine (ar, 1, "Speaks: %s", (LPCTSTR) convert_languages (mob->speaks)); if (mob->speaking) WriteLine (ar, 1, "Speaking: %s", (LPCTSTR) convert_languages (mob->speaking)); // now print all programs ShowPrograms (ar, mob->programlist); WriteLine (ar, 2, "----------------------------------------------------------------------"); // line of 70 hyphens, then blank line after mob } // end of each mob WriteLine (ar, 2, ""); WriteLine (ar, 2, "***** %i object%s *****", PLURAL (m_ObjectList.GetCount ())); // objects **************************************************************** for (POSITION ObjectPos = m_ObjectList.GetHeadPosition (); ObjectPos; ) { object = m_ObjectList.GetNext (ObjectPos); WriteLine (ar, 1, "%s", (LPCTSTR) object->Summary ()); // WriteLine (ar, 2, "%s", (LPCTSTR) object->short_descr); // short descr is in summary I think if (!object->description.IsEmpty ()) WriteLine (ar, 2, "%s", (LPCTSTR) object->description); WriteLine (ar, 1, "Type: %s", (LPCTSTR) ObjectItemList.ReturnName (object->item_type, false)); WriteLine (ar, 1, "Weight: %i, Cost: %i", object->weight, object->cost); if (object->extra_flags) WriteLine (ar, 1, "Flags: %s", (LPCTSTR) convert_object_flags (object->extra_flags)); if (object->wear_flags) WriteLine (ar, 1, "Wear: %s", (LPCTSTR) convert_wear_flags (object->wear_flags)); // list the affects caused by this object POSITION affectPos; CAffect * affect; CString strAffects; strAffects.Empty (); for (affectPos = object->affectlist.GetHeadPosition (); affectPos; ) { affect = object->affectlist.GetNext (affectPos); if (!strAffects.IsEmpty ()) strAffects += ", "; strAffects += affect->Summary (); } // end of adding each affect item if (!strAffects.IsEmpty ()) WriteLine (ar, 1, "Affects: %s", (LPCTSTR) strAffects); // summarise spell type, armour class etc. CString strSummary = object->ValueSummary (); if (!strSummary.IsEmpty ()) WriteLine (ar, 1, "%s", (LPCTSTR) strSummary); WriteLine (ar, 1, ""); // now add extra descriptions for (POSITION extraPos = object->extralist.GetHeadPosition (); extraPos; ) { CExtraDescription * extra = object->extralist.GetNext (extraPos); WriteLine (ar, 1, "%s", (LPCTSTR) extra->Summary ()); WriteLine (ar, 1, "%s", (LPCTSTR) extra->description); } // now print all programs ShowPrograms (ar, object->programlist); WriteLine (ar, 2, "----------------------------------------------------------------------"); // line of 70 hyphens, then blank line after object } // end of each object } // end of try catch (CException * e) { e->ReportError (); ar.Close (); e->Delete (); Frame.SetStatusMessage (READY); delete [] printline_buff; printline_buff = NULL; return true; } // good exit ar.Write ("", 1); // write trailing null ar.Close (); delete [] printline_buff; printline_buff = NULL; return false; } // end of CAreaEditorDoc::ProduceReport void CAreaEditorView::OnFilePrint() { CAreaEditorDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); int iLinesPerPage = App.GetProfileInt (sProfilePreferences, sProfileLinesPerpage, 60); CString strName = "Untitled world"; if (pDoc->m_Area && !pDoc->m_Area->strAreaName.IsEmpty ()) strName = pDoc->m_Area->strAreaName; if (App.GetProfileInt (sProfilePreferences, sProfilePrintToFile, 0)) { CFileDialog dlg(FALSE, // FALSE for FileSave "txt", // default extension "arealisting.txt", OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST, "Text files (*.txt)|*.txt||", this); dlg.m_ofn.lpstrTitle = "Area listing"; if (dlg.DoModal() != IDOK) return; try { CFile f (dlg.GetPathName(), CFile::modeCreate|CFile::modeWrite|CFile::shareExclusive); if (pDoc->ProduceReport (f)) return; // error in producing form } catch (CException* e) { e->ReportError(); e->Delete(); } return; } // end of printing to a file CMemFile f; // open memory file for writing Frame.SetStatusMessage ("Generating print file..."); if (pDoc->ProduceReport (f)) return; // error in producing form iPages = 0; iLine = 0; // printer control block for printing t_print_control_block pcb; // count pages in print file - allow 4 lines for header and footer Frame.SetStatusMessage ("Counting pages..."); try { CString str; f.SeekToBegin (); // back to start of file, we now read it back in CArchive ar (&f, CArchive::load); // we can read an archive as lines while (ar.ReadString (str)) iLine++; } // end of try catch (...) { ::AfxMessageBox ("An error occurred whilst printing area", MB_ICONEXCLAMATION); Frame.SetStatusMessage (READY); return; } // end of catching an exception Frame.SetStatusMessage (READY); // now work out how many pages that would have taken iPages = (iLine + (iLinesPerPage - 4) - 1) / (iLinesPerPage - 4); // attempt to open the printer if (print_start_document (pcb, strName, 1, iPages, App.GetProfileInt (sProfilePreferences, sProfileLeftMargin, 15), App.GetProfileInt (sProfilePreferences, sProfileTopMargin, 15), iLinesPerPage, App.GetProfileInt (sProfilePreferences, sProfileFontSize, 9), App.GetProfileInt (sProfilePreferences, sProfileFontSize, 9), // Line spacing App.GetProfileString (sProfilePreferences, sProfileFontName, "Courier"), false)) return; Frame.SetStatusMessage ("Printing area..."); int current_line = iLinesPerPage; // force new page immediately try { CString str; f.SeekToBegin (); // back to start of file, we now read it back in CArchive ar (&f, CArchive::load); // we can read an archive as lines while (ar.ReadString (str)) { // do footer and header if required if (current_line > (iLinesPerPage - 2)) { // do footer if not first page if (pcb.current_page > 0) { if (print_printline (pcb, 1, "")) // first do a blank Line break; print_font (pcb, FONT_BOLD); if (print_printline (pcb, 1, "Page %i of %i", pcb.current_page, iPages)) // then print the page number break; print_font (pcb, FONT_NORMAL); print_end_page (pcb); } // end of not first page // now do page header print_start_page (pcb); print_font (pcb, FONT_BOLD | FONT_UNDERLINE); CString strTime; strTime = CTime::GetCurrentTime().Format ("%A, %B %d, %Y, %#I:%M %p"); if (print_printline (pcb, 2, "%s - %s", (LPCTSTR) strName, (LPCTSTR) strTime)) break; print_font (pcb, FONT_NORMAL); current_line = 2; // back to top of page } // end of past end of page // finished header and footer, print the current Line print_font (pcb, FONT_NORMAL); if (print_printline (pcb, 1, str)) // print each line break; current_line++; } // end of processing each line ar.Close (); // finished with archive } catch (...) { ::AfxMessageBox ("An error occurred whilst printing area", MB_ICONEXCLAMATION); Frame.SetStatusMessage (READY); return; } // end of catching an exception // do final page footer if (!pcb.cancelled) { while (current_line <= (iLinesPerPage - 2)) { if (print_printline (pcb, 1, "")) // first do a blank iLine break; current_line++; } if (!pcb.cancelled) { print_font (pcb, FONT_BOLD); print_printline (pcb, 1, "Page %ld", pcb.current_page); print_font (pcb, FONT_NORMAL); } } // end of doing page footer // terminate the report by sending out the last page print_end_page (pcb); print_end_document (pcb); if (pcb.cancelled) ::AfxMessageBox ("Printing cancelled"); Frame.SetStatusMessage (READY); }