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

  1. /* splbook.cpp: routines for spell and spellbook manipulation
  2.  
  3.     Copyright (C) 1993, 1994 John-Marc Chandonia
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation; either version 2 of the License, or
  8.     (at your option) any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19.  
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include "splbook.hpp"
  24. #include "general.hpp"
  25.  
  26. // get a spell description from the appropriate file
  27. void spell::get_desc() {
  28.     char buffer[256];
  29.     FILE *infile;
  30.     
  31.     if ((infile=fopen(source_file,"r"))==NULL)
  32.     return;
  33.     
  34.     fsetpos(infile,&desc_pos);
  35.  
  36.     fgets_no_cr(buffer,256,infile);
  37.     while ((strncmp(buffer,"-----",5)!=0) && (!feof(infile))) {
  38.     add_desc(buffer);
  39.     fgets_no_cr(buffer,256,infile);
  40.     }
  41.     
  42.     fclose(infile);
  43.   
  44.     desc_loaded=true;
  45. }
  46.  
  47. // kill off a spell's description
  48. void spell::kill_desc() {
  49.     int i;
  50.     
  51.     for (i=0; i<lines; i++)
  52.     delete(description[i]);
  53.     lines=0;
  54.  
  55.     desc_loaded=false;
  56. }
  57.  
  58. // search for a string in the description
  59. // if ignore_case, have string in upper case to save time!
  60. boolean spell::desc_search(char *str, boolean ignore_case) {
  61.     int i;
  62.     char *tmpstr;
  63.     
  64.     if (desc_loaded==false) get_desc();
  65.     if (ignore_case) {
  66.     for (i=0; i<lines; i++) {
  67.         tmpstr=strdup(description[i]);
  68.         upstr(tmpstr);
  69.         if (strstr(tmpstr,str)!=0) return(true);
  70.     }
  71.     }
  72.     else for (i=0; i<lines; i++)
  73.     if (strstr(description[i],str)!=0) return(true);
  74.  
  75.     kill_desc();
  76.  
  77.     return(false);
  78. }
  79.  
  80. spell::spell() {
  81.     name=source=range=area=NULL;
  82.     type=' ';
  83.     level= -1;
  84.     lines=0;
  85.     desc_loaded=false;
  86. }
  87.  
  88. spell::~spell() {
  89.     if (name) delete(name);
  90.     if (source) delete(source);
  91.     if (source_file) delete(source_file);
  92.     if (range) delete(range);
  93.     if (area) delete(area);
  94.     for (int i=0; i<lines; i++)
  95.     delete(description[i]);
  96. }
  97.  
  98. void spell::add_desc(char *x) {
  99.     if (lines>255) return;
  100.  
  101.     // kluge to remove " " as a description... take out space.
  102.     if ((strlen(x)==2) && (x[0]==' ')) {
  103.     description[lines]=new char[strlen(x)];
  104.     strcpy(description[lines++],x+1);
  105.     }
  106.     else {
  107.     description[lines]=new char[strlen(x)+1];
  108.     strcpy(description[lines++],x);
  109.     }
  110. }
  111.  
  112. magespell::magespell() {
  113.     school=components=duration=casttime=save=NULL;
  114.     reversible=false;
  115.     type='M';
  116. };
  117.  
  118. magespell::~magespell() {
  119.     if (school) delete(school);
  120.     if (components) delete(components);
  121.     if (duration) delete(duration);
  122.     if (casttime) delete(casttime);
  123.     if (save) delete(save);
  124. };
  125.  
  126. void magespell::print_stats() {
  127.     printf("%s (%s)\r\n",name,school);
  128.     if (reversible) printf("Reversible\r\n");
  129.     printf("  from %s\r\n",source);
  130.     printf("Range: %s\r\n",range);
  131.     printf("Components: %s\r\n",components);
  132.     printf("Duration: %s\r\n",duration);
  133.     printf("Casting Time: %s\r\n",casttime);
  134.     printf("Area of Effect: %s\r\n",area);
  135.     printf("Saving Throw: %s\r\n",save);
  136. }
  137.  
  138. void magespell::f_print(FILE *outfile) {
  139.     if (desc_loaded==false) get_desc();
  140.  
  141.     fprintf(outfile,"%s (%s)\n",name,school);
  142.     if (reversible) fprintf(outfile,"Reversible\n");
  143.     if (source) fprintf(outfile,"  from %s\n",source);
  144.     fprintf(outfile,"Level: %d\n",level);
  145.     if (range) fprintf(outfile,"Range: %s\n",range);
  146.     if (components) fprintf(outfile,"Components: %s\n",components);
  147.     if (duration) fprintf(outfile,"Duration: %s\n",duration);
  148.     if (casttime) fprintf(outfile,"Casting Time: %s\n",casttime);
  149.     if (area) fprintf(outfile,"Area of Effect: %s\n",area);
  150.     if (save) fprintf(outfile,"Saving Throw: %s\n",save);
  151.     fprintf(outfile,"\n");
  152.     for (int i=0; i<lines; i++)
  153.     fprintf(outfile,"%s\n",description[i]);
  154.  
  155.     kill_desc();
  156. }
  157.  
  158. void magespell::s_print(char *buffer) {
  159.     int i;
  160.  
  161.     if (desc_loaded==false) get_desc();
  162.  
  163.     sprintf(buffer,"%s (%s)\n",name,school);
  164.     i=strlen(buffer);
  165.     if (reversible) sprintf(buffer+i,"Reversible\n");
  166.     i=strlen(buffer);
  167.     if (source) sprintf(buffer+i,"  from %s\n",source);
  168.     i=strlen(buffer);
  169.     sprintf(buffer+i,"Level: %d\n",level);
  170.     i=strlen(buffer);
  171.     if (range) sprintf(buffer+i,"Range: %s\n",range);
  172.     i=strlen(buffer);
  173.     if (components) sprintf(buffer+i,"Components: %s\n",components);
  174.     i=strlen(buffer);
  175.     if (duration) sprintf(buffer+i,"Duration: %s\n",duration);
  176.     i=strlen(buffer);
  177.     if (casttime) sprintf(buffer+i,"Casting Time: %s\n",casttime);
  178.     i=strlen(buffer);
  179.     if (area) sprintf(buffer+i,"Area of Effect: %s\n",area);
  180.     i=strlen(buffer);
  181.     if (save) sprintf(buffer+i,"Saving Throw: %s\n",save);
  182.     i=strlen(buffer);
  183.     sprintf(buffer+i," \n");
  184.     i=strlen(buffer);
  185.     for (int j=0; j<lines; j++) {
  186.     if ((strlen(description[j])==0) || 
  187.         ((strlen(description[j])==1) && (description[j][0]==' '))) 
  188.         sprintf(buffer+i," \n");
  189.     else {
  190.         sprintf(buffer+i,"%s ",description[j]);
  191.         i=strlen(buffer);
  192.         if ((j<lines-1) && 
  193.         ((description[j+1][0]==' ') || 
  194.          (strlen(description[j+1])<2) ||
  195.          (description[j+1][0]=='\t')))
  196.         sprintf(buffer+i," \n");
  197.     }
  198.     i=strlen(buffer);
  199.     }
  200.     kill_desc();
  201. }
  202.  
  203. void magespell::f_print_header(FILE *outfile) {
  204.     fprintf(outfile,"%17.17s ",name);
  205.     if (reversible) fprintf(outfile,"(R) ");
  206.     else fprintf(outfile,"    ");
  207.     fprintf(outfile,"%5.5s ",casttime);
  208.     fprintf(outfile,"%7.7s ",components);
  209.     fprintf(outfile,"%15.15s ",range);
  210.     fprintf(outfile,"%15.15s ",duration);
  211.     fprintf(outfile,"%15.15s ",area);
  212.     fprintf(outfile,"%4.4s ",save);
  213.     fprintf(outfile,"\n");
  214. }
  215.  
  216. void magespell::quicksave(FILE *outfile) {
  217.     fprintf(outfile,"M\n");
  218.     fprintf(outfile,"%s\n",name);
  219.     fprintf(outfile,"%s\n",source_file);
  220.     fprintf(outfile,"%s\n",school);
  221.     if (reversible) fprintf(outfile,"R\n");
  222.     else fprintf(outfile,"N\n");
  223.     if (source) fprintf(outfile,"%s",source);
  224.     fprintf(outfile,"\n");
  225.     fprintf(outfile,"%d\n",level);
  226.     fprintf(outfile,"%s\n",range);
  227.     fprintf(outfile,"%s\n",components);
  228.     fprintf(outfile,"%s\n",duration);
  229.     fprintf(outfile,"%s\n",casttime);
  230.     fprintf(outfile,"%s\n",area);
  231.     fprintf(outfile,"%s\n",save);
  232.     fprintf(outfile,"%d\n",lines);
  233.     fwrite(&desc_pos,sizeof(fpos_t),1,outfile);
  234. }
  235.  
  236. // load magespell, with "M" line already read
  237. void magespell::quickload(FILE *infile) {
  238.     char buffer[256];
  239.  
  240.     fgets_no_cr(buffer,256,infile);
  241.     if (buffer[0]!=(char)0) name = strdup(buffer);
  242.     fgets_no_cr(buffer,256,infile);
  243.     if (buffer[0]!=(char)0) source_file = strdup(buffer);
  244.     fgets_no_cr(buffer,256,infile);
  245.     if (buffer[0]!=(char)0) school = strdup(buffer);
  246.     fgets_no_cr(buffer,256,infile);
  247.     if (buffer[0]=='R') reversible=true;
  248.     else reversible = false;
  249.     fgets_no_cr(buffer,256,infile);
  250.     if (buffer[0]!=(char)0) source = strdup(buffer);
  251.     fgets(buffer,256,infile);
  252.     sscanf(buffer,"%d",&level);
  253.     fgets_no_cr(buffer,256,infile);
  254.     if (buffer[0]!=(char)0) range = strdup(buffer);
  255.     fgets_no_cr(buffer,256,infile);
  256.     if (buffer[0]!=(char)0) components = strdup(buffer);
  257.     fgets_no_cr(buffer,256,infile);
  258.     if (buffer[0]!=(char)0) duration = strdup(buffer);
  259.     fgets_no_cr(buffer,256,infile);
  260.     if (buffer[0]!=(char)0) casttime = strdup(buffer);
  261.     fgets_no_cr(buffer,256,infile);
  262.     if (buffer[0]!=(char)0) area = strdup(buffer);
  263.     fgets_no_cr(buffer,256,infile);
  264.     if (buffer[0]!=(char)0) save = strdup(buffer);
  265.     fgets(buffer,256,infile);
  266.     sscanf(buffer,"%d",&lines);
  267.     fread(&desc_pos,sizeof(fpos_t),1,infile);
  268. }
  269.  
  270. void magespell::f_read(FILE *infile) {
  271.     char buffer[256];
  272.     
  273.     do {
  274.     fgets_no_cr(buffer,256,infile);
  275.     } while ((strlen(buffer)<=1) && !feof(infile));
  276.     if (feof(infile)) return;
  277.  
  278.     char *l=strrchr(buffer,'(');
  279.     char *m=strrchr(buffer,')');
  280.     if ((m==NULL) || (l==NULL)) {
  281.     if (buffer[0]!=(char)0) name = strdup(buffer);
  282.     }
  283.     else {
  284.     int namelen=strlen(buffer)-strlen(l);
  285.     name=new char[namelen];
  286.     name[namelen-1]=(char)0;
  287.     strncpy(name,buffer,namelen-1);
  288.     int schoollen=strlen(l)-strlen(m);
  289.     school=new char[schoollen];
  290.     school[schoollen-1]=(char)0;
  291.     strncpy(school,l+1,schoollen-1);
  292.     }
  293.     fgets_no_cr(buffer,256,infile);
  294.     if (strncmp(buffer,"Reversible",10)==0) {
  295.     reversible=true;
  296.     fgets_no_cr(buffer,256,infile);
  297.     }
  298.     while ((strlen(buffer)>2) && !feof(infile)) {
  299.     if (strstr(buffer,"Range:"))
  300.         range=strdup(buffer+7);
  301.     else if (strstr(buffer,"Components:"))
  302.         components=strdup(buffer+12);
  303.     else if (strstr(buffer,"Duration:"))
  304.         duration=strdup(buffer+10);
  305.     else if (strstr(buffer,"Casting Time:"))
  306.         casttime=strdup(buffer+14);
  307.     else if (strstr(buffer,"Area of Effect:"))
  308.         area=strdup(buffer+16);
  309.     else if (strstr(buffer,"Saving Throw:"))
  310.         save=strdup(buffer+14);
  311.     else if (strstr(buffer,"School:"))
  312.         school=strdup(buffer+8);
  313.     else if (strstr(buffer,"  from "))
  314.         source=strdup(buffer+7);
  315.     else if (strstr(buffer,"Level:"))
  316.         sscanf(buffer+7,"%d",&level);
  317.     
  318.     fgets_no_cr(buffer,256,infile);
  319.     }
  320.     fgetpos(infile,&desc_pos);
  321.     while ((strncmp(buffer,"-----",5)!=0) && !feof(infile)) {
  322.     fgets(buffer,256,infile);
  323.     }
  324. }
  325.  
  326. priestspell::priestspell() {
  327.     sphere=NULL;
  328.     type='P';
  329. };
  330.  
  331. priestspell::~priestspell() {
  332.     delete(sphere);
  333. };
  334.  
  335. void priestspell::print_stats() {
  336.     printf("%s (%s)\r\n",name,school);
  337.     if (reversible) printf("Reversible\r\n");
  338.     printf("  from %s\r\n",source);
  339.     printf("Sphere: %s\r\n",sphere);
  340.     printf("Range: %s\r\n",range);
  341.     printf("Components: %s\r\n",components);
  342.     printf("Duration: %s\r\n",duration);
  343.     printf("Casting Time: %s\r\n",casttime);
  344.     printf("Area of Effect: %s\r\n",area);
  345.     printf("Saving Throw: %s\r\n",save);
  346. }
  347.  
  348. void priestspell::f_print(FILE *outfile) {
  349.     if (desc_loaded==false) get_desc();
  350.  
  351.     fprintf(outfile,"%s (%s)\n",name,school);
  352.     if (reversible) fprintf(outfile,"Reversible\n");
  353.     if (source) fprintf(outfile,"  from %s\n",source);
  354.     fprintf(outfile,"Level: %d\n",level);
  355.     if (sphere) fprintf(outfile,"Sphere: %s\n",sphere);
  356.     if (range) fprintf(outfile,"Range: %s\n",range);
  357.     if (components) fprintf(outfile,"Components: %s\n",components);
  358.     if (duration) fprintf(outfile,"Duration: %s\n",duration);
  359.     if (casttime) fprintf(outfile,"Casting Time: %s\n",casttime);
  360.     if (area) fprintf(outfile,"Area of Effect: %s\n",area);
  361.     if (save) fprintf(outfile,"Saving Throw: %s\n",save);
  362.     fprintf(outfile,"\n");
  363.     for (int i=0; i<lines; i++)
  364.     fprintf(outfile,"%s\n",description[i]);
  365.     kill_desc();
  366. }
  367.  
  368. void priestspell::s_print(char *buffer) {
  369.     int i;
  370.  
  371.     if (desc_loaded==false) get_desc();
  372.  
  373.     sprintf(buffer,"%s (%s)\n",name,school);
  374.     i=strlen(buffer);
  375.     if (reversible) sprintf(buffer+i,"Reversible\n");
  376.     i=strlen(buffer);
  377.     if (source) sprintf(buffer+i,"  from %s\n",source);
  378.     i=strlen(buffer);
  379.     sprintf(buffer+i,"Level: %d\n",level);
  380.     i=strlen(buffer);
  381.     if (sphere) sprintf(buffer+i,"Sphere: %s\n",sphere);
  382.     i=strlen(buffer);
  383.     if (range) sprintf(buffer+i,"Range: %s\n",range);
  384.     i=strlen(buffer);
  385.     if (components) sprintf(buffer+i,"Components: %s\n",components);
  386.     i=strlen(buffer);
  387.     if (duration) sprintf(buffer+i,"Duration: %s\n",duration);
  388.     i=strlen(buffer);
  389.     if (casttime) sprintf(buffer+i,"Casting Time: %s\n",casttime);
  390.     i=strlen(buffer);
  391.     if (area) sprintf(buffer+i,"Area of Effect: %s\n",area);
  392.     i=strlen(buffer);
  393.     if (save) sprintf(buffer+i,"Saving Throw: %s\n",save);
  394.     i=strlen(buffer);
  395.     sprintf(buffer+i," \n");
  396.     i=strlen(buffer);
  397.     for (int j=0; j<lines; j++) {
  398.     if ((strlen(description[j])==0) || 
  399.         ((strlen(description[j])==1) && (description[j][0]==' '))) 
  400.         sprintf(buffer+i," \n");
  401.     else {
  402.         sprintf(buffer+i,"%s ",description[j]);
  403.         i=strlen(buffer);
  404.         if ((j<lines-1) && 
  405.         ((description[j+1][0]==' ') || 
  406.          (strlen(description[j+1])<2) ||
  407.          (description[j+1][0]=='\t')))
  408.         sprintf(buffer+i," \n");
  409.     }
  410.     i=strlen(buffer);
  411.     }
  412.     kill_desc();
  413. }
  414.  
  415. void priestspell::f_print_header(FILE *outfile) {
  416.     fprintf(outfile,"%17.17s ",name);
  417.     if (reversible) fprintf(outfile,"(R) ");
  418.     else fprintf(outfile,"    ");
  419.     fprintf(outfile,"15.15s ",school);
  420.     fprintf(outfile,"%5.5s ",casttime);
  421.     fprintf(outfile,"%7.7s ",components);
  422.     fprintf(outfile,"%15.15s ",range);
  423.     fprintf(outfile,"%15.15s ",duration);
  424.     fprintf(outfile,"%15.15s ",area);
  425.     fprintf(outfile,"%4.4s ",save);
  426.     fprintf(outfile,"\n");
  427. }
  428.  
  429. void priestspell::quicksave(FILE *outfile) {
  430.     fprintf(outfile,"P\n");
  431.     fprintf(outfile,"%s\n",name);
  432.     fprintf(outfile,"%s\n",source_file);
  433.     fprintf(outfile,"%s\n",school);
  434.     fprintf(outfile,"%s\n",sphere);
  435.     if (reversible) fprintf(outfile,"R\n");
  436.     else fprintf(outfile,"N\n");
  437.     if (source) fprintf(outfile,"%s",source);
  438.     fprintf(outfile,"\n");
  439.     fprintf(outfile,"%d\n",level);
  440.     fprintf(outfile,"%s\n",range);
  441.     fprintf(outfile,"%s\n",components);
  442.     fprintf(outfile,"%s\n",duration);
  443.     fprintf(outfile,"%s\n",casttime);
  444.     fprintf(outfile,"%s\n",area);
  445.     fprintf(outfile,"%s\n",save);
  446.     fprintf(outfile,"%d\n",lines);
  447.     fwrite(&desc_pos,sizeof(fpos_t),1,outfile);
  448. }
  449.  
  450. // load priestspell, with "P" line already read
  451. void priestspell::quickload(FILE *infile) {
  452.     char buffer[256];
  453.  
  454.     fgets_no_cr(buffer,256,infile);
  455.     if (buffer[0]!=(char)0) name = strdup(buffer);
  456.     fgets_no_cr(buffer,256,infile);
  457.     if (buffer[0]!=(char)0) source_file = strdup(buffer);
  458.     fgets_no_cr(buffer,256,infile);
  459.     if (buffer[0]!=(char)0) school = strdup(buffer);
  460.     fgets_no_cr(buffer,256,infile);
  461.     if (buffer[0]!=(char)0) sphere = strdup(buffer);
  462.     fgets_no_cr(buffer,256,infile);
  463.     if (buffer[0]=='R') reversible=true;
  464.     else reversible = false;
  465.     fgets_no_cr(buffer,256,infile);
  466.     if (buffer[0]!=(char)0) source = strdup(buffer);
  467.     fgets(buffer,256,infile);
  468.     sscanf(buffer,"%d",&level);
  469.     fgets_no_cr(buffer,256,infile);
  470.     if (buffer[0]!=(char)0) range = strdup(buffer);
  471.     fgets_no_cr(buffer,256,infile);
  472.     if (buffer[0]!=(char)0) components = strdup(buffer);
  473.     fgets_no_cr(buffer,256,infile);
  474.     if (buffer[0]!=(char)0) duration = strdup(buffer);
  475.     fgets_no_cr(buffer,256,infile);
  476.     if (buffer[0]!=(char)0) casttime = strdup(buffer);
  477.     fgets_no_cr(buffer,256,infile);
  478.     if (buffer[0]!=(char)0) area = strdup(buffer);
  479.     fgets_no_cr(buffer,256,infile);
  480.     if (buffer[0]!=(char)0) save = strdup(buffer);
  481.     fgets(buffer,256,infile);
  482.     sscanf(buffer,"%d",&lines);
  483.     fread(&desc_pos,sizeof(fpos_t),1,infile);
  484. }
  485.  
  486. void priestspell::f_read(FILE *infile) {
  487.     char buffer[256];
  488.     
  489.     do {
  490.     fgets_no_cr(buffer,256,infile);
  491.     } while ((strlen(buffer)<=1) && !feof(infile));
  492.     if (feof(infile)) return;
  493.  
  494.     char *l=strrchr(buffer,'(');
  495.     char *m=strrchr(buffer,')');
  496.     if ((m==NULL) || (l==NULL)) {
  497.     if (buffer[0]!=(char)0) name = strdup(buffer);
  498.     }
  499.     else {
  500.     int namelen=strlen(buffer)-strlen(l);
  501.     name=new char[namelen];
  502.     name[namelen-1]=(char)0;
  503.     strncpy(name,buffer,namelen-1);
  504.     int schoollen=strlen(l)-strlen(m);
  505.     school=new char[schoollen];
  506.     school[schoollen-1]=(char)0;
  507.     strncpy(school,l+1,schoollen-1);
  508.     }
  509.     fgets_no_cr(buffer,256,infile);
  510.     if (strncmp(buffer,"Reversible",10)==0) {
  511.     reversible=true;
  512.     fgets_no_cr(buffer,256,infile);
  513.     }
  514.     while ((strlen(buffer)>1) && !feof(infile)) {
  515.     if (strstr(buffer,"Range:"))
  516.         range=strdup(buffer+7);
  517.     else if (strstr(buffer,"Components:"))
  518.         components=strdup(buffer+12);
  519.     else if (strstr(buffer,"Duration:"))
  520.         duration=strdup(buffer+10);
  521.     else if (strstr(buffer,"Casting Time:"))
  522.         casttime=strdup(buffer+14);
  523.     else if (strstr(buffer,"Area of Effect:"))
  524.         area=strdup(buffer+16);
  525.     else if (strstr(buffer,"Saving Throw:"))
  526.         save=strdup(buffer+14);
  527.     else if (strstr(buffer,"Sphere:"))
  528.         sphere=strdup(buffer+8);
  529.     else if (strstr(buffer,"School:"))
  530.         school=strdup(buffer+8);
  531.     else if (strstr(buffer,"  from "))
  532.         source=strdup(buffer+7);
  533.     else if (strstr(buffer,"Level:"))
  534.         sscanf(buffer+7,"%d",&level);
  535.     
  536.     fgets_no_cr(buffer,256,infile);
  537.     }
  538.     fgetpos(infile,&desc_pos);
  539.     while ((strncmp(buffer,"-----",5)!=0) && !feof(infile)) {
  540.     fgets(buffer,256,infile);
  541.     }
  542. }
  543.  
  544. void priest_to_mage(magespell &y, priestspell &x) {
  545.   if (x.name) y.name=strdup(x.name);
  546.   y.level=x.level;
  547.   if (x.range) y.range=strdup(x.range);
  548.   if (x.area) y.area=strdup(x.area);
  549.   if (x.source) y.source=strdup(x.source);
  550.   if (x.source_file) y.source_file=strdup(x.source_file);
  551.   y.desc_pos=x.desc_pos;
  552.   if (x.school) y.school=strdup(x.school);
  553.   if (x.duration) y.duration=strdup(x.duration);
  554.   if (x.components) y.components=strdup(x.components);
  555.   if (x.casttime) y.casttime=strdup(x.casttime);
  556.   if (x.save) y.save=strdup(x.save);
  557.   y.reversible=x.reversible;
  558.   for (int i=0; i<x.lines; i++)
  559.     y.add_desc(x.description[i]);
  560. }
  561.  
  562. spellbook::spellbook() {
  563.     first=last=NULL;
  564.     name=NULL;
  565. }
  566.  
  567. spellbook::spellbook(spellbook &s) {
  568.   first=last=NULL;
  569.   if (s.name) name=strdup(s.name);
  570.   else name=NULL;
  571.   *this += s;
  572. }
  573.  
  574. spellbook::~spellbook() {
  575.   spelllist *i=first;
  576.   spelllist *j;
  577.     
  578.   while (i!=NULL) {
  579.     j=i->next;
  580.     delete i;
  581.     i=j;
  582.   }
  583.   if (name) delete name;
  584. }
  585.  
  586. spelllist *spellbook::add_spell(spell &x, spelllist *where) {
  587.     spelllist *sl;
  588.  
  589.     sl=new spelllist;
  590.  
  591.     // spell is given.
  592.     sl->s=&x;
  593.  
  594.     if (where==NULL) {   // add at end.
  595.     sl->next=NULL;
  596.     sl->prev=last;
  597.     if (last!=NULL) last->next=sl;
  598.     if (first==NULL) first=sl;
  599.     last=sl;
  600.     } else {  // add after "where"
  601.     sl->next=where->next;
  602.     sl->prev=where;
  603.     if (where->next!=NULL) where->next->prev=sl;
  604.     where->next=sl;
  605.     if (where==last) last=sl;
  606.     }
  607.     return(sl);
  608. }
  609.  
  610.  
  611. // delete a spell given its spelllist entry
  612. void spellbook::del_spell(spelllist *sl) {
  613.   if (sl->next!=NULL) sl->next->prev=sl->prev;
  614.   if (sl->prev!=NULL) sl->prev->next=sl->next;
  615.   if (first==sl) first=sl->next;
  616.   if (last==sl) last=sl->prev;
  617.   delete sl;
  618. }
  619.  
  620. // find and delete one reference to spell x in book
  621. void spellbook::del_spell(spell &x) {
  622.   spelllist *i;
  623.   
  624.   for (i=first; i!=NULL; i=i->next) 
  625.     if (i->s==&x) {
  626.       del_spell(i);
  627.       return;
  628.     }
  629. }
  630.  
  631. spellbook& spellbook::operator +=(spell &x) {
  632.     add_spell(x);
  633.     return(*this);
  634. }
  635.  
  636. spellbook& spellbook::operator +=(spellbook &x) {
  637.     for (spelllist *i=x.first; i!=NULL; i=i->next) 
  638.     add_spell(*(i->s));
  639.     return(*this);
  640. }
  641.  
  642. spellbook& spellbook::operator -=(spell &x) {
  643.   del_spell(x);
  644.   return(*this);
  645. }
  646.  
  647. spellbook& spellbook::operator -=(spellbook &x) {
  648.     for (spelllist *i=x.first; i!=NULL; i=i->next) 
  649.     del_spell(*(i->s));
  650.     return(*this);
  651. }
  652.  
  653. // read full spell listings; return number of spells that
  654. // contained errors.
  655. // return -1 if can't read the file
  656. int spellbook::read_book(char *filename) {
  657.     FILE *infile;
  658.     fpos_t pos;
  659.     char buffer[256];
  660.     int errors = 0;
  661.  
  662.     // clear out old book, if present.
  663.     this->~spellbook();
  664.     first=last=NULL;
  665.     name=NULL;
  666.     if ((infile=fopen(filename,"r"))==NULL) return(-1);
  667.  
  668.     // get spellbook name from first line of file, if there
  669.     fgetpos(infile,&pos);
  670.     fgets_no_cr(buffer,256,infile);
  671.     if (strstr(buffer,"Title:  ")==NULL) {
  672.     name=NULL;
  673.     fsetpos(infile,&pos);
  674.     }
  675.     else name=strdup(buffer+8);
  676.  
  677.     while (!feof(infile)) {
  678.     priestspell *x;
  679.     x = new priestspell;
  680.     x->f_read(infile);
  681.     if (x->level== -1) errors++;
  682.     else {
  683.         x->source_file=strdup(filename);
  684.         if (x->sphere) add_spell(*x);
  685.         else {  // was actually a magespell.
  686.         magespell *y;
  687.         y=new magespell;
  688.         priest_to_mage(*y,*x);
  689.         add_spell(*y);
  690.         delete x;
  691.         }
  692.     }
  693.     }
  694.     fclose(infile);
  695.     return(errors);
  696. }
  697.  
  698. boolean spellbook::quickload(char *filename) {
  699.     FILE *infile;
  700.     char buffer[256];
  701.     priestspell *ps;
  702.     magespell *ms;
  703.  
  704.     // clear out old book, if present.
  705.     this->~spellbook();
  706.     first=last=NULL;
  707.     name=NULL;
  708.     if ((infile=fopen(filename,"rb"))==NULL) return(false);
  709.  
  710.     // get spellbook name from first line of file
  711.     fgets_no_cr(buffer,256,infile);
  712.     if (buffer[0]!=(char)0) name=strdup(buffer);
  713.     else name=NULL;
  714.  
  715.     fgets(buffer,256,infile);
  716.     while (!feof(infile)) {
  717.     if (buffer[0]=='M') {
  718.         ms = new magespell;
  719.         ms->quickload(infile);
  720.         add_spell(*ms);
  721.     }
  722.     else {
  723.         ps = new priestspell;
  724.         ps->quickload(infile);
  725.         add_spell(*ps);
  726.     }
  727.     fgets(buffer,256,infile);
  728.     }
  729.         
  730.     fclose(infile);
  731.     return(true);
  732. }
  733.  
  734. boolean spellbook::quicksave(char *filename) {
  735.     FILE *outfile;
  736.  
  737.     if ((outfile=fopen(filename,"wb"))==NULL) return(false);
  738.  
  739.     if (name) fprintf(outfile,"%s",name);
  740.     fprintf(outfile,"\n");
  741.  
  742.     for (spelllist *i=first; i!=NULL; i=i->next) 
  743.     i->s->quicksave(outfile);
  744.     
  745.     fclose(outfile);
  746.     return(true);
  747. }
  748.  
  749. // look up a spell by title.
  750. spell *spellbook::lookup(char *sname) {
  751.     for (spelllist *i=first; i!=NULL; i=i->next) 
  752.     if (strcmp(i->s->name,sname)==0) return(i->s);
  753.     return(NULL);
  754. }
  755.  
  756. // read spellbook from list of spells... return number of spells
  757. // not found in masterlist
  758. // return -1 if unopenable file.
  759. int spellbook::read_titles(char *filename, spellbook *masterlist) {
  760.     FILE *infile;
  761.     fpos_t pos;
  762.     char buffer[256];
  763.     int errors=0;
  764.  
  765.     // clear out old book, if present.
  766.     this->~spellbook();
  767.     first=last=NULL;
  768.     name=NULL;
  769.     if ((infile=fopen(filename,"r"))==NULL) return(-1);
  770.  
  771.     // get spellbook name from first line of file, if there
  772.     fgetpos(infile,&pos);
  773.     fgets_no_cr(buffer,256,infile);
  774.     if (strstr(buffer,"Title:  ")==NULL) {
  775.     name=NULL;
  776.     fsetpos(infile,&pos);
  777.     }
  778.     else name=strdup(buffer+8);
  779.  
  780.     while (!feof(infile)) {
  781.     fgets_no_cr(buffer,256,infile);
  782.     if (!feof(infile)) {
  783.         spell *ns;
  784.         ns=masterlist->lookup(buffer);
  785.         if (ns==NULL) errors++;
  786.         else add_spell(*ns);
  787.     }
  788.     }
  789.     fclose(infile);
  790.     return(errors);
  791. }
  792.  
  793. // return 0 if OK, -1 if error.
  794. int spellbook::print_titles(char *filename) {
  795.     FILE *outfile;
  796.     
  797.     if ((outfile=fopen(filename,"w"))==NULL)
  798.     return(-1);
  799.     
  800.     if (name) fprintf(outfile,"Title:  %s\n",name);
  801.     else fprintf(outfile,"\n");
  802.     for (spelllist *i=first; i!=NULL; i=i->next)
  803.     fprintf(outfile,"%s\n",i->s->name);
  804.     
  805.     fclose(outfile);
  806.     return(0);
  807. }
  808.  
  809. // save an entire spellbook 
  810. // return 0 if ok, -1 if error.
  811. int spellbook::print_book(char *filename) {
  812.     FILE *outfile;
  813.     
  814.     if ((outfile=fopen(filename,"w"))==NULL)
  815.     return(-1);
  816.     
  817.     if (name) fprintf(outfile,"Title:  %s\n",name);
  818.     for (spelllist *i=first; i!=NULL; i=i->next) {
  819.     i->s->f_print(outfile);
  820.     if (i->next!=NULL) fprintf(outfile,"-----\n");
  821.     }
  822.     
  823.     fclose(outfile);
  824.     return(0);
  825. }
  826.  
  827. // print out abbreviated spellbook
  828. boolean spellbook::print_abbrev(char *filename) {
  829.     FILE *outfile;
  830.     
  831.     if ((outfile=fopen(filename,"w"))==NULL) 
  832.     return(false);
  833.     
  834.     if (name) fprintf(outfile,"%s\n",name);
  835.     else fprintf(outfile,"\n");
  836.     for (spelllist *i=first; i!=NULL; i=i->next) {
  837.     i->s->f_print_header(outfile);
  838.     }
  839.     
  840.     fclose(outfile);
  841.     return(true);
  842. }
  843.  
  844. // read in a book, guessing if full or title list.
  845. // return # of spells unreadable.
  846. // return -1 if other error
  847. int spellbook::read(char *filename, spellbook *masterlist) {
  848.     int rc;
  849.  
  850.     rc = read_book(filename);
  851.     if (rc==0) return(0);
  852.     this->~spellbook();
  853.     first=last=NULL;
  854.     name=NULL;
  855.     if (masterlist) return(read_titles(filename,masterlist));
  856.     else return(rc);
  857. }
  858.  
  859. // get master list of spells from file
  860. spellbook *get_master_list(char *master_name) {
  861.     spellbook *ml;
  862.     spellbook *x;
  863.     char buffer[256];
  864.     FILE *infile;
  865.  
  866.     ml=new spellbook;    
  867.     if (ml==NULL) return(NULL);
  868.     ml->name=strdup("Master Spell List");
  869.     x=new spellbook;
  870.     if (x==NULL) return(NULL);
  871.  
  872.     if ((infile=fopen(master_name,"r"))==NULL) return(NULL);
  873.  
  874.     while (!feof(infile)) {
  875.     fgets_no_cr(buffer,256,infile);
  876.     if ((!feof(infile)) && (buffer[0]!=';')) {
  877.         x->read_book(buffer);
  878.         (*ml)+=(*x);
  879.     }
  880.     }
  881.     
  882.     return(ml);
  883. }
  884.  
  885.