home *** CD-ROM | disk | FTP | other *** search
/ Informática Multimedia: Special Games / INFESPGAMES.mdf / os2 / spl / src / splobjec.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-26  |  21.2 KB  |  802 lines

  1. /* splobj.cpp:
  2.  
  3.   working thread and object window for spellbook class
  4.   bookwindow procedures mainly called by object window go in here
  5.  
  6.     Copyright (C) 1993, 1994 John-Marc Chandonia
  7.  
  8.     This program is free software; you can redistribute it and/or modify
  9.     it under the terms of the GNU General Public License as published by
  10.     the Free Software Foundation; either version 2 of the License, or
  11.     (at your option) any later version.
  12.  
  13.     This program is distributed in the hope that it will be useful,
  14.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.     GNU General Public License for more details.
  17.  
  18.     You should have received a copy of the GNU General Public License
  19.     along with this program; if not, write to the Free Software
  20.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21. */
  22.  
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include "spl.hpp"
  27. #include "general.hpp"
  28. #include "spldlg.h"
  29. #include "bookwin.hpp"
  30. #include "splwin.hpp"
  31. #include "spldlgs.hpp"
  32. #include "ea.hpp"
  33.  
  34. // stuff needed from spl.cpp
  35. extern char master_name[256];
  36. extern char quick_master_name[256];
  37. extern spellbook *masterlist;
  38. extern HEV sem_object_started;
  39. extern HEV sem_master_loading;
  40. extern BYTE xfer_buffer[10240];
  41.  
  42. // bookwindow currently being created: from threadmain(f)
  43. bookwindow *first;
  44.  
  45. // set window to a given spellbook
  46. boolean bookwindow::set_spellbook(spellbook *x) {
  47.     spellrecord *deleteme;
  48.     spelllist *i;
  49.     char buffer[256];
  50.  
  51.     // clear old spellbook, and window
  52.     while (deleteme=(spellrecord *)
  53.        WinSendMsg(hwndcnr,
  54.               CM_QUERYRECORD,
  55.               0,
  56.               MPFROM2SHORT(CMA_FIRST,CMA_ITEMORDER)))
  57.        delete_spell(deleteme);
  58.        
  59.     // add new spells to my window, at end.
  60.     add_all_spells(x);
  61.  
  62.     // change name of book to book just read.
  63.     if (x->name) {
  64.     delete (sb->name);
  65.     sb->name=strdup(x->name);
  66.     }
  67.     
  68.     refresh();
  69.  
  70.     saved=true;
  71.     return(true);
  72. }
  73.  
  74. // add all spells in a spellbook, efficiently
  75. boolean bookwindow::add_all_spells(spellbook *b, spellrecord *where) {
  76.     spelllist *sl;
  77.     spellrecord *sr;
  78.     int nspells=0;
  79.     spellrecord *newrecords;
  80.     LONG extrabytes;
  81.     HPOINTER myicon;
  82.     priestspell *ps;
  83.     int i;
  84.  
  85. /* inefficient way:
  86.     for (sl=b->first; sl!=NULL; sl=sl->next)
  87.     add_spell(sl->s);
  88. */
  89.  
  90.     for (sl=b->first; sl!=NULL; sl=sl->next)
  91.     nspells++;
  92.  
  93.     if (nspells==0) return(true);
  94.  
  95.     extrabytes=(LONG)(sizeof(spellrecord)-sizeof(RECORDCORE));
  96.     // tell the container to allocate memory for new records
  97.     newrecords=(spellrecord *)WinSendMsg(hwndcnr,
  98.                      CM_ALLOCRECORD,
  99.                      MPFROMLONG(extrabytes),
  100.                      (MPARAM)nspells);
  101.     sr=newrecords;
  102.     // set up each record
  103.     for (sl=b->first; sl!=NULL; sl=sl->next) {
  104.     sr->core.flRecordAttr=0;
  105.     sr->s=sl->s;
  106.     sr->level = (ULONG)sl->s->level;
  107.     ps = (priestspell *)sl->s;
  108.     sr->cast = ps->casttime;
  109.     sr->range = ps->range;
  110.     sr->duration = ps->duration;
  111.     sr->area = ps->area;
  112.     if (sl->s->type=='M')
  113.         sr->sphereschool = ps->school;
  114.     else 
  115.         sr->sphereschool = ps->sphere;
  116.     sr->components = ps->components;    
  117.     sr->save = ps->save;
  118.     sr->core.pszIcon=(PSZ)sl->s->name;
  119.     sr->core.pszText=(PSZ)sl->s->name;
  120.     sr->core.pszName=(PSZ)sl->s->name;
  121.     myicon=lookup_icon(sl->s);
  122.     sr->core.hptrIcon=myicon;
  123.     sr->core.hptrMiniIcon=myicon;
  124.  
  125.     // add to spellbook, also
  126.     if (where==NULL)  // add at end.
  127.         sr->spl = sb->add_spell(*(sl->s), sb->last);
  128.     else  // add after where
  129.         sr->spl = sb->add_spell(*(sl->s), where->spl);
  130.  
  131.     sr=(spellrecord *)sr->core.preccNextRecord;
  132.     }
  133.         
  134.     // tell the container to add the records
  135.     RECORDINSERT ri;
  136.     ri.cb=sizeof(RECORDINSERT);
  137.     if (where==NULL) 
  138.     ri.pRecordOrder=(PRECORDCORE)CMA_END;
  139.     else
  140.     ri.pRecordOrder=&(where->core);
  141.     ri.pRecordParent=NULL;
  142.     ri.fInvalidateRecord=FALSE;
  143.     ri.zOrder=CMA_TOP;
  144.     ri.cRecordsInsert=nspells;
  145.     
  146.     WinSendMsg(hwndcnr,
  147.            CM_INSERTRECORD,
  148.            MPFROMP(newrecords),
  149.            MPFROMP(&ri));
  150.  
  151.     if (!readonly) saved=false;
  152.     return(true);
  153. }
  154.  
  155. // create a subset, given a window to choose from and a selection dialog.
  156. // returns true if a subset was found, else false.
  157. boolean create_subset(bookwindow *mywin,HWND dlg) {
  158.     bookwindow *nsw=NULL;
  159.     spellrecord *sr;
  160.     spell *s;
  161.     char *tmpstr;
  162.     magespell *ms;
  163.     priestspell *ps;
  164.     boolean matches,itemmatch;
  165.     int i,j;
  166.  
  167.     // see if we're doing "and" or "or"
  168.     boolean s_and;
  169.     if (WinQueryButtonCheckstate(dlg,DLG_AND)==1) s_and=true;
  170.     else s_and=false;
  171.  
  172.     // see if things are case sensitive
  173.     boolean s_nocase=false;
  174.     if (WinQueryButtonCheckstate(dlg,DLG_CASE)==0) s_nocase=true;
  175.  
  176.     // see if there's a restriction on the name.
  177.     boolean s_name;
  178.     char *str_name;
  179.     if ((i=WinQueryDlgItemTextLength(dlg,DLG_NAME))==0) 
  180.     s_name=false;
  181.     else {
  182.     s_name=true;
  183.     str_name=new char[i+1];
  184.     WinQueryDlgItemText(dlg,DLG_NAME,i+1,(PSZ)str_name);
  185.     if (s_nocase) upstr(str_name);
  186.     }
  187.  
  188.     // check school
  189.     boolean s_school;
  190.     char *str_school;
  191.     if ((i=WinQueryDlgItemTextLength(dlg,DLG_SCHOOL))==0) 
  192.     s_school=false;
  193.     else {
  194.     s_school=true;
  195.     str_school=new char[i+1];
  196.     WinQueryDlgItemText(dlg,DLG_SCHOOL,i+1,(PSZ)str_school);
  197.     if (s_nocase) upstr(str_school);
  198.     }
  199.  
  200.     // check sphere
  201.     boolean s_sphere;
  202.     char *str_sphere;
  203.     if ((i=WinQueryDlgItemTextLength(dlg,DLG_SPHERE))==0) 
  204.     s_sphere=false;
  205.     else {
  206.     s_sphere=true;
  207.     str_sphere=new char[i+1];
  208.     WinQueryDlgItemText(dlg,DLG_SPHERE,i+1,(PSZ)str_sphere);
  209.     if (s_nocase) upstr(str_sphere);
  210.     }
  211.  
  212.     // check mage,priest,reversible
  213.     boolean s_mage;
  214.     boolean s_priest;
  215.     boolean s_reversible;
  216.     if (WinQueryButtonCheckstate(dlg,DLG_MAGE)==1) s_mage=true;
  217.     else s_mage=false;
  218.     if (WinQueryButtonCheckstate(dlg,DLG_PRIEST)==1) s_priest=true;
  219.     else s_priest=false;
  220.     if (WinQueryButtonCheckstate(dlg,DLG_REVERSIBLE)==1) s_reversible=true;
  221.     else s_reversible=false;
  222.  
  223.     
  224.     // check save
  225.     boolean s_save;
  226.     char *str_save;
  227.     if ((i=WinQueryDlgItemTextLength(dlg,DLG_SAVE))==0) 
  228.     s_save=false;
  229.     else {
  230.     s_save=true;
  231.     str_save=new char[i+1];
  232.     WinQueryDlgItemText(dlg,DLG_SAVE,i+1,(PSZ)str_save);
  233.     if (s_nocase) upstr(str_save);
  234.     }
  235.  
  236.     // check components
  237.     boolean s_components;
  238.     boolean s_c_v=false;
  239.     boolean s_c_s=false;
  240.     boolean s_c_m=false;
  241.     if ((i=WinQueryDlgItemTextLength(dlg,DLG_COMPONENTS))==0) 
  242.     s_components=false;
  243.     else {
  244.     s_components=true;
  245.     tmpstr=new char[i+1];
  246.     WinQueryDlgItemText(dlg,DLG_COMPONENTS,i+1,(PSZ)tmpstr);
  247.     upstr(tmpstr);
  248.     if (strchr(tmpstr,'V')!=0) s_c_v=true;
  249.     if (strchr(tmpstr,'S')!=0) s_c_s=true;
  250.     if (strchr(tmpstr,'M')!=0) s_c_m=true;
  251.     delete tmpstr;
  252.     }
  253.  
  254.     // see if there's a restriction on the level.
  255.     boolean s_level;
  256.     boolean s_level_gt=false;
  257.     boolean s_level_lt=false;
  258.     int int_level=0;
  259.     if ((i=WinQueryDlgItemTextLength(dlg,DLG_LEVEL))==0) 
  260.     s_level=false;
  261.     else {
  262.     s_level=true;
  263.     tmpstr=new char[i+1];
  264.     WinQueryDlgItemText(dlg,DLG_LEVEL,i+1,(PSZ)tmpstr);
  265.     if (tmpstr[0]=='>') {
  266.         s_level_gt=true;
  267.         sscanf(tmpstr,">%d",&int_level);
  268.     }
  269.     else if (tmpstr[0]=='<') {
  270.         s_level_lt=true;
  271.         sscanf(tmpstr,"<%d",&int_level);
  272.     }
  273.     else sscanf(tmpstr,"%d",&int_level);
  274.     delete tmpstr;
  275.     }
  276.  
  277.     // see if there's a description search going
  278.     boolean s_desc;
  279.     int int_desc;
  280.     int str_desc_len;
  281.     boolean s_desc_and=false;
  282.     PCHAR *str_desc;
  283.     HWND dh=WinWindowFromID(dlg,DLG_DESCRIPTION);
  284.     if (WinSendMsg(dh,
  285.            MLM_QUERYTEXTLENGTH,
  286.            0,0)==0)
  287.     s_desc=false;
  288.     else {
  289.     int_desc=(int)WinSendMsg(dh,
  290.                  MLM_QUERYLINECOUNT,
  291.                  0,0);
  292.     str_desc=new PCHAR[int_desc];
  293.     IPT pos= 0;
  294.  
  295.     // see if we're and'ing or or'ing the description search.
  296.     if (WinQueryButtonCheckstate(dlg,DLG_DES_AND)==1) s_desc_and=true;
  297.  
  298.     // set up xfer buffer
  299.     WinSendMsg(dh,
  300.            MLM_SETIMPORTEXPORT,
  301.            (MPARAM)(&xfer_buffer),
  302.            (MPARAM)10240);
  303.     WinSendMsg(dh,
  304.            MLM_FORMAT,
  305.            (MPARAM)MLFIE_NOTRANS,
  306.            0);
  307.     for (i=0; i<int_desc; i++) {
  308.         WinSendMsg(dh,MLM_SETSEL,(MPARAM)pos,(MPARAM)pos);
  309.         j=(int)WinSendMsg(dh,
  310.                   MLM_QUERYLINELENGTH,
  311.                   (MPARAM)pos,
  312.                   0);
  313.         str_desc[i]=new char[j+1];
  314.         str_desc_len=j;
  315.         WinSendMsg(dh,
  316.                MLM_EXPORT,
  317.                (MPARAM)&pos,
  318.                (MPARAM)&j);
  319.         strncpy(str_desc[i],(char *)xfer_buffer,str_desc_len);
  320.         str_desc[i][str_desc_len]=(char)0;
  321.  
  322.         // get rid of \n at end of string.
  323.         if ((str_desc_len>1) && (i<int_desc-1))
  324.         str_desc[i][str_desc_len-1]=(char)0;
  325.  
  326.         if (s_nocase) upstr(str_desc[i]);
  327.     }
  328.     }
  329.     
  330.     // get first spell
  331.     sr=(spellrecord *)
  332.     WinSendMsg(mywin->hwndcnr,
  333.            CM_QUERYRECORD,
  334.            0,
  335.            MPFROM2SHORT(CMA_FIRST,CMA_ITEMORDER));
  336.     while (sr!=NULL) {
  337.     s=sr->s;
  338.     ms=(magespell *)s;
  339.     ps=(priestspell *)s;
  340.     if (s_and) matches=true;
  341.     else matches=false;
  342.  
  343.     // see if this spell matches selection.
  344.     if (s_name) {
  345.         if (s_nocase) {
  346.         tmpstr=strdup(s->name);
  347.         upstr(tmpstr);
  348.         itemmatch=(boolean)(strstr(tmpstr,str_name)!=0);
  349.         delete tmpstr;
  350.         }
  351.         else itemmatch = (boolean)(strstr(s->name,str_name)!=0);
  352.  
  353.         if (s_and) matches = (boolean)(matches && itemmatch);
  354.         else matches = (boolean)(matches || itemmatch);
  355.     }
  356.     if (s_school) {
  357.         if ((s->type=='M') || (s->type=='P')) {
  358.         if (s_nocase) {
  359.             tmpstr=strdup(ms->school);
  360.             upstr(tmpstr);
  361.             itemmatch=(boolean)(strstr(tmpstr,str_school)!=0);
  362.             delete tmpstr;
  363.         }
  364.         else itemmatch = (boolean)(strstr(ms->school,str_school)!=0);
  365.         }
  366.         else itemmatch=false;
  367.  
  368.         if (s_and) matches = (boolean)(matches && itemmatch);
  369.         else matches = (boolean)(matches || itemmatch);
  370.     }
  371.     if (s_sphere) {
  372.         if (s->type=='P') {
  373.         if (s_nocase) {
  374.             tmpstr=strdup(ps->sphere);
  375.             upstr(tmpstr);
  376.             itemmatch=(boolean)(strstr(tmpstr,str_sphere)!=0);
  377.             delete tmpstr;
  378.         }
  379.         else itemmatch = (boolean)(strstr(ps->sphere,str_sphere)!=0);
  380.         }
  381.         else itemmatch=false;
  382.  
  383.         if (s_and) matches = (boolean)(matches && itemmatch);
  384.         else matches = (boolean)(matches || itemmatch);
  385.     }
  386.     if (s_level) {
  387.         if (s_level_gt) itemmatch = (boolean)(s->level > int_level);
  388.         else if (s_level_lt) itemmatch = (boolean)(s->level < int_level);
  389.         else itemmatch = (boolean)(s->level == int_level);
  390.  
  391.         if (s_and) matches = (boolean)(matches && itemmatch);
  392.         else matches = (boolean)(matches || itemmatch);
  393.     }
  394.     if (s_save) {
  395.         if ((s->type=='M') || (s->type=='P')) {
  396.         if (s_nocase) {
  397.             tmpstr=strdup(ms->save);
  398.             upstr(tmpstr);
  399.             itemmatch=(boolean)(strstr(tmpstr,str_save)!=0);
  400.             delete tmpstr;
  401.         }
  402.         else itemmatch = (boolean)(strstr(ms->save,str_save)!=0);
  403.         }
  404.         else itemmatch=false;
  405.  
  406.         if (s_and) matches = (boolean)(matches && itemmatch);
  407.         else matches = (boolean)(matches || itemmatch);
  408.     }
  409.     if (s_mage) {
  410.         itemmatch=(boolean)(s->type=='M');
  411.  
  412.         if (s_and) matches = (boolean)(matches && itemmatch);
  413.         else matches = (boolean)(matches || itemmatch);
  414.     }
  415.     if (s_priest) {
  416.         itemmatch=(boolean)(s->type=='P');
  417.  
  418.         if (s_and) matches = (boolean)(matches && itemmatch);
  419.         else matches = (boolean)(matches || itemmatch);
  420.     }
  421.     if (s_reversible) {
  422.         if ((s->type=='M') || (s->type=='P')) 
  423.         itemmatch=ms->reversible;
  424.         else itemmatch=false;
  425.  
  426.         if (s_and) matches = (boolean)(matches && itemmatch);
  427.         else matches = (boolean)(matches || itemmatch);
  428.     }
  429.     if (s_components) {
  430.         if ((s->type=='M') || (s->type=='P')) {
  431.         itemmatch=(boolean)(s_c_v || s_c_m || s_c_s);
  432.         if (s_c_v) itemmatch = 
  433.             (boolean)(itemmatch && strchr(ms->components,'V'));
  434.         if (s_c_s) itemmatch = 
  435.             (boolean)(itemmatch && strchr(ms->components,'S'));
  436.         if (s_c_m) itemmatch = 
  437.             (boolean)(itemmatch && strchr(ms->components,'M'));
  438.         }
  439.         else itemmatch=false;
  440.  
  441.         if (s_and) matches = (boolean)(matches && itemmatch);
  442.         else matches = (boolean)(matches || itemmatch);
  443.     }
  444.     // only search thru the descs if it matters... slow!
  445.     if ((s_desc) &&
  446.         (((s_and) && (matches==true)) ||
  447.          ((s_and==false) && (matches==false)))) {
  448.         if (s_desc_and) itemmatch=true;
  449.         else itemmatch=false;
  450.  
  451.         for (i=0; i<int_desc; i++) {
  452.         if (strlen(str_desc[i])!=0) {
  453.             if (s_desc_and) itemmatch = 
  454.             (boolean)(itemmatch && 
  455.                   s->desc_search(str_desc[i],s_nocase));
  456.             else itemmatch = 
  457.             (boolean)(itemmatch || 
  458.                   s->desc_search(str_desc[i],s_nocase));
  459.         }
  460.         }
  461.  
  462.         if (s_and) matches = (boolean)(matches && itemmatch);
  463.         else matches = (boolean)(matches || itemmatch);
  464.     }
  465.  
  466.     // if it still matches, add it in.
  467.     if (matches) {
  468.         if (!nsw) nsw=new bookwindow("Selection Matches:");
  469.         nsw->add_spell(s);
  470.     }
  471.  
  472.     // get next spell
  473.     sr=(spellrecord *)
  474.         WinSendMsg(mywin->hwndcnr,
  475.                CM_QUERYRECORD,
  476.                (MPARAM)sr,
  477.                MPFROM2SHORT(CMA_NEXT,CMA_ITEMORDER));
  478.     }
  479.  
  480.     // see if any spells were actually selected
  481.     if (nsw==NULL) {
  482.     WinMessageBox(HWND_DESKTOP,
  483.               HWND_DESKTOP,
  484.               (PSZ)"No spells in this book matched these selection criteria",
  485.               (PSZ)"Sorry!",
  486.               102,
  487.               MB_OK|MB_ICONEXCLAMATION);
  488.     return(false);
  489.     }
  490.     
  491.     // don't bug the user about closing the window
  492.     nsw->saved=true;
  493.     nsw->refresh();
  494.     return(true);
  495. }
  496.  
  497. // sort according to fields in sb integer array.
  498. SHORT APIENTRY spell_order(PRECORDCORE prc1, PRECORDCORE prc2, PVOID sb) {
  499.     spellrecord *psr1, *psr2;
  500.     int *sortby = (int *)sb;
  501.     int i;
  502.     SHORT cmp=0;
  503.     char *a, *b;
  504.  
  505.     psr1=(spellrecord *)prc1;
  506.     psr2=(spellrecord *)prc2;
  507.     priestspell *ps1 = (priestspell *)(psr1->s);
  508.     priestspell *ps2 = (priestspell *)(psr2->s);
  509.  
  510.     for (i=0; i<5; i++) {
  511.     /* sorting by:
  512.     0 = "None",
  513.     1 = "Caster Type",
  514.     2 = "Name of Spell",
  515.     3 = "Spell Level",
  516.     4 = "School/Sphere",
  517.     5 = "Components",
  518.     6 = "Save"
  519.     */
  520.     switch (sortby[i]) {
  521.     case 1:
  522.         if ((ps1->type=='P') && (ps2->type=='M'))
  523.         cmp = -1;
  524.         if ((ps1->type=='M') && (ps2->type=='P'))
  525.         cmp = 1;
  526.         break;
  527.     case 2:
  528.         cmp = strcmpi(ps1->name,ps2->name);
  529.         break;
  530.     case 3:
  531.         if (ps1->level < ps2->level) cmp = -1;
  532.         if (ps1->level > ps2->level) cmp = 1;
  533.         break;
  534.     case 4:
  535.         if (ps1->type=='P') a=ps1->sphere;
  536.         else a=ps1->school;
  537.         if (ps2->type=='P') b=ps2->sphere;
  538.         else b=ps2->school;
  539.         cmp = strcmpi(a,b);
  540.         break;
  541.     case 5:
  542.         cmp = strcmpi(ps1->components,ps2->components);
  543.         break;
  544.     case 6:
  545.         cmp = strcmpi(ps1->save,ps2->save);
  546.         break;
  547.     }
  548.     if (cmp) return(cmp);
  549.     }
  550.     return(0);
  551. }
  552.  
  553. // sort spellbook
  554. boolean bookwindow::sort_book(ULONG sortorder) {
  555.     spelllist *sl1, *sl2;
  556.     int sortby[5];
  557.     int j;
  558.  
  559.     titleprintf(hwndframe,"%s:  Sorting Book...",sb->name);
  560.  
  561.     // figure out what the ULONG code means:
  562.     for (j=0; j<5; j++) {
  563.     sortby[j] = sortorder % 7;
  564.     sortorder /= 7;
  565.     }
  566.  
  567.     WinSendMsg(hwndcnr,
  568.            CM_SORTRECORD,
  569.            (MPARAM)(spell_order),
  570.            (MPARAM)sortby);
  571.  
  572.     // sort sb also, according to result of container sort
  573.     spellrecord *i;
  574.     i=(spellrecord *)
  575.     WinSendMsg(hwndcnr,
  576.            CM_QUERYRECORD,
  577.            0,
  578.            MPFROM2SHORT(CMA_FIRST,CMA_ITEMORDER));
  579.  
  580.     if (i==NULL) return(false);
  581.  
  582.     sl1=i->spl;
  583.     sb->first=sl1;
  584.     sl1->prev=NULL;  
  585.     while (i!=NULL) {
  586.     i=(spellrecord *)
  587.         WinSendMsg(hwndcnr,
  588.                CM_QUERYRECORD,
  589.                (MPARAM)i,
  590.                MPFROM2SHORT(CMA_NEXT,CMA_ITEMORDER));
  591.     if (i!=NULL) {
  592.         sl2=i->spl;
  593.         sl2->prev=sl1;
  594.         sl1->next=sl2;
  595.         sl1=sl2;
  596.     }
  597.     }
  598.     sl1->next=NULL;
  599.     sb->last=sl1;
  600.  
  601.     titleprintf(hwndframe,"%s",sb->name);
  602.     saved=false;
  603.     return(true);    
  604. }
  605.  
  606. // object window procedure
  607. MRESULT EXPENTRY object_window_func(HWND hwnd, ULONG msg, 
  608.                     MPARAM param1, MPARAM param2) {
  609.     bookwindow *mywin;
  610.     spellbook *newsb;
  611.     long masterdate,quickdate;
  612.     int rc;
  613.     ULONG count_sem;
  614.  
  615.     switch(msg) {
  616.     case WM_CREATE:
  617.     // save book handle in first window
  618.     first->hwndobject=hwnd;
  619.  
  620.     // save pointer to my instance in window word
  621.     WinSetWindowPtr(hwnd,
  622.             0,
  623.             first);
  624.  
  625.     // tell main window I'm ready.
  626.     DosPostEventSem(sem_object_started);
  627.  
  628.     return (MRESULT)0;
  629.     break;
  630.  
  631.     case WM_USER_LOAD_MASTER:
  632.     // find most recent master list, load it in
  633.     masterdate = query_last_write(master_name);
  634.     quickdate = query_last_write(quick_master_name);
  635.     if (masterdate > quickdate) {
  636.         // load in the master list from "slow" file, then quicksave copy
  637.         masterlist=get_master_list(master_name);  
  638.         masterlist->name=strdup("Master Spell List");
  639.         if (masterlist)
  640.         masterlist->quicksave(quick_master_name);
  641.     }
  642.     else { // load in quick copy of list
  643.         masterlist=new spellbook;    
  644.         if (masterlist->quickload(quick_master_name)==false) {
  645.         delete masterlist;
  646.         masterlist = NULL;
  647.         }
  648.         else if (masterlist->name==NULL)
  649.         masterlist->name=strdup("Master Spell List");
  650.     }
  651.     return (MRESULT)0;
  652.     break;
  653.  
  654.     case WM_USER_SHOW_MASTER:
  655.     mywin=(bookwindow *)WinQueryWindowPtr(hwnd,0);
  656.  
  657.     DosRequestMutexSem(sem_master_loading,SEM_INDEFINITE_WAIT);
  658.     if (!masterlist) {
  659.         // wait for master window to be loaded
  660.         WinSendMsg(mywin->hwndobject, WM_USER_LOAD_MASTER, 0,0);
  661.     }
  662.     DosReleaseMutexSem(sem_master_loading);
  663.     if (!masterlist) 
  664.         titleprintf(mywin->hwndframe,"Can't Load Master List!");
  665.     else {
  666.         titleprintf(mywin->hwndframe,
  667.             "%s:  Loading Icons...",masterlist->name);
  668.         mywin->set_spellbook(masterlist);
  669.         titleprintf(mywin->hwndframe,"%s",masterlist->name);
  670.     }
  671.  
  672.     // reactivate the main window
  673.     WinPostMsg( mywin->hwnd,WM_USER_ACK,(MPARAM)msg,0);
  674.  
  675.     break;
  676.  
  677.     case WM_USER_SAVE:
  678.     // param1 should contain a value for just titles, 0 for entire book.
  679.     mywin=(bookwindow *)WinQueryWindowPtr(hwnd,0);
  680.     titleprintf(mywin->hwndframe,"Saving to %s",mywin->filename);
  681.  
  682.     if (param1) rc = mywin->sb->print_titles(mywin->filename);
  683.     else rc = mywin->sb->print_book(mywin->filename);
  684.  
  685.     if (rc==0) {
  686.         mywin->saved=true;
  687.         titleprintf(mywin->hwndframe,"%s",mywin->sb->name);
  688.     }
  689.     else
  690.         titleprintf(mywin->hwndframe,"Error saving to %s",mywin->filename);
  691.  
  692.     WinPostMsg( mywin->hwnd,WM_USER_ACK,(MPARAM)msg,0);
  693.     return (MRESULT)0;
  694.     break;
  695.     
  696.     case WM_USER_LOAD:
  697.     mywin=(bookwindow *)WinQueryWindowPtr(hwnd,0);
  698.     titleprintf(mywin->hwndframe,"Loading %s...",mywin->filename);
  699.  
  700.     newsb = new spellbook;
  701.     DosRequestMutexSem(sem_master_loading,SEM_INDEFINITE_WAIT);
  702.     rc = newsb->read(mywin->filename, masterlist);
  703. //    titleprintf(mywin->hwndframe,"rc = %d",rc);
  704.     if ((rc) && (!masterlist)) {
  705.         // be sure master list is loaded.
  706.         WinSendMsg(mywin->hwndobject, WM_USER_LOAD_MASTER, 0,0);
  707.         DosReleaseMutexSem(sem_master_loading);
  708. //        titleprintf(mywin->hwndframe,"read masterlist");
  709.         if (masterlist)
  710.         rc = newsb->read_titles(mywin->filename,masterlist);
  711.     }
  712.     else 
  713.         DosReleaseMutexSem(sem_master_loading);
  714.  
  715. //    titleprintf(mywin->hwndframe,"DONE");
  716.  
  717.     if (rc==-1) 
  718.         titleprintf(mywin->hwndframe,"Error loading %s",mywin->filename);
  719.     else {
  720.         mywin->set_spellbook(newsb);
  721.         titleprintf(mywin->hwndframe,"%s",mywin->sb->name);
  722.     }
  723.     if (rc>0) {
  724.         sprintf((char *)xfer_buffer,
  725.             "%s:  %d spells not found in master list",
  726.             mywin->sb->name, rc);
  727.         WinMessageBox(HWND_DESKTOP,
  728.               HWND_DESKTOP,
  729.               (PSZ)xfer_buffer,
  730.               (PSZ)"Warning!",
  731.               102,
  732.               MB_OK|MB_ICONEXCLAMATION);
  733.     }
  734.  
  735.     delete newsb;
  736.     WinPostMsg( mywin->hwnd,WM_USER_ACK,(MPARAM)msg,0);
  737.     return (MRESULT)0;
  738.     break;
  739.  
  740.     case WM_USER_SORT:
  741.     mywin=(bookwindow *)WinQueryWindowPtr(hwnd,0);
  742.     if (!mywin->sort_book((ULONG)param1))
  743.         titleprintf(mywin->hwndframe,"Error sorting %s",mywin->sb->name);
  744.     WinPostMsg( mywin->hwnd,WM_USER_ACK,(MPARAM)msg,0);
  745.     return (MRESULT)0;
  746.     break;
  747.  
  748.     case WM_USER_CREATE_SUBSET:
  749.     mywin=(bookwindow *)WinQueryWindowPtr(hwnd,0);
  750.     titleprintf(mywin->hwndframe,"Finding subset...");
  751.     if (create_subset(mywin,(HWND)param1)) 
  752.         WinPostMsg((HWND)param1,
  753.                WM_USER_ACK,
  754.                (MPARAM)1,0);
  755.     else 
  756.         WinPostMsg((HWND)param1,
  757.                WM_USER_ACK,
  758.                0,0);
  759.     titleprintf(mywin->hwndframe,"%s",mywin->sb->name);
  760.     WinPostMsg( mywin->hwnd,WM_USER_ACK,(MPARAM)msg,0);
  761.     return (MRESULT)0;
  762.     break;
  763.     }
  764.     return WinDefWindowProc(hwnd, msg, param1, param2);
  765. }
  766.  
  767.  
  768. // entry point for 2nd threads started by spellbook windows
  769. void _Optlink threadmain(void *f) {
  770.     HAB hab;
  771.     HMQ hand_mq;  // message queue 
  772.     QMSG q_mess;  // message queue 
  773.  
  774.     hab=WinInitialize(0);  // get anchor block 
  775.     hand_mq = WinCreateMsgQueue(hab, 0); // start queue 
  776.  
  777.     first=(bookwindow *)f;
  778.  
  779.     if (!WinRegisterClass(
  780.               hab,
  781.               (PSZ) spbobjclass,
  782.               (PFNWP) object_window_func,
  783.               0,
  784.               sizeof(bookwindow *)))
  785.     exit(1);
  786.  
  787.     WinCreateWindow(HWND_OBJECT,
  788.             spbobjclass,
  789.             "",
  790.             0,0,0,0,0,
  791.             HWND_OBJECT,
  792.             HWND_BOTTOM,
  793.             0,0,0);
  794.  
  795.     // message loop 
  796.     while(WinGetMsg(hab, &q_mess, 0L,0,0))
  797.     WinDispatchMsg(hab, &q_mess);
  798.  
  799.     WinDestroyMsgQueue(hand_mq);
  800.     WinTerminate(hab);
  801. }
  802.