/[enigma]/enigma/lib-src/oxydlib/Level.cpp
ViewVC logotype

Diff of /enigma/lib-src/oxydlib/Level.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.4 by dheck, Wed Jun 18 10:07:53 2003 UTC revision 1.5 by reallysoft, Wed Jun 25 19:31:59 2003 UTC
# Line 19  Line 19 
19  #include "Level.h"  #include "Level.h"
20  #include <stdio.h>  #include <stdio.h>
21    
22    namespace OxydLib {
23    
24  using namespace std;  using namespace std;
25    
26  Marble::Marble()  Marble::Marble()
# Line 88  bool RubberBand::operator == (const Rubb Line 90  bool RubberBand::operator == (const Rubb
90      }      }
91    } else {    } else {
92      if (getSecondEndPieceX() != other.getSecondEndPieceX() ||      if (getSecondEndPieceX() != other.getSecondEndPieceX() ||
93          getSecondEndPieceY() != other.getSecondEndPieceY()) {          getSecondEndPieceY() != other.getSecondEndPieceY()) {
94        return false;        return false;
95      }      }
96    }    }
# Line 101  bool RubberBand::operator != (const Rubb Line 103  bool RubberBand::operator != (const Rubb
103    return !(*this == other);    return !(*this == other);
104  }  }
105    
106    Block::Block()
 ScrambleItem::ScrambleItem()  
107  : m_x(0)  : m_x(0)
108  , m_y(0)  , m_y(0)
 , m_dir(ScrambleDir_Up)  
109  {  {
110  }  }
111    
112  ScrambleItem::ScrambleItem(unsigned int x, unsigned int y, ScrambleDir dir)  Block::Block(unsigned int x, unsigned int y)
113  : m_x(x)  : m_x(x)
114  , m_y(y)  , m_y(y)
 , m_dir(dir)  
115  {  {
116  }  }
117    
118  ScrambleItem::~ScrambleItem()  Block::~Block()
119  {  {
120  }  }
121    
122  Oscillator::Oscillator()  bool Block::operator < (const Block &other) const
123    {
124      if (getY() != other.getY()) {
125        return getY() < other.getY();
126      }
127    
128      if (getX() != other.getX()) {
129        return getX() < other.getX();
130      }
131    
132      return false;
133    }
134    
135    bool Block::operator == (const Block &other) const
136    {
137      if (getX() != other.getX()) {
138        return false;
139      }
140    
141      if (getY() != other.getY()) {
142        return false;
143      }
144    
145      return true;
146    }
147    
148    bool Block::operator != (const Block &other) const
149    {
150      return !(*this == other);
151    }
152    
153    ScrambleItem::ScrambleItem()
154  : m_x(0)  : m_x(0)
155  , m_y(0)  , m_y(0)
156  , m_period(0)  , m_dir(Direction_Up)
157  {  {
158  }  }
159    
160  Oscillator::Oscillator(unsigned int x, unsigned int y, unsigned int period)  ScrambleItem::ScrambleItem(unsigned int x, unsigned int y, Direction dir)
161  : m_x(x)  : m_x(x)
162  , m_y(y)  , m_y(y)
163  , m_period(period)  , m_dir(dir)
164  {  {
165  }  }
166    
167  Oscillator::~Oscillator()  ScrambleItem::~ScrambleItem()
168  {  {
169  }  }
170    
171  bool Oscillator::operator < (const Oscillator &other) const  Laser::Laser()
172    : m_dir(Direction_Up)
173    , m_bOn(false)
174  {  {
175    if (getY() != other.getY()) {  }
176      return getY() < other.getY();  
177    Laser::Laser(Direction dir, bool bOn)
178    : m_dir(dir)
179    , m_bOn(bOn)
180    {
181    }
182    
183    Laser::~Laser()
184    {
185    }
186    
187    bool Laser::operator == (const Laser &other) const
188    {
189      if (getDir() != other.getDir()) {
190        return false;
191    }    }
192    
193    if (getX() != other.getX()) {    if (getOn() != other.getOn()) {
194      return getX() < other.getX();      return false;
195    }    }
196    
197    return false;    return true;
198    }
199    
200    bool Laser::operator != (const Laser &other) const
201    {
202      return !(*this == other);
203    }
204    
205    Oscillator::Oscillator()
206    : m_period(0)
207    , m_bOn(true)
208    {
209    }
210    
211    Oscillator::Oscillator(unsigned int period, bool bOn)
212    : m_period(period)
213    , m_bOn(bOn)
214    {
215    }
216    
217    Oscillator::~Oscillator()
218    {
219  }  }
220    
221  bool Oscillator::operator == (const Oscillator &other) const  bool Oscillator::operator == (const Oscillator &other) const
222  {  {
223    return    if (getPeriod() != other.getPeriod()) {
224      getX() == other.getX() &&      return false;
225      getY() == other.getY() &&    }
226      getPeriod() == other.getPeriod();  
227      if (getOn() != other.getOn()) {
228        return false;
229      }
230    
231      return true;
232  }  }
233    
234  bool Oscillator::operator != (const Oscillator &other) const  bool Oscillator::operator != (const Oscillator &other) const
# Line 172  SignalLocation::SignalLocation() Line 244  SignalLocation::SignalLocation()
244  }  }
245    
246  SignalLocation::SignalLocation(unsigned int x, unsigned int y,  SignalLocation::SignalLocation(unsigned int x, unsigned int y,
247                                 GridType gridType)                                 GridType gridType)
248  : m_x(x)  : m_x(x)
249  , m_y(y)  , m_y(y)
250  , m_gridType(gridType)  , m_gridType(gridType)
# Line 241  void Grid::resize(unsigned int width, un Line 313  void Grid::resize(unsigned int width, un
313    for (unsigned int y = 0; y < getHeight(); y++) {    for (unsigned int y = 0; y < getHeight(); y++) {
314      for (unsigned int x = 0; x < getWidth(); x++) {      for (unsigned int x = 0; x < getWidth(); x++) {
315        if (x < oldWidth && y < oldHeight) {        if (x < oldWidth && y < oldHeight) {
316          set(x, y, oldData[y * oldWidth + x]);          set(x, y, oldData[y * oldWidth + x]);
317        } else {        } else {
318          set(x, y, 0x00);          set(x, y, 0x00);
319        }        }
320      }      }
321    }    }
# Line 275  namespace Line 347  namespace
347    };    };
348    
349    bool unpackSignalLocation(const Level &level,    bool unpackSignalLocation(const Level &level,
350                              unsigned int packedSignalLocation,                              unsigned int packedSignalLocation,
351                              SignalLocation *pSignalLocation,                              SignalLocation *pSignalLocation,
352                              bool *pWithinGrid,                              bool *pWithinGrid,
353                              string *pMsg)                              string *pMsg)
354    {    {
355      if (packedSignalLocation & 0xc000) {      if (packedSignalLocation & 0xc000) {
356        if (pMsg) {        if (pMsg) {
357          pMsg->assign("High bits set in signal location.");          pMsg->assign("High bits set in signal location.");
358        }        }
359        return false;        return false;
360      }      }
# Line 297  namespace Line 369  namespace
369        // This can happen.        // This can happen.
370        /*        /*
371        if (pMsg) {        if (pMsg) {
372          pMsg->assign("Signal block number too high.");          pMsg->assign("Signal block number too high.");
373        }        }
374        return false;        return false;
375        */        */
# Line 317  namespace Line 389  namespace
389    }    }
390    
391    bool packSignalLocation(const Level &level,    bool packSignalLocation(const Level &level,
392                            const SignalLocation &signalLocation,                            const SignalLocation &signalLocation,
393                            unsigned int *pPackedSignalLocation,                            unsigned int *pPackedSignalLocation,
394                            string *pMsg)                            string *pMsg)
395    {    {
396      unsigned int blockNum =      unsigned int blockNum =
397        signalLocation.getY() * level.getWidth() + signalLocation.getX();        signalLocation.getY() * level.getWidth() + signalLocation.getX();
398    
399      if (blockNum > 0x1fff) {      if (blockNum > 0x1fff) {
400        if (pMsg) {        if (pMsg) {
401          pMsg->assign("Signal block number too high.");          pMsg->assign("Signal block number too high.");
402        }        }
403        return false;        return false;
404      }      }
# Line 337  namespace Line 409  namespace
409      case GridType_Objects: gridTypeBit = 1; break;      case GridType_Objects: gridTypeBit = 1; break;
410      default:      default:
411        if (pMsg) {        if (pMsg) {
412          pMsg->assign("Invalid grid type for signal location.");          pMsg->assign("Invalid grid type for signal location.");
413        }        }
414        return false;        return false;
415      }      }
# Line 348  namespace Line 420  namespace
420    
421      return true;      return true;
422    }    }
423    
424      Laser s_defaultLasers[3] = {
425        Laser(Direction_Up, false),
426        Laser(Direction_Down, false),
427        Laser(Direction_Right, false)
428      };
429  }  }
430    
431  Level::Level()  Level::Level()
# Line 379  void Level::clear() Line 457  void Level::clear()
457    m_bWalkThroughPuzzle = false;    m_bWalkThroughPuzzle = false;
458    m_scrambleItems.clear();    m_scrambleItems.clear();
459    
460      for (int nLaser = 0; nLaser < 3; nLaser++) {
461        m_lasers[nLaser] = s_defaultLasers[nLaser];
462      }
463    
464    for (int nNote = 0; nNote < 2; nNote++) {    for (int nNote = 0; nNote < 2; nNote++) {
465      for (int nLang = Language_First;      for (int nLang = Language_First;
466           nLang <= Language_Last;           nLang <= Language_Last;
467           nLang++) {           nLang++) {
468        m_noteText[nNote][nLang].assign("");        m_noteText[nNote][nLang].assign("");
469      }      }
470    }    }
# Line 436  int Level::getNumRubberBands(GameMode ga Line 518  int Level::getNumRubberBands(GameMode ga
518  }  }
519    
520  const RubberBand &Level::getRubberBand(GameMode gameMode,  const RubberBand &Level::getRubberBand(GameMode gameMode,
521                                         int nRubberBand) const                                         int nRubberBand) const
522  {  {
523    return m_rubberBands[gameMode][nRubberBand];    return m_rubberBands[gameMode][nRubberBand];
524  }  }
525    
526  RubberBand *Level::getRubberBandForWrite(GameMode gameMode,  RubberBand *Level::getRubberBandForWrite(GameMode gameMode,
527                                           int nRubberBand)                                           int nRubberBand)
528  {  {
529    return &m_rubberBands[gameMode][nRubberBand];    return &m_rubberBands[gameMode][nRubberBand];
530  }  }
531    
532  void Level::addRubberBand(GameMode gameMode,  void Level::addRubberBand(GameMode gameMode,
533                            const RubberBand &rubberBand,                            const RubberBand &rubberBand,
534                            int nRubberBand)                            int nRubberBand)
535  {  {
536    vector<RubberBand> &vec = m_rubberBands[gameMode];    vector<RubberBand> &vec = m_rubberBands[gameMode];
537    
# Line 472  int Level::getBlackRubberBandPieceNatura Line 554  int Level::getBlackRubberBandPieceNatura
554  }  }
555    
556  void Level::setBlackRubberBandPieceNaturalLength(GameMode gameMode,  void Level::setBlackRubberBandPieceNaturalLength(GameMode gameMode,
557                                                   int naturalLength)                                                   int naturalLength)
558  {  {
559    m_blackRubberBandPieceNaturalLength[gameMode] = naturalLength;    m_blackRubberBandPieceNaturalLength[gameMode] = naturalLength;
560  }  }
# Line 493  int Level::getWhiteRubberBandPieceNatura Line 575  int Level::getWhiteRubberBandPieceNatura
575  }  }
576    
577  void Level::setWhiteRubberBandPieceNaturalLength(GameMode gameMode,  void Level::setWhiteRubberBandPieceNaturalLength(GameMode gameMode,
578                                                   int naturalLength)                                                   int naturalLength)
579  {  {
580    m_whiteRubberBandPieceNaturalLength[gameMode] = naturalLength;    m_whiteRubberBandPieceNaturalLength[gameMode] = naturalLength;
581  }  }
# Line 514  int Level::getRubberBandObjectNaturalLen Line 596  int Level::getRubberBandObjectNaturalLen
596  }  }
597    
598  void Level::setRubberBandObjectNaturalLength(GameMode gameMode,  void Level::setRubberBandObjectNaturalLength(GameMode gameMode,
599                                               int naturalLength)                                               int naturalLength)
600  {  {
601    m_rubberBandObjectNaturalLength[gameMode] = naturalLength;    m_rubberBandObjectNaturalLength[gameMode] = naturalLength;
602  }  }
# Line 565  ScrambleItem *Level::getScrambleItemForW Line 647  ScrambleItem *Level::getScrambleItemForW
647  }  }
648    
649  void Level::addScrambleItem(const ScrambleItem &scrambleItem,  void Level::addScrambleItem(const ScrambleItem &scrambleItem,
650                              int nScrambleItem)                              int nScrambleItem)
651  {  {
652    vector<ScrambleItem> &vec = m_scrambleItems;    vector<ScrambleItem> &vec = m_scrambleItems;
653    
# Line 582  void Level::removeScrambleItem(int nScra Line 664  void Level::removeScrambleItem(int nScra
664    vec.erase(vec.begin() + nScrambleItem);    vec.erase(vec.begin() + nScrambleItem);
665  }  }
666    
667    const Laser &Level::getLaser(int nLaser) const
668    {
669      return m_lasers[nLaser];
670    }
671    
672    void Level::setLaser(int nLaser, const Laser &laser)
673    {
674      m_lasers[nLaser] = laser;
675    }
676    
677    const OscillatorMap &Level::getOscillators(GameMode gameMode) const
678    {
679      return m_oscillators[gameMode];
680    }
681    
682    OscillatorMap *Level::getOscillatorsForWrite(GameMode gameMode)
683    {
684      return &m_oscillators[gameMode];
685    }
686    
687  void Level::getSenders(set<SignalLocation> *pSenders) const  void Level::getSenders(set<SignalLocation> *pSenders) const
688  {  {
689    pSenders->clear();    pSenders->clear();
# Line 603  int Level::getNumRecipients(const Signal Line 705  int Level::getNumRecipients(const Signal
705  }  }
706    
707  const SignalLocation &Level::getRecipient(const SignalLocation &sender,  const SignalLocation &Level::getRecipient(const SignalLocation &sender,
708                                            int nRecipient) const                                            int nRecipient) const
709  {  {
710    SignalMap::const_iterator findIter = m_signals.find(sender);    SignalMap::const_iterator findIter = m_signals.find(sender);
711    if (findIter == m_signals.end()) {    if (findIter == m_signals.end()) {
# Line 614  const SignalLocation &Level::getRecipien Line 716  const SignalLocation &Level::getRecipien
716  }  }
717    
718  void Level::setRecipient(const SignalLocation &sender,  void Level::setRecipient(const SignalLocation &sender,
719                           int nRecipient,                           int nRecipient,
720                           const SignalLocation &recipient)                           const SignalLocation &recipient)
721  {  {
722    SignalMap::iterator findIter = m_signals.find(sender);    SignalMap::iterator findIter = m_signals.find(sender);
723    SignalLocation *pRecipient = 0;    SignalLocation *pRecipient = 0;
# Line 626  void Level::setRecipient(const SignalLoc Line 728  void Level::setRecipient(const SignalLoc
728  }  }
729    
730  void Level::addRecipient(const SignalLocation &sender,  void Level::addRecipient(const SignalLocation &sender,
731                           const SignalLocation &recipient,                           const SignalLocation &recipient,
732                           int nRecipient)                           int nRecipient)
733  {  {
734    vector<SignalLocation> &vec = m_signals[sender];    vector<SignalLocation> &vec = m_signals[sender];
735    
# Line 639  void Level::addRecipient(const SignalLoc Line 741  void Level::addRecipient(const SignalLoc
741  }  }
742    
743  void Level::removeRecipient(const SignalLocation &sender,  void Level::removeRecipient(const SignalLocation &sender,
744                              int nRecipient)                              int nRecipient)
745  {  {
746    vector<SignalLocation> &vec = m_signals[sender];    vector<SignalLocation> &vec = m_signals[sender];
747    vec.erase(vec.begin() + nRecipient);    vec.erase(vec.begin() + nRecipient);
# Line 651  void Level::removeRecipient(const Signal Line 753  void Level::removeRecipient(const Signal
753  namespace  namespace
754  {  {
755    bool parseGrid(const ByteVec &compressedGrid,    bool parseGrid(const ByteVec &compressedGrid,
756                   Grid *pGrid,                   Grid *pGrid,
757                   string *pMsg)                   string *pMsg)
758    {    {
759      string msg;      string msg;
760      if (!pMsg) {      if (!pMsg) {
# Line 673  namespace Line 775  namespace
775    
776        switch (curByte) {        switch (curByte) {
777        case 0xFF: // long repeat        case 0xFF: // long repeat
778          {          {
779            if (curIn - 3 < -1) {            if (curIn - 3 < -1) {
780              pMsg->assign("Unexpected end of compressed grid data.");              pMsg->assign("Unexpected end of compressed grid data.");
781              return false;              return false;
782            }            }
783    
784            unsigned char repeatByte = compressedGrid[curIn];            unsigned char repeatByte = compressedGrid[curIn];
785            curIn--;            curIn--;
786    
787            int repeatCount = compressedGrid[curIn];            int repeatCount = compressedGrid[curIn];
788            curIn--;            curIn--;
789            repeatCount <<= 8;            repeatCount <<= 8;
790            repeatCount += compressedGrid[curIn];            repeatCount += compressedGrid[curIn];
791            repeatCount++;            repeatCount++;
792            curIn--;            curIn--;
793    
794            if (curOut - repeatCount < -1) {            if (curOut - repeatCount < -1) {
795              pMsg->assign("Too much compresed grid data writing repeated bytes.");              pMsg->assign("Too much compresed grid data writing repeated bytes.");
796              return false;              return false;
797            }            }
798    
799            int ii;            int ii;
800            for (ii = 0; ii < repeatCount; ii++) {            for (ii = 0; ii < repeatCount; ii++) {
801              data[curOut] = repeatByte;              data[curOut] = repeatByte;
802              curOut--;              curOut--;
803            }            }
804          }          }
805          break;          break;
806        case 0xFD: // short repeat        case 0xFD: // short repeat
807          {          {
808            if (curIn - 2 < -1) {            if (curIn - 2 < -1) {
809              pMsg->assign("Unexpected end of compressed grid data.");              pMsg->assign("Unexpected end of compressed grid data.");
810              return false;              return false;
811            }            }
812    
813            unsigned char repeatByte = compressedGrid[curIn];            unsigned char repeatByte = compressedGrid[curIn];
814            curIn--;            curIn--;
815    
816            int repeatCount = compressedGrid[curIn] + 1;            int repeatCount = compressedGrid[curIn] + 1;
817            curIn--;            curIn--;
818    
819            if (curOut - repeatCount < -1) {            if (curOut - repeatCount < -1) {
820              pMsg->assign("Too much compresed grid data writing repeated bytes.");              pMsg->assign("Too much compresed grid data writing repeated bytes.");
821              return false;              return false;
822            }            }
823    
824            int ii;            int ii;
825            for (ii = 0; ii < repeatCount; ii++) {            for (ii = 0; ii < repeatCount; ii++) {
826              data[curOut] = repeatByte;              data[curOut] = repeatByte;
827              curOut--;              curOut--;
828            }            }
829          }          }
830          break;          break;
831        case 0xFE: // pattern        case 0xFE: // pattern
832          {          {
833            if (curIn - 3 < -1) {            if (curIn - 3 < -1) {
834              pMsg->assign("Unexpected end of compressed grid data.");              pMsg->assign("Unexpected end of compressed grid data.");
835              return false;              return false;
836            }            }
837    
838            unsigned char patternBytes[2];            unsigned char patternBytes[2];
839    
840            patternBytes[0] = compressedGrid[curIn];            patternBytes[0] = compressedGrid[curIn];
841            curIn--;            curIn--;
842    
843            patternBytes[1] = compressedGrid[curIn];            patternBytes[1] = compressedGrid[curIn];
844            curIn--;            curIn--;
845    
846            int patternCount = compressedGrid[curIn] + 1;            int patternCount = compressedGrid[curIn] + 1;
847            curIn--;            curIn--;
848    
849            int bitPatternSize = (patternCount + 7) / 8;            int bitPatternSize = (patternCount + 7) / 8;
850            if (curIn - bitPatternSize < -1) {            if (curIn - bitPatternSize < -1) {
851              pMsg->assign("Unexpected end of compressed grid data.");              pMsg->assign("Unexpected end of compressed grid data.");
852              return false;              return false;
853            }            }
854    
855            if (curOut - patternCount < -1) {            if (curOut - patternCount < -1) {
856              pMsg->assign("Too much compresed grid data writing repeated bytes.");              pMsg->assign("Too much compresed grid data writing repeated bytes.");
857              return false;              return false;
858            }            }
859    
860            int ii;            int ii;
861            for (ii = patternCount - 1; ii >= 0; ii--) {            for (ii = patternCount - 1; ii >= 0; ii--) {
862              unsigned char bitPatternByte = compressedGrid[curIn];              unsigned char bitPatternByte = compressedGrid[curIn];
863              int bitNum = ii % 8;              int bitNum = ii % 8;
864              int bit = (bitPatternByte & (1 << bitNum)) >> bitNum;              int bit = (bitPatternByte & (1 << bitNum)) >> bitNum;
865              data[curOut] = patternBytes[bit];              data[curOut] = patternBytes[bit];
866              curOut--;              curOut--;
867    
868              if (ii % 8 == 0) {              if (ii % 8 == 0) {
869                curIn--;                curIn--;
870              }              }
871            }            }
872          }          }
873          break;          break;
874        default:        default:
875          {          {
876            if (curOut - 1 < -1) {            if (curOut - 1 < -1) {
877              pMsg->assign("Too much compresed grid data writing literal byte.");              pMsg->assign("Too much compresed grid data writing literal byte.");
878              return false;              return false;
879            }            }
880    
881            data[curOut] = curByte;            data[curOut] = curByte;
882            curOut--;            curOut--;
883          }          }
884        }        }
885      }      }
886    
# Line 789  namespace Line 891  namespace
891    
892      for (unsigned int y = 0; y < pGrid->getHeight(); y++) {      for (unsigned int y = 0; y < pGrid->getHeight(); y++) {
893        for (unsigned int x = 0; x < pGrid->getWidth(); x++) {        for (unsigned int x = 0; x < pGrid->getWidth(); x++) {
894          pGrid->set(x, y, data[y * pGrid->getWidth() + x]);          pGrid->set(x, y, data[y * pGrid->getWidth() + x]);
895        }        }
896      }      }
897    
# Line 797  namespace Line 899  namespace
899    }    }
900    
901    bool unparseGrid(const Grid &grid,    bool unparseGrid(const Grid &grid,
902                     ByteVec *pCompressedGrid,                     ByteVec *pCompressedGrid,
903                     string *pMsg)                     string *pMsg)
904    {    {
905      string msg;      string msg;
906      if (!pMsg) {      if (!pMsg) {
# Line 809  namespace Line 911  namespace
911      pCompressedGrid->resize(grid.getWidth() * grid.getHeight());      pCompressedGrid->resize(grid.getWidth() * grid.getHeight());
912      for (unsigned int y = 0; y < grid.getHeight(); y++) {      for (unsigned int y = 0; y < grid.getHeight(); y++) {
913        for (unsigned int x = 0; x < grid.getWidth(); x++) {        for (unsigned int x = 0; x < grid.getWidth(); x++) {
914          (*pCompressedGrid)[y * grid.getWidth() + x] = grid.get(x, y);          (*pCompressedGrid)[y * grid.getWidth() + x] = grid.get(x, y);
915        }        }
916      }      }
917    
# Line 817  namespace Line 919  namespace
919    }    }
920    
921    bool parseNumberList(const string &str,    bool parseNumberList(const string &str,
922                         vector<int> *pNumberList)                         vector<int> *pNumberList)
923    {    {
924      pNumberList->clear();      pNumberList->clear();
925    
# Line 825  namespace Line 927  namespace
927      int sz = str.size();      int sz = str.size();
928      while (cur < sz) {      while (cur < sz) {
929        if (str[cur] != '(') {        if (str[cur] != '(') {
930          return false;          return false;
931        }        }
932        cur++;        cur++;
933    
934        bool bEmpty = true;        bool bEmpty = true;
935        int num = 0;        int num = 0;
936        while (cur < sz && str[cur] >= '0' && str[cur] <= '9') {        while (cur < sz && str[cur] >= '0' && str[cur] <= '9') {
937          bEmpty = false;          bEmpty = false;
938          num *= 10;          num *= 10;
939          num += (str[cur] - '0');          num += (str[cur] - '0');
940          cur++;          cur++;
941        }        }
942    
943        if (cur < sz) {        if (cur < sz) {
944          if (str[cur] == ')') {          if (str[cur] == ')') {
945            pNumberList->push_back(bEmpty ? -1 : num);            pNumberList->push_back(bEmpty ? -1 : num);
946            cur++;            cur++;
947          } else {          } else {
948            return false;            return false;
949          }          }
950        } else {        } else {
951          return false;          return false;
952        }        }
953      }      }
954    
# Line 854  namespace Line 956  namespace
956    }    }
957    
958    void unparseNumberList(const vector<int> &numberList,    void unparseNumberList(const vector<int> &numberList,
959                           string *pStr)                           string *pStr)
960    {    {
961      for (int i = 0; i < (int)numberList.size(); i++) {      for (int i = 0; i < (int)numberList.size(); i++) {
962        int num = numberList[i];        int num = numberList[i];
963        pStr->append(1, '(');        pStr->append(1, '(');
964        if (num != -1) {        if (num != -1) {
965          char buf[1000];          char buf[1000];
966          sprintf(buf, "%d", num);          sprintf(buf, "%d", num);
967          pStr->append(buf);          pStr->append(buf);
968        }        }
969        pStr->append(1, ')');        pStr->append(1, ')');
970      }      }
# Line 930  bool parseLevel(const ByteVec &in, Level Line 1032  bool parseLevel(const ByteVec &in, Level
1032      case INFOOBJECTS:      case INFOOBJECTS:
1033        {        {
1034          if (cur1 + 2 > sz) {          if (cur1 + 2 > sz) {
1035            pMsg->assign("Unexpected end of level reading info length.");            pMsg->assign("Unexpected end of level reading info length.");
1036            return false;            return false;
1037          }          }
1038    
# Line 941  bool parseLevel(const ByteVec &in, Level Line 1043  bool parseLevel(const ByteVec &in, Level
1043        break;        break;
1044      case INFOGENERAL:      case INFOGENERAL:
1045        {        {
1046          infoSize = 68;          infoSize = 68;
1047          break;          break;
1048        }        }
1049      case INFOEND:      case INFOEND:
1050        {        {
1051          infoSize = 0;          infoSize = 0;
1052          break;          break;
1053        }        }
1054      }      }
# Line 958  bool parseLevel(const ByteVec &in, Level Line 1060  bool parseLevel(const ByteVec &in, Level
1060    
1061      infoArr[infoType].resize(infoSize);      infoArr[infoType].resize(infoSize);
1062      copy(in.begin() + cur1, in.begin() + cur1 + infoSize,      copy(in.begin() + cur1, in.begin() + cur1 + infoSize,
1063           infoArr[infoType].begin());           infoArr[infoType].begin());
1064      cur1 += infoSize;      cur1 += infoSize;
1065    
1066      foundAll = true;      foundAll = true;
# Line 984  bool parseLevel(const ByteVec &in, Level Line 1086  bool parseLevel(const ByteVec &in, Level
1086    
1087    for (int nMarble = 0; nMarble < 8; nMarble++) {    for (int nMarble = 0; nMarble < 8; nMarble++) {
1088      if (infoGeneral[0x04 + (nMarble * 8) + 0x02] != 0x00 ||      if (infoGeneral[0x04 + (nMarble * 8) + 0x02] != 0x00 ||
1089          infoGeneral[0x04 + (nMarble * 8) + 0x03] != 0x00 ||          infoGeneral[0x04 + (nMarble * 8) + 0x03] != 0x00 ||
1090          infoGeneral[0x04 + (nMarble * 8) + 0x06] != 0x00 ||          infoGeneral[0x04 + (nMarble * 8) + 0x06] != 0x00 ||
1091          infoGeneral[0x04 + (nMarble * 8) + 0x07] != 0x00) {          infoGeneral[0x04 + (nMarble * 8) + 0x07] != 0x00) {
1092        pMsg->assign("Unexpected non-zero byte in info-general.");        pMsg->assign("Unexpected non-zero byte in info-general.");
1093        return false;        return false;
1094      }      }
# Line 1002  bool parseLevel(const ByteVec &in, Level Line 1104  bool parseLevel(const ByteVec &in, Level
1104    
1105      {      {
1106        for (int i = 0; i < (int)infoSpecialVec.size() - 1; i++) {        for (int i = 0; i < (int)infoSpecialVec.size() - 1; i++) {
1107          if (infoSpecialVec[i] == 0x00) {          if (infoSpecialVec[i] == 0x00) {
1108            pMsg->assign("Info special contains a 0x00 byte before the end.");            pMsg->assign("Info special contains a 0x00 byte before the end.");
1109            return false;            return false;
1110          }          }
1111        }        }
1112      }      }
1113    
# Line 1017  bool parseLevel(const ByteVec &in, Level Line 1119  bool parseLevel(const ByteVec &in, Level
1119      string infoSpecial;      string infoSpecial;
1120      infoSpecial.resize(infoSpecialVec.size() - 1);      infoSpecial.resize(infoSpecialVec.size() - 1);
1121      copy(infoSpecialVec.begin(),      copy(infoSpecialVec.begin(),
1122           infoSpecialVec.begin() + (infoSpecialVec.size() - 1),           infoSpecialVec.begin() + (infoSpecialVec.size() - 1),
1123           infoSpecial.begin());           infoSpecial.begin());
1124    
1125      //printf("%s\n", infoSpecial.c_str());      //printf("%s\n", infoSpecial.c_str());
1126    
# Line 1028  bool parseLevel(const ByteVec &in, Level Line 1130  bool parseLevel(const ByteVec &in, Level
1130      int infoSpecialSize = infoSpecial.size();      int infoSpecialSize = infoSpecial.size();
1131      while (start < infoSpecialSize) {      while (start < infoSpecialSize) {
1132        while (start < infoSpecialSize &&        while (start < infoSpecialSize &&
1133               infoSpecial[start] == 0x20) {               infoSpecial[start] == 0x20) {
1134          start++;          start++;
1135        }        }
1136    
1137        if (start < infoSpecialSize) {        if (start < infoSpecialSize) {
1138          int end = start + 1;          int end = start + 1;
1139          bool inQuote = false;          bool inQuote = false;
1140          while (end < infoSpecialSize &&          while (end < infoSpecialSize &&
1141                 (infoSpecial[end] != 0x20 || inQuote)) {                 (infoSpecial[end] != 0x20 || inQuote)) {
1142            if (infoSpecial[end] == '"') {            if (infoSpecial[end] == '"') {
1143              inQuote = !inQuote;              inQuote = !inQuote;
1144            }            }
1145            end++;            end++;
1146          }          }
   
         // This can happen  
         /*  
         if (inQuote) {  
           pMsg->assign("Quote not terminated in info-special.");  
           return false;  
         }  
         */  
1147    
1148          string specialItem = infoSpecial.substr(start, end - start);          // This can happen
1149          specialItems.push_back(specialItem);          /*
1150            if (inQuote) {
1151              pMsg->assign("Quote not terminated in info-special.");
1152              return false;
1153            }
1154            */
1155    
1156          start = end;          string specialItem = infoSpecial.substr(start, end - start);
1157            specialItems.push_back(specialItem);
1158    
1159            start = end;
1160        }        }
1161      }      }
1162    
1163      /*      /*
1164      {      {
1165        for (int nItem = 0; nItem < (int)specialItems.size(); nItem++) {        for (int nItem = 0; nItem < (int)specialItems.size(); nItem++) {
1166          printf("  %s\n", specialItems[nItem].c_str());          printf("  %s\n", specialItems[nItem].c_str());
1167        }        }
1168      }      }
1169      */      */
# Line 1072  bool parseLevel(const ByteVec &in, Level Line 1174  bool parseLevel(const ByteVec &in, Level
1174      int numExtraRubberBandsArr[GameMode_Count];      int numExtraRubberBandsArr[GameMode_Count];
1175      {      {
1176        for (int curGameModeInt = GameMode_First;        for (int curGameModeInt = GameMode_First;
1177             curGameModeInt <= GameMode_Last;             curGameModeInt <= GameMode_Last;
1178             curGameModeInt++) {             curGameModeInt++) {
1179          GameMode curGameMode = GameMode(curGameModeInt);          GameMode curGameMode = GameMode(curGameModeInt);
1180          numMarblesArr[curGameMode] = 0;          numMarblesArr[curGameMode] = 0;
1181          numExtraRubberBandsArr[curGameMode] = 0;          numExtraRubberBandsArr[curGameMode] = 0;
1182          }
1183        }
1184    
1185        bool foundLaserArr[3];
1186        {
1187          for (int nLaser = 0; nLaser < 3; nLaser++) {
1188            foundLaserArr[nLaser] = false;
1189        }        }
1190      }      }
1191    
# Line 1085  bool parseLevel(const ByteVec &in, Level Line 1194  bool parseLevel(const ByteVec &in, Level
1194    
1195        // Easy and hard game mode        // Easy and hard game mode
1196        if (item.compare("[") == 0) {        if (item.compare("[") == 0) {
1197          if (gameMode != GameMode_Invalid) {          if (gameMode != GameMode_Invalid) {
1198            pMsg->assign("Hard game mode begin not expected.");            pMsg->assign("Hard game mode begin not expected.");
1199            return false;            return false;
1200          }          }
1201          gameMode = GameMode_Hard;          gameMode = GameMode_Hard;
1202          continue;          continue;
1203        }        }
1204    
1205        if (item.compare("]") == 0) {        if (item.compare("]") == 0) {
1206          if (gameMode != GameMode_Hard) {          if (gameMode != GameMode_Hard) {
1207            pMsg->assign("Hard game mode end not expected.");            pMsg->assign("Hard game mode end not expected.");
1208            return false;            return false;
1209          }          }
1210          gameMode = GameMode_Invalid;          gameMode = GameMode_Invalid;
1211          continue;          continue;
1212        }        }
1213    
1214        if (item.compare("{") == 0) {        if (item.compare("{") == 0) {
1215          if (gameMode != GameMode_Invalid) {          if (gameMode != GameMode_Invalid) {
1216            pMsg->assign("Easy game mode begin not expected.");            pMsg->assign("Easy game mode begin not expected.");
1217            return false;            return false;
1218          }          }
1219          gameMode = GameMode_Easy;          gameMode = GameMode_Easy;
1220          continue;          continue;
1221        }        }
1222    
1223        if (item.compare("}") == 0) {        if (item.compare("}") == 0) {
1224          if (gameMode != GameMode_Easy) {          if (gameMode != GameMode_Easy) {
1225            pMsg->assign("Easy game mode end not expected.");            pMsg->assign("Easy game mode end not expected.");
1226            return false;            return false;
1227          }          }
1228          gameMode = GameMode_Invalid;          gameMode = GameMode_Invalid;
1229          continue;          continue;
1230        }        }
1231    
1232        // Goal        // Goal
1233        if (item[0] == 'G') {        if (item[0] == 'G') {
1234          if (item.size() == 2 && item[1] == 'M') {          if (item.size() == 2 && item[1] == 'M') {
1235            if (gameMode != GameMode_Invalid) {            if (gameMode != GameMode_Invalid) {
1236              pMsg->assign("Goal must be the same in all game modes.");              pMsg->assign("Goal must be the same in all game modes.");
1237              return false;              return false;
1238            }            }
1239            pLevel->setMeditation(true);            pLevel->setMeditation(true);
1240            continue;            continue;
1241          }          }
1242          if (item.size() >= 2 && item[1] == 'N') {          if (item.size() >= 2 && item[1] == 'N') {
1243            if (gameMode != GameMode_Invalid) {            if (gameMode != GameMode_Invalid) {
1244              pMsg->assign("Goal must be the same in all game modes.");              pMsg->assign("Goal must be the same in all game modes.");
1245              return false;              return false;
1246            }            }
1247            pLevel->setMeditation(false);            pLevel->setMeditation(false);
1248            continue;            continue;
1249          }          }
1250        }        }
1251    
1252        // Harmless meditation marbles        // Harmless meditation marbles
1253        if (item.compare("n") == 0) {        if (item.compare("n") == 0) {
1254          if (gameMode != GameMode_Invalid) {          if (gameMode != GameMode_Invalid) {
1255            pMsg->assign("Harmless meditation marbles setting must be the same in all game modes.");            pMsg->assign("Harmless meditation marbles setting must be the same in all game modes.");
1256            return false;            return false;
1257          }          }
1258          pLevel->setHarmlessMeditationMarbles(true);          pLevel->setHarmlessMeditationMarbles(true);
1259          continue;          continue;
1260        }        }
1261    
1262        // Marbles        // Marbles
1263        if (item[0] == 'F' && item.size() >= 2) {        if (item[0] == 'F' && item.size() >= 2) {
1264          MarbleType marbleType = MarbleType_Invalid;          MarbleType marbleType = MarbleType_Invalid;
1265          switch (item[1]) {          switch (item[1]) {
1266          case 'B': marbleType = MarbleType_Black;          break;          case 'B': marbleType = MarbleType_Black;          break;
1267          case 'b': marbleType = MarbleType_White;          break;          case 'b': marbleType = MarbleType_White;          break;
1268          case 'M': marbleType = MarbleType_Meditation;     break;          case 'M': marbleType = MarbleType_Meditation;     break;
1269          case 'G': marbleType = MarbleType_Horse;          break;          case 'G': marbleType = MarbleType_Horse;          break;
1270          case 'K': marbleType = MarbleType_Jack;           break;          case 'K': marbleType = MarbleType_Jack;           break;
1271          case 'C': marbleType = MarbleType_LifeSpitter;    break;          case 'C': marbleType = MarbleType_LifeSpitter;    break;
1272          case 'D': marbleType = MarbleType_DynamiteHolder; break;          case 'D': marbleType = MarbleType_DynamiteHolder; break;
1273          case 'R': marbleType = MarbleType_Rotor;          break;          case 'R': marbleType = MarbleType_Rotor;          break;
1274          case 'H': marbleType = MarbleType_Bug;            break;          case 'H': marbleType = MarbleType_Bug;            break;
1275          default:          default:
1276            printf ("(Oxydlib) unknown marble type: %c\n", item[1]);            printf ("(Oxydlib) unknown marble type: %c\n", item[1]);
1277            break;            break;
1278          }          }
1279          if (marbleType != MarbleType_Invalid) {          if (marbleType != MarbleType_Invalid) {
1280            for (int curGameModeInt = GameMode_First;            for (int curGameModeInt = GameMode_First;
1281                 curGameModeInt <= GameMode_Last;                 curGameModeInt <= GameMode_Last;
1282                 curGameModeInt++) {                 curGameModeInt++) {
1283              GameMode curGameMode = GameMode(curGameModeInt);              GameMode curGameMode = GameMode(curGameModeInt);
1284              if (gameMode != GameMode_Invalid &&              if (gameMode != GameMode_Invalid &&
1285                  curGameMode != gameMode) {                  curGameMode != gameMode) {
1286                continue;                continue;
1287              }              }
1288    
1289              if (numMarblesArr[curGameMode] >= 8) {              if (numMarblesArr[curGameMode] >= 8) {
1290                pMsg->assign("Too many marbles.");                pMsg->assign("Too many marbles.");
1291                return false;                return false;
1292              }              }
1293    
1294              int nMarble = numMarblesArr[curGameMode];              int nMarble = numMarblesArr[curGameMode];
1295              numMarblesArr[curGameMode]++;              numMarblesArr[curGameMode]++;
1296    
1297              if (pLevel->getNumMarbles() < nMarble) {              if (pLevel->getNumMarbles() < nMarble) {
1298                pMsg->assign("Something strange has happened parsing marbles.");                pMsg->assign("Something strange has happened parsing marbles.");
1299                return false;                return false;
1300              } else if (pLevel->getNumMarbles() == nMarble) {              } else if (pLevel->getNumMarbles() == nMarble) {
1301                pLevel->setNumMarbles(nMarble + 1);                pLevel->setNumMarbles(nMarble + 1);
1302                Marble *pMarble = pLevel->getMarbleForWrite(nMarble);                Marble *pMarble = pLevel->getMarbleForWrite(nMarble);
1303    
1304                pMarble->setMarbleType(marbleType);                pMarble->setMarbleType(marbleType);
1305                pMarble->setX(getInt2(infoGeneral.begin() + 0x04 +                pMarble->setX(getInt2(infoGeneral.begin() + 0x04 +
1306                                      (nMarble * 8)));                                      (nMarble * 8)));
1307                pMarble->setY(getInt2(infoGeneral.begin() + 0x04 +                pMarble->setY(getInt2(infoGeneral.begin() + 0x04 +
1308                                      (nMarble * 8) + 0x04));                                      (nMarble * 8) + 0x04));
1309    
1310                string *pData = pMarble->getDataForWrite(curGameMode);                string *pData = pMarble->getDataForWrite(curGameMode);
1311                *pData = item.substr(2);                *pData = item.substr(2);
1312              } else { // if (pLevel->getNumMarbles() > nMarble)              } else { // if (pLevel->getNumMarbles() > nMarble)
1313                Marble *pMarble = pLevel->getMarbleForWrite(nMarble);                Marble *pMarble = pLevel->getMarbleForWrite(nMarble);
1314    
1315                if (pMarble->getMarbleType() != marbleType) {                if (pMarble->getMarbleType() != marbleType) {
1316                  pMsg->assign("Marble types differ in easy and hard game mode.");                  pMsg->assign("Marble types differ in easy and hard game mode.");
1317                  return false;                  return false;
1318                }                }
1319    
1320                string *pData = pMarble->getDataForWrite(curGameMode);                string *pData = pMarble->getDataForWrite(curGameMode);
1321                *pData = item.substr(2);                *pData = item.substr(2);
1322              }              }
1323            }            }
1324    
1325            continue;            continue;
1326          }          }
1327        }        }
1328    
1329        // Rubber bands        // Rubber bands
1330        if (item[0] == 'B') {        if (item[0] == 'B') {
1331          string temp1 = item.substr(1);          string temp1 = item.substr(1);
1332    
1333            string::size_type f8Pos = temp1.find(0xf8);
1334            string temp2;
1335            string temp3;
1336            if (f8Pos == string::npos) {
1337              temp2 = temp1;
1338            } else {
1339              temp2 = temp1.substr(0, f8Pos);
1340              temp3 = temp1.substr(f8Pos + 1);
1341            }
1342    
1343            if (!temp3.empty()) {
1344              pMsg->assign("Rubber band has extra data after the 0xF8 byte.");
1345              return false;
1346            }
1347    
1348            string::size_type f9Pos = temp2.find((char)0xf9);
1349            string strNumberList1;
1350            string strNumberList2;
1351            if (f9Pos == string::npos) {
1352              strNumberList1 = temp2;
1353            } else {
1354              strNumberList1 = temp2.substr(0, f9Pos);
1355              strNumberList2 = temp2.substr(f9Pos + 1);
1356            }
1357    
1358            vector<int> numberList1;
1359            if (!parseNumberList(strNumberList1, &numberList1)) {
1360              pMsg->assign("Cannot parse first number list in rubber band.");
1361              return false;
1362            }
1363            vector<int> numberList2;
1364            if (!parseNumberList(strNumberList2, &numberList2)) {
1365              pMsg->assign("Cannot parse second number list in rubber band.");
1366              return false;
1367            }
1368    
1369          string::size_type f8Pos = temp1.find(0xf8);          if (numberList1.size() > 3) {
1370          string temp2;            pMsg->assign("First number list in rubber band is too long.");
1371          string temp3;            return false;
1372          if (f8Pos == string::npos) {          }
1373            temp2 = temp1;          if (numberList2.size() > 2) {
1374          } else {            pMsg->assign("Second number list in rubber band is too long.");
1375            temp2 = temp1.substr(0, f8Pos);            return false;
1376            temp3 = temp1.substr(f8Pos + 1);          }
         }  
   
         if (!temp3.empty()) {  
           pMsg->assign("Rubber band has extra data after the 0xF8 byte.");  
           return false;  
         }  
   
         string::size_type f9Pos = temp2.find(0xf9);  
         string strNumberList1;  
         string strNumberList2;  
         if (f9Pos == string::npos) {  
           strNumberList1 = temp2;  
         } else {  
           strNumberList1 = temp2.substr(0, f9Pos);  
           strNumberList2 = temp2.substr(f9Pos + 1);  
         }  
   
         vector<int> numberList1;  
         if (!parseNumberList(strNumberList1, &numberList1)) {  
           pMsg->assign("Cannot parse first number list in rubber band.");  
           return false;  
         }  
         vector<int> numberList2;  
         if (!parseNumberList(strNumberList2, &numberList2)) {  
           pMsg->assign("Cannot parse second number list in rubber band.");  
           return false;  
         }  
   
         if (numberList1.size() > 3) {  
           pMsg->assign("First number list in rubber band is too long.");  
           return false;  
         }  
         if (numberList2.size() > 2) {  
           pMsg->assign("Second number list in rubber band is too long.");  
           return false;  
         }  
   
         int naturalLength = -1;  
         if (numberList1.size() > 0) {  
           naturalLength = numberList1[0];  
         }  
         int force = -1;  
         if (numberList1.size() > 1) {  
           force = numberList1[1];  
         }  
         int blockNumber = -1;  
         if (numberList1.size() > 2) {  
           blockNumber = numberList1[2];  
         }  
   
         int marbleNumber1 = -1;  
         if (numberList2.size() > 0) {  
           marbleNumber1 = numberList2[0];  
         }  
         int marbleNumber2 = -1;  
         if (numberList2.size() > 1) {  
           marbleNumber2 = numberList2[1];  
         }  
   
         bool bInitialRubberBand = false;  
         RubberBand rubberBand;  
   
         if (blockNumber != -1 ||  
             marbleNumber2 !=  -1) {  
           if (blockNumber != -1 &&  
               marbleNumber2 != -1) {  
             pMsg->assign("A rubber band can't have a block number and two marble numbers.");  
             return false;  
           }  
   
           if (marbleNumber1 == -1 &&  
               marbleNumber2 != -1) {  
             pMsg->assign("A rubber band can't have a second marble number without a first.");  
             return false;  
           }  
   
           if (naturalLength == -1 ||  
               force == -1) {  
             pMsg->assign("An initial rubber band must have both natural length and force values.");  
             return false;  
           }  
   
           bInitialRubberBand = true;  
   
           rubberBand.setNaturalLength(naturalLength);  
           rubberBand.setForce(force);  
           rubberBand.setFirstEndMarble(marbleNumber1 == -1 ?  
                                        0 : marbleNumber1);  
           if (blockNumber != -1) {  
             unsigned int gridSize = width * height;  
             if (blockNumber >= (int)gridSize) {  
               pMsg->assign("Rubber band block number is too large.");  
               return false;  
             }  
             unsigned int x = blockNumber % width;  
             unsigned int y = blockNumber / width;  
             rubberBand.setSecondEndPiece(x, y);  
           } else {  
             rubberBand.setSecondEndMarble(marbleNumber2);  
           }  
         } else if (marbleNumber1 != -1) {  
           pMsg->assign("A rubber band can't have a first marble number without a block number or a secend marble number.");  
           return false;  
         } else {  
           // No checks on natural length or force for extra rubber bands  
         }  
   
         for (int curGameModeInt = GameMode_First;  
              curGameModeInt <= GameMode_Last;  
              curGameModeInt++) {  
           GameMode curGameMode = GameMode(curGameModeInt);  
           if (gameMode != GameMode_Invalid &&  
               curGameMode != gameMode) {  
             continue;  
           }  
   
           if (bInitialRubberBand) {  
             pLevel->addRubberBand(curGameMode, rubberBand);  
           } else {  
             int nExtraRubberBand = numExtraRubberBandsArr[curGameMode];  
             if (nExtraRubberBand >= 3) {  
               pMsg->assign("Too many extra rubber bands.");  
               return false;  
             }  
             numExtraRubberBandsArr[curGameMode]++;  
             switch (nExtraRubberBand) {  
             case 0:  
               {  
                 pLevel->setBlackRubberBandPieceNaturalLength(curGameMode,  
                                                              naturalLength);  
                 pLevel->setBlackRubberBandPieceForce(curGameMode,  
                                                      force);  
               }  
               break;  
             case 1:  
               {  
                 pLevel->setWhiteRubberBandPieceNaturalLength(curGameMode,  
                                                              naturalLength);  
                 pLevel->setWhiteRubberBandPieceForce(curGameMode,  
                                                      force);  
               }  
               break;  
             case 2:  
               {  
                 pLevel->setRubberBandObjectNaturalLength(curGameMode,  
                                                          naturalLength);  
                 pLevel->setRubberBandObjectForce(curGameMode, force);  
               }  
               break;  
             }  
           }  
         }  
1377    
1378          continue;          int naturalLength = -1;
1379            if (numberList1.size() > 0) {
1380              naturalLength = numberList1[0];
1381            }
1382            int force = -1;
1383            if (numberList1.size() > 1) {
1384              force = numberList1[1];
1385            }
1386            int blockNumber = -1;
1387            if (numberList1.size() > 2) {
1388              blockNumber = numberList1[2];
1389            }
1390    
1391            int marbleNumber1 = -1;
1392            if (numberList2.size() > 0) {
1393              marbleNumber1 = numberList2[0];
1394            }
1395            int marbleNumber2 = -1;
1396            if (numberList2.size() > 1) {
1397              marbleNumber2 = numberList2[1];
1398            }
1399    
1400            bool bInitialRubberBand = false;
1401            RubberBand rubberBand;
1402    
1403            if (blockNumber != -1 ||
1404                marbleNumber2 !=  -1) {
1405              if (blockNumber != -1 &&
1406                  marbleNumber2 != -1) {
1407                pMsg->assign("A rubber band can't have a block number and two marble numbers.");
1408                return false;
1409              }
1410    
1411              if (marbleNumber1 == -1 &&
1412                  marbleNumber2 != -1) {
1413                pMsg->assign("A rubber band can't have a second marble number without a first.");
1414                return false;
1415              }
1416    
1417              if (naturalLength == -1 ||
1418                  force == -1) {
1419                pMsg->assign("An initial rubber band must have both natural length and force values.");
1420                return false;
1421              }
1422    
1423              bInitialRubberBand = true;
1424    
1425              rubberBand.setNaturalLength(naturalLength);
1426              rubberBand.setForce(force);
1427              rubberBand.setFirstEndMarble(marbleNumber1 == -1 ?
1428                                           0 : marbleNumber1);
1429              if (blockNumber != -1) {
1430                unsigned int gridSize = width * height;
1431                if (blockNumber >= (int)gridSize) {
1432                  pMsg->assign("Rubber band block number is too large.");
1433                  return false;
1434                }
1435                unsigned int x = blockNumber % width;
1436                unsigned int y = blockNumber / width;
1437                rubberBand.setSecondEndPiece(x, y);
1438              } else {
1439                rubberBand.setSecondEndMarble(marbleNumber2);
1440              }
1441            } else if (marbleNumber1 != -1) {
1442              pMsg->assign("A rubber band can't have a first marble number without a block number or a secend marble number.");
1443              return false;
1444            } else {
1445              // No checks on natural length or force for extra rubber bands
1446            }
1447    
1448            for (int curGameModeInt = GameMode_First;
1449                 curGameModeInt <= GameMode_Last;
1450                 curGameModeInt++) {
1451              GameMode curGameMode = GameMode(curGameModeInt);
1452              if (gameMode != GameMode_Invalid &&
1453                  curGameMode != gameMode) {
1454                continue;
1455              }
1456    
1457              if (bInitialRubberBand) {
1458                pLevel->addRubberBand(curGameMode, rubberBand);
1459              } else {
1460                int nExtraRubberBand = numExtraRubberBandsArr[curGameMode];
1461                if (nExtraRubberBand >= 3) {
1462                  pMsg->assign("Too many extra rubber bands.");
1463                  return false;
1464                }
1465                numExtraRubberBandsArr[curGameMode]++;
1466                switch (nExtraRubberBand) {
1467                case 0:
1468                  {
1469                    pLevel->setBlackRubberBandPieceNaturalLength(curGameMode,
1470                                                                 naturalLength);
1471                    pLevel->setBlackRubberBandPieceForce(curGameMode,
1472                                                         force);
1473                  }
1474                  break;
1475                case 1:
1476                  {
1477                    pLevel->setWhiteRubberBandPieceNaturalLength(curGameMode,
1478                                                                 naturalLength);
1479                    pLevel->setWhiteRubberBandPieceForce(curGameMode,
1480                                                         force);
1481                  }
1482                  break;
1483                case 2:
1484                  {
1485                    pLevel->setRubberBandObjectNaturalLength(curGameMode,
1486                                                             naturalLength);
1487                    pLevel->setRubberBandObjectForce(curGameMode, force);
1488                  }
1489                  break;
1490                }
1491              }
1492            }
1493    
1494            continue;
1495        }        }
1496    
1497        // Rubber band object marbles        // Rubber band object marbles
1498        if (item[0] == 'N') {        if (item[0] == 'N') {
1499          string strNumberList = item.substr(1);          string strNumberList = item.substr(1);
1500          vector<int> numberList;          vector<int> numberList;
1501          if (parseNumberList(strNumberList, &numberList)) {          if (parseNumberList(strNumberList, &numberList)) {
1502            if (numberList.size() <= 2) {            if (numberList.size() <= 2) {
1503              if (gameMode != GameMode_Invalid) {              if (gameMode != GameMode_Invalid) {
1504                pMsg->assign("Rubber band object marbles must be the same in all game modes.");                pMsg->assign("Rubber band object marbles must be the same in all game modes.");
1505                return false;                return false;
1506              }              }
1507    
1508              int nMarbleBlack = 1;              int nMarbleBlack = 1;
1509              if (numberList.size() > 0 &&              if (numberList.size() > 0 &&
1510                  numberList[0] != -1) {                  numberList[0] != -1) {
1511                nMarbleBlack = numberList[0];                nMarbleBlack = numberList[0];
1512              }              }
1513    
1514              int nMarbleWhite = 0;              int nMarbleWhite = 0;
1515              if (numberList.size() > 1 &&              if (numberList.size() > 1 &&
1516                  numberList[1] != -1) {                  numberList[1] != -1) {
1517                nMarbleWhite = numberList[1];                nMarbleWhite = numberList[1];
1518              }              }
1519    
1520              pLevel->setBlackRubberBandObjectMarble(nMarbleBlack);              pLevel->setBlackRubberBandObjectMarble(nMarbleBlack);
1521              pLevel->setWhiteRubberBandObjectMarble(nMarbleWhite);              pLevel->setWhiteRubberBandObjectMarble(nMarbleWhite);
1522            }            }
1523          }          }
   
         // Skip anything else that begins with 'N', since there is  
         // a rubber band that mistakenly begins with 'N' instead  
         // of 'B'.  
1524    
1525          continue;          // Skip anything else that begins with 'N', since there is
1526            // a rubber band that mistakenly begins with 'N' instead
1527            // of 'B'.
1528    
1529            continue;
1530        }        }
1531    
1532        // Require magic piece        // Require magic piece
1533        if (item.compare("!") == 0) {        if (item.compare("!") == 0) {
1534          if (gameMode != GameMode_Invalid) {          if (gameMode != GameMode_Invalid) {
1535            pMsg->assign("Require magic piece setting must be the same in all game modes.");            pMsg->assign("Require magic piece setting must be the same in all game modes.");
1536            return false;            return false;
1537          }          }
1538          pLevel->setRequireMagicPiece(true);          pLevel->setRequireMagicPiece(true);
1539          continue;          continue;
1540        }        }
1541    
1542        // Scrolling        // Scrolling
1543        if (item.compare("f") == 0) {        if (item.compare("f") == 0) {
1544          if (gameMode != GameMode_Invalid) {          if (gameMode != GameMode_Invalid) {
1545            pMsg->assign("Scrolling setting must be the same in all game modes.");            pMsg->assign("Scrolling setting must be the same in all game modes.");
1546            return false;            return false;
1547          }          }
1548          pLevel->setScrolling(true);          pLevel->setScrolling(true);
1549          continue;          continue;
1550        }        }
1551    
1552        // Reset        // Reset
1553        if (item.compare("s") == 0) {        if (item.compare("s") == 0) {
1554          for (int curGameModeInt = GameMode_First;          for (int curGameModeInt = GameMode_First;
1555               curGameModeInt <= GameMode_Last;               curGameModeInt <= GameMode_Last;
1556               curGameModeInt++) {               curGameModeInt++) {
1557            GameMode curGameMode = GameMode(curGameModeInt);            GameMode curGameMode = GameMode(curGameModeInt);
1558            if (gameMode != GameMode_Invalid &&            if (gameMode != GameMode_Invalid &&
1559                curGameMode != gameMode) {                curGameMode != gameMode) {
1560              continue;              continue;
1561            }            }
1562    
1563            pLevel->setReset(curGameMode, true);            pLevel->setReset(curGameMode, true);
1564          }          }
1565          continue;          continue;
1566        }        }
1567    
1568        // Walk-through puzzle        // Walk-through puzzle
1569        if (item.compare("j") == 0) {        if (item.compare("j") == 0) {
1570          if (gameMode != GameMode_Invalid) {          if (gameMode != GameMode_Invalid) {
1571            pMsg->assign("Walk-through puzzle setting must be the same in all game modes.");            pMsg->assign("Walk-through puzzle setting must be the same in all game modes.");
1572            return false;            return false;
1573          }          }
1574          pLevel->setWalkThroughPuzzle(true);          pLevel->setWalkThroughPuzzle(true);
1575          continue;          continue;
1576        }        }
1577    
1578        // Force        // Force
1579        if (item[0] == 'g') {        if (item[0] == 'g') {
1580          for (int curGameModeInt = GameMode_First;          for (int curGameModeInt = GameMode_First;
1581               curGameModeInt <= GameMode_Last;               curGameModeInt <= GameMode_Last;
1582               curGameModeInt++) {               curGameModeInt++) {
1583            GameMode curGameMode = GameMode(curGameModeInt);            GameMode curGameMode = GameMode(curGameModeInt);
1584            if (gameMode != GameMode_Invalid &&            if (gameMode != GameMode_Invalid &&
1585                curGameMode != gameMode) {                curGameMode != gameMode) {
1586              continue;              continue;
1587            }            }
1588    
1589            string strNumberList = item.substr(1);            string strNumberList = item.substr(1);
1590            vector<int> numberList;            vector<int> numberList;
1591            if (parseNumberList(strNumberList, &numberList)) {            if (parseNumberList(strNumberList, &numberList)) {
1592              if (numberList.size() >= 1) {              if (numberList.size() >= 1) {
1593                pLevel->setFlatForce(curGameMode, numberList[0]);                pLevel->setFlatForce(curGameMode, numberList[0]);
1594              }              }
1595              if (numberList.size() >= 2) {              if (numberList.size() >= 2) {
1596                pLevel->setFriction(curGameMode, numberList[1]);                pLevel->setFriction(curGameMode, numberList[1]);
1597              }              }
1598              if (numberList.size() >= 3) {              if (numberList.size() >= 3) {
1599                pLevel->setSlopeForce(curGameMode, numberList[2]);                pLevel->setSlopeForce(curGameMode, numberList[2]);
1600              }              }
1601            } else {            } else {
1602              pMsg->assign("Could not parse force special item.");              pMsg->assign("Could not parse force special item.");
1603              return false;              return false;
1604            }            }
1605          }          }
1606          continue;          continue;
1607        }        }
1608    
1609        // Scramble items        // Scramble items
1610        if (item[0] == 'P') {        if (item[0] == 'P') {
1611          if (gameMode != GameMode_Invalid) {          if (gameMode != GameMode_Invalid) {
1612            pMsg->assign("Scramble items must be the same in all game modes.");            pMsg->assign("Scramble items must be the same in all game modes.");
1613            return false;            return false;
1614          }          }
   
         string strNumberList = item.substr(1);  
         vector<int> numberList;  
         if (!parseNumberList(strNumberList, &numberList)) {  
           pMsg->assign("Could not parse scramble items.");  
           return false;  
         }  
   
         if (numberList.size() % 2 == 1) {  
           pMsg->assign("Scramble item number list size should not be odd.");  
           return false;  
         }  
   
         for (int nScrambleItem = 0;  
              nScrambleItem < (int)(numberList.size() / 2);  
              nScrambleItem++) {  
           int blockNumber = numberList[nScrambleItem * 2];  
           int dirInt = numberList[nScrambleItem * 2 + 1];  
   
           unsigned int gridSize = width * height;  
           if (blockNumber >= (int)gridSize) {  
             pMsg->assign("Scramble item block number is too large.");  
             return false;  
           }  
           unsigned int x = blockNumber % width;  
           unsigned int y = blockNumber / width;  
   
           ScrambleDir dir = ScrambleDir_Invalid;  
           switch (dirInt) {  
           case 0: dir = ScrambleDir_Up;    break;  
           case 1: dir = ScrambleDir_Down;  break;  
           case 2: dir = ScrambleDir_Left;  break;  
           case 3: dir = ScrambleDir_Right; break;  
           }  
   
           if (dir == ScrambleDir_Invalid) {  
             pMsg->assign("Invalid scramble item direction number.");  
             return false;  
           }  
1615    
1616            pLevel->addScrambleItem(ScrambleItem(x, y, dir));          string strNumberList = item.substr(1);
1617          }          vector<int> numberList;
1618            if (!parseNumberList(strNumberList, &numberList)) {
1619              pMsg->assign("Could not parse scramble items.");
1620              return false;
1621            }
1622    
1623          continue;          if (numberList.size() % 2 == 1) {
1624              // This can happen
1625              /*
1626              pMsg->assign("Scramble item number list size should not be odd.");
1627              return false;
1628              */
1629    
1630              numberList.erase(numberList.begin() + (numberList.size() - 1));
1631            }
1632    
1633            for (int nScrambleItem = 0;
1634                 nScrambleItem < (int)(numberList.size() / 2);
1635                 nScrambleItem++) {
1636              int blockNumber = numberList[nScrambleItem * 2];
1637              int dirInt = numberList[nScrambleItem * 2 + 1];
1638    
1639              unsigned int gridSize = width * height;
1640              if (blockNumber >= (int)gridSize) {
1641                pMsg->assign("Scramble item block number is too large.");
1642                return false;
1643              }
1644              unsigned int x = blockNumber % width;
1645              unsigned int y = blockNumber / width;
1646    
1647              Direction dir = Direction_Invalid;
1648              switch (dirInt) {
1649              case 0: dir = Direction_Up;    break;
1650              case 1: dir = Direction_Down;  break;
1651              case 2: dir = Direction_Left;  break;
1652              case 3: dir = Direction_Right; break;
1653              }
1654    
1655              if (dir == Direction_Invalid) {
1656                pMsg->assign("Invalid scramble item direction number.");
1657                return false;
1658              }
1659    
1660              pLevel->addScrambleItem(ScrambleItem(x, y, dir));
1661            }
1662    
1663            continue;
1664          }
1665    
1666          // Lasers
1667          if (item[0] == 'L') {
1668            if (gameMode != GameMode_Invalid) {
1669              pMsg->assign("Lasers must be the same in all game modes.");
1670              return false;
1671            }
1672    
1673            string strLaserData = item.substr(1);
1674    
1675            string strNumberList;
1676            bool bOn = false;
1677            if (strLaserData.size() > 0) {
1678              char lastByte = strLaserData[strLaserData.size() - 1];
1679              if (lastByte == (char)0xf9 ||
1680                  lastByte == (char)0xf8) {
1681                strNumberList = strLaserData.substr(0, strLaserData.size() - 1);
1682                if (lastByte == (char)0xf9) {
1683                  bOn = true;
1684                }
1685              } else {
1686                strNumberList = strLaserData;
1687              }
1688            }
1689    
1690            vector<int> numberList;
1691            if (!parseNumberList(strNumberList, &numberList)) {
1692              pMsg->assign("Could not parse laser.");
1693              return false;
1694            }
1695    
1696            if (numberList.size() != 2) {
1697              pMsg->assign("Laser number list should have two numbers.");
1698              return false;
1699            }
1700    
1701            int laserNumber = numberList[0];
1702            int dirInt = numberList[1];
1703    
1704            if (laserNumber < 1 || laserNumber > 3) {
1705              pMsg->assign("Laser type must be between 1 and 3.");
1706              return false;
1707            }
1708    
1709            Direction dir = Direction_Invalid;
1710            switch (dirInt) {
1711            case 0: dir = Direction_Up;    break;
1712            case 1: dir = Direction_Down;  break;
1713            case 2: dir = Direction_Left;  break;
1714            case 3: dir = Direction_Right; break;
1715            }
1716    
1717            if (dir == Direction_Invalid) {
1718              pMsg->assign("Invalid laser direction number.");
1719              return false;
1720            }
1721    
1722            if (foundLaserArr[laserNumber - 1]) {
1723              pMsg->assign("Laser type occurs more than once.");
1724              return false;
1725            }
1726            foundLaserArr[laserNumber - 1] = true;
1727    
1728            pLevel->setLaser(laserNumber - 1, Laser(dir, bOn));
1729    
1730            continue;
1731        }        }
1732    
1733        // Oscillators        // Oscillators
1734        if (item[0] == '~') {        if (item[0] == '~') {
1735          string strNumberList = item.substr(1);          string strNumberList = item.substr(1);
1736          vector<int> numberList;          vector<int> numberList;
1737          if (!parseNumberList(strNumberList, &numberList)) {          if (!parseNumberList(strNumberList, &numberList)) {
1738            pMsg->assign("Could not parse oscillator.");            pMsg->assign("Could not parse oscillator.");
1739            return false;            return false;
1740          }          }
1741    
1742          if (numberList.size() != 2) {          if (numberList.size() != 2) {
1743            pMsg->assign("Oscillator number list should have two numbers.");            pMsg->assign("Oscillator number list should have two numbers.");
1744            return false;            return false;
1745          }          }
   
         int blockNumber = numberList[0];  
         int period = numberList[1];  
   
         if (blockNumber == -1) {  
           pMsg->assign("Oscillator block number is empty.");  
           return false;  
         }  
   
         if (period == -1) {  
           pMsg->assign("Oscillator period is empty.");  
           return false;  
         }  
   
         unsigned int gridSize = width * height;  
         if (blockNumber >= (int)gridSize) {  
           pMsg->assign("Oscillator block number is too large.");  
           return false;  
         }  
   
         unsigned int x = blockNumber % width;  
         unsigned int y = blockNumber / width;  
   
         Oscillator oscillator(x, y, period);  
   
         for (int curGameModeInt = GameMode_First;  
              curGameModeInt <= GameMode_Last;  
              curGameModeInt++) {  
           GameMode curGameMode = GameMode(curGameModeInt);  
           if (gameMode != GameMode_Invalid &&  
               curGameMode != gameMode) {  
             continue;  
           }  
   
           set<Oscillator> *pOscillators =  
             pLevel->getOscillatorsForWrite(curGameMode);  
           if (pOscillators->find(oscillator) != pOscillators->end()) {  
             pMsg->assign("Duplicate oscillator block number.");  
             return false;  
           }  
1746    
1747            pOscillators->insert(oscillator);          int blockNumber = numberList[0];
1748          }          int period = numberList[1];
1749    
1750          continue;          if (blockNumber == -1) {
1751              pMsg->assign("Oscillator block number is empty.");
1752              return false;
1753            }
1754    
1755            if (period == -1) {
1756              pMsg->assign("Oscillator period is empty.");
1757              return false;
1758            }
1759    
1760            unsigned int gridSize = width * height;
1761            if (blockNumber >= (int)gridSize) {
1762              pMsg->assign("Oscillator block number is too large.");
1763              return false;
1764            }
1765    
1766            unsigned int x = blockNumber % width;
1767            unsigned int y = blockNumber / width;
1768    
1769            for (int curGameModeInt = GameMode_First;
1770                 curGameModeInt <= GameMode_Last;
1771                 curGameModeInt++) {
1772              GameMode curGameMode = GameMode(curGameModeInt);
1773              if (gameMode != GameMode_Invalid &&
1774                  curGameMode != gameMode) {
1775                continue;
1776              }
1777    
1778              OscillatorMap *pOscillators =
1779                pLevel->getOscillatorsForWrite(curGameMode);
1780              (*pOscillators)[Block(x, y)].setPeriod(period);
1781            }
1782    
1783            continue;
1784          }
1785    
1786          // Still oscillators
1787          if (item[0] == 'O') {
1788            string strNumberList = item.substr(1);
1789            vector<int> numberList;
1790            if (!parseNumberList(strNumberList, &numberList)) {
1791              pMsg->assign("Could not parse still oscillator.");
1792              return false;
1793            }
1794    
1795            if (numberList.size() != 1) {
1796              pMsg->assign("Still oscillator number list should have one number.");
1797              return false;
1798            }
1799    
1800            int blockNumber = numberList[0];
1801    
1802            if (blockNumber == -1) {
1803              pMsg->assign("Still oscillator block number is empty.");
1804              return false;
1805            }
1806    
1807            unsigned int gridSize = width * height;
1808            if (blockNumber >= (int)gridSize) {
1809              pMsg->assign("Still oscillator block number is too large.");
1810              return false;
1811            }
1812    
1813            unsigned int x = blockNumber % width;
1814            unsigned int y = blockNumber / width;
1815    
1816            for (int curGameModeInt = GameMode_First;
1817                 curGameModeInt <= GameMode_Last;
1818                 curGameModeInt++) {
1819              GameMode curGameMode = GameMode(curGameModeInt);
1820              if (gameMode != GameMode_Invalid &&
1821                  curGameMode != gameMode) {
1822                continue;
1823              }
1824    
1825              OscillatorMap *pOscillators =
1826                pLevel->getOscillatorsForWrite(curGameMode);
1827              (*pOscillators)[Block(x, y)].setOn(false);
1828            }
1829    
1830            continue;
1831        }        }
1832    
1833        // Notes        // Notes
1834        if (item[0] == 'Z' || item[0] == 'z') {        if (item[0] == 'Z' || item[0] == 'z') {
1835          if (gameMode != GameMode_Invalid) {          if (gameMode != GameMode_Invalid) {
1836            pMsg->assign("Note text must be the same in all game modes.");            pMsg->assign("Note text must be the same in all game modes.");
1837            return false;            return false;
1838          }          }
1839          int nNote = (item[0] == 'Z' ? 0 : 1);          int nNote = (item[0] == 'Z' ? 0 : 1);
1840    
1841          if (item.size() >= 4) {          if (item.size() >= 4) {
1842            Language lang = Language_Invalid;            Language lang = Language_Invalid;
1843            switch (item[1]) {            switch (item[1]) {
1844            case 'g': lang = Language_German;  break;            case 'g': lang = Language_German;  break;
1845            case 'e': lang = Language_English; break;            case 'e': lang = Language_English; break;
1846            case 'f': lang = Language_French;  break;            case 'f': lang = Language_French;  break;
1847            }            }
1848            if (lang != Language_Invalid) {            if (lang != Language_Invalid) {
1849              if (item[2] == '"') {              if (item[2] == '"') {
1850                int i = 3;                int i = 3;
1851                while (i < (int)item.size() &&                while (i < (int)item.size() &&
1852                       item[i] != '"') {                       item[i] != '"') {
1853                  i++;                  i++;
1854                }                }
1855                // Allow extra characters after the second quote                // Allow extra characters after the second quote
1856                if (i < (int)item.size()) {                if (i < (int)item.size()) {
1857                  string noteText = item.substr(3, i-3);                  string noteText = item.substr(3, i-3);
1858                  pLevel->setNoteText(nNote, lang, noteText);                  pLevel->setNoteText(nNote, lang, noteText);
1859                  continue;                  continue;
1860                }                }
1861              }              }
1862            }            }
1863          }          }
1864        }        }
1865    
1866        // Clean up some bad data in notes        // Clean up some bad data in notes
1867        if (item[0] == '"') {        if (item[0] == '"') {
1868          continue;          continue;
1869        }        }
1870    
1871        /*        /*
1872        if (item.compare(">(0)") == 0) {        if (item.compare(">(0)") == 0) {
1873          pLevel->getSpecialItemsForWrite()->push_back(">(1)");          pLevel->getSpecialItemsForWrite()->push_back(">(1)");
1874          continue;          continue;
1875        }        }
1876        */        */
1877    
1878        /*        /*
1879        if (item.compare("#") == 0) {        if (item.compare("#") == 0) {
1880          continue;          continue;
1881        }        }
1882        */        */
1883    
1884        /*        /*
1885        if (item.compare("r") == 0) {        if (item.compare("r") == 0) {
1886          continue;          continue;
1887        }        }
1888        */        */
1889    
       if (item[0] == 'O') {  
         continue;  
       }  
   
1890        if (true || gameMode != GameMode_Easy) {        if (true || gameMode != GameMode_Easy) {
1891          pLevel->getSpecialItemsForWrite()->push_back(item);          pLevel->getSpecialItemsForWrite()->push_back(item);
1892        }        }
1893      }      }
1894    
# Line 1687  bool parseLevel(const ByteVec &in, Level Line 1904  bool parseLevel(const ByteVec &in, Level
1904    }    }
1905    
1906    if (!parseGrid(infoArr[INFOSURFACES],    if (!parseGrid(infoArr[INFOSURFACES],
1907                   pLevel->getGridForWrite(GridType_Surfaces), pMsg)) {                   pLevel->getGridForWrite(GridType_Surfaces), pMsg)) {
1908      return false;      return false;
1909    }    }
1910    if (!parseGrid(infoArr[INFOPIECES],    if (!parseGrid(infoArr[INFOPIECES],
1911                   pLevel->getGridForWrite(GridType_Pieces), pMsg)) {                   pLevel->getGridForWrite(GridType_Pieces), pMsg)) {
1912      return false;      return false;
1913    }    }
1914    if (!parseGrid(infoArr[INFOOBJECTS],    if (!parseGrid(infoArr[INFOOBJECTS],
1915                   pLevel->getGridForWrite(GridType_Objects), pMsg)) {                   pLevel->getGridForWrite(GridType_Objects), pMsg)) {
1916      return false;      return false;
1917    }    }
1918    
# Line 1708  bool parseLevel(const ByteVec &in, Level Line 1925  bool parseLevel(const ByteVec &in, Level
1925      for (int i = 0; i < infoSignal.size(); i++) {      for (int i = 0; i < infoSignal.size(); i++) {
1926        printf("%02x ", infoSignal[i]);        printf("%02x ", infoSignal[i]);
1927        if (q == 3) {        if (q == 3) {
1928          j = infoSignal[i] * 2;          j = infoSignal[i] * 2;
1929        }        }
1930        if (j == 0) {        if (j == 0) {
1931          printf("\n");          printf("\n");
1932          q = 0;          q = 0;
1933          j = 9999;          j = 9999;
1934        } else {        } else {
1935          q++;          q++;
1936          j--;          j--;
1937        }        }
1938      }      }
1939      printf("\n");      printf("\n");
# Line 1729  bool parseLevel(const ByteVec &in, Level Line 1946  bool parseLevel(const ByteVec &in, Level
1946      int cur = 0;      int cur = 0;
1947      while (true) {      while (true) {
1948        if (cur + 2 > (int)infoSignal.size()) {        if (cur + 2 > (int)infoSignal.size()) {
1949          pMsg->assign("Unexpected end of data reading signal sender.");          pMsg->assign("Unexpected end of data reading signal sender.");
1950          return false;          return false;
1951        }        }
1952    
1953        unsigned int packedSignalSender = getInt2(infoSignal.begin() + cur);        unsigned int packedSignalSender = getInt2(infoSignal.begin() + cur);
1954        cur += 2;        cur += 2;
1955    
1956        if (packedSignalSender == 0xffff) {        if (packedSignalSender == 0xffff) {
1957          break;          break;
1958        }        }
1959    
1960        SignalLocation signalSender;        SignalLocation signalSender;
1961        bool senderWithinGrid = true;        bool senderWithinGrid = true;
1962        if (!unpackSignalLocation(*pLevel,        if (!unpackSignalLocation(*pLevel,
1963                                  packedSignalSender,                                  packedSignalSender,
1964                                  &signalSender,                                  &signalSender,
1965                                  &senderWithinGrid,                                  &senderWithinGrid,
1966                                  pMsg)) {                                  pMsg)) {
1967          return false;          return false;
1968        }        }
1969    
1970        if (senderWithinGrid) {        if (senderWithinGrid) {
1971          if (pLevel->getNumRecipients(signalSender) > 0) {          if (pLevel->getNumRecipients(signalSender) > 0) {
1972            pMsg->assign("Duplicate signal sender.");            pMsg->assign("Duplicate signal sender.");
1973            return false;            return false;
1974          }          }
1975        }        }
1976    
1977        if (cur + 2 > (int)infoSignal.size()) {        if (cur + 2 > (int)infoSignal.size()) {
1978          pMsg->assign("Unexpected end of data reading signal recipient count.");          pMsg->assign("Unexpected end of data reading signal recipient count.");
1979          return false;          return false;
1980        }        }
1981    
1982        unsigned int signalRecipientCount = getInt2(infoSignal.begin() + cur);        unsigned int signalRecipientCount = getInt2(infoSignal.begin() + cur);
1983        cur += 2;        cur += 2;
1984    
1985        if (signalRecipientCount <= 0) {        if (signalRecipientCount <= 0) {
1986          pMsg->assign("Signal sender has no recipients.");          pMsg->assign("Signal sender has no recipients.");
1987          return false;          return false;
1988        }        }
1989    
1990        if (cur + (2 * signalRecipientCount) > infoSignal.size()) {        if (cur + (2 * signalRecipientCount) > infoSignal.size()) {
1991          pMsg->assign("Unexpected end of data reading signal recipients.");          pMsg->assign("Unexpected end of data reading signal recipients.");
1992          return false;          return false;
1993        }        }
1994    
1995        for (unsigned int nRecipient = 0;        for (unsigned int nRecipient = 0;
1996             nRecipient < signalRecipientCount;             nRecipient < signalRecipientCount;
1997             nRecipient++) {             nRecipient++) {
1998          unsigned int packedSignalRecipient = getInt2(infoSignal.begin() + cur);          unsigned int packedSignalRecipient = getInt2(infoSignal.begin() + cur);
1999          cur += 2;          cur += 2;
2000    
2001          SignalLocation signalRecipient;          SignalLocation signalRecipient;
2002          bool recipientWithinGrid = true;          bool recipientWithinGrid = true;
2003          if (!unpackSignalLocation(*pLevel,          if (!unpackSignalLocation(*pLevel,
2004                                    packedSignalRecipient,                                    packedSignalRecipient,
2005                                    &signalRecipient,                                    &signalRecipient,
2006                                    &recipientWithinGrid,                                    &recipientWithinGrid,
2007                                    pMsg)) {                                    pMsg)) {
2008            return false;            return false;
2009          }          }
2010    
2011          if (senderWithinGrid && recipientWithinGrid) {          if (senderWithinGrid && recipientWithinGrid) {
2012            pLevel->addRecipient(signalSender, signalRecipient);            pLevel->addRecipient(signalSender, signalRecipient);
2013          }          }
2014        }        }
2015      }      }
2016    
# Line 1850  bool unparseLevel(const Level &level, By Line 2067  bool unparseLevel(const Level &level, By
2067        int x = 0;        int x = 0;
2068        int y = 0;        int y = 0;
2069        if (nMarble < level.getNumMarbles()) {        if (nMarble < level.getNumMarbles()) {
2070          const Marble &marble = level.getMarble(nMarble);          const Marble &marble = level.getMarble(nMarble);
2071          x = marble.getX();          x = marble.getX();
2072          y = marble.getY();          y = marble.getY();
2073        }        }
2074    
2075        putInt2(out.begin() + cur, x);        putInt2(out.begin() + cur, x);
# Line 1879  bool unparseLevel(const Level &level, By Line 2096  bool unparseLevel(const Level &level, By
2096        set<SignalLocation>::const_iterator iter = senders.begin();        set<SignalLocation>::const_iterator iter = senders.begin();
2097        set<SignalLocation>::const_iterator end = senders.end();        set<SignalLocation>::const_iterator end = senders.end();
2098        for (; iter != end; ++iter) {        for (; iter != end; ++iter) {
2099          const SignalLocation &sender = *iter;          const SignalLocation &sender = *iter;
2100          numSignals += level.getNumRecipients(sender);          numSignals += level.getNumRecipients(sender);
2101        }        }
2102      }      }
2103    
# Line 1901  bool unparseLevel(const Level &level, By Line 2118  bool unparseLevel(const Level &level, By
2118    
2119        unsigned int packedSignalSender = 0;        unsigned int packedSignalSender = 0;
2120        if (!packSignalLocation(level,        if (!packSignalLocation(level,
2121                                sender,                                sender,
2122                                &packedSignalSender,                                &packedSignalSender,
2123                                pMsg)) {                                pMsg)) {
2124          return false;          return false;
2125        }        }
2126    
2127        putInt2(out.begin() + cur, packedSignalSender);        putInt2(out.begin() + cur, packedSignalSender);
# Line 1916  bool unparseLevel(const Level &level, By Line 2133  bool unparseLevel(const Level &level, By
2133        cur += 2;        cur += 2;
2134    
2135        for (int nRecipient = 0; nRecipient < numRecipients; nRecipient++) {        for (int nRecipient = 0; nRecipient < numRecipients; nRecipient++) {
2136          const SignalLocation &recipient =          const SignalLocation &recipient =
2137            level.getRecipient(sender, nRecipient);            level.getRecipient(sender, nRecipient);
2138    
2139          unsigned int packedSignalRecipient = 0;          unsigned int packedSignalRecipient = 0;
2140          if (!packSignalLocation(level,          if (!packSignalLocation(level,
2141                                  recipient,                                  recipient,
2142                                  &packedSignalRecipient,                                  &packedSignalRecipient,
2143                                  pMsg)) {                                  pMsg)) {
2144            return false;            return false;
2145          }          }
2146    
2147          putInt2(out.begin() + cur, packedSignalRecipient);          putInt2(out.begin() + cur, packedSignalRecipient);
2148          cur += 2;          cur += 2;
2149        }        }
2150      }      }
2151    
# Line 1942  bool unparseLevel(const Level &level, By Line 2159  bool unparseLevel(const Level &level, By
2159    bool needGameModeArr[GameMode_Count];    bool needGameModeArr[GameMode_Count];
2160    {    {
2161      for (int curGameModeInt = GameMode_First;      for (int curGameModeInt = GameMode_First;
2162           curGameModeInt <= GameMode_Last;           curGameModeInt <= GameMode_Last;
2163           curGameModeInt++) {           curGameModeInt++) {
2164        GameMode curGameMode = GameMode(curGameModeInt);        GameMode curGameMode = GameMode(curGameModeInt);
2165        needGameModeArr[curGameMode] = false;        needGameModeArr[curGameMode] = false;
2166      }      }
# Line 1956  bool unparseLevel(const Level &level, By Line 2173  bool unparseLevel(const Level &level, By
2173        const string &dataHard = marble.getData(GameMode_Hard);        const string &dataHard = marble.getData(GameMode_Hard);
2174        const string &dataEasy = marble.getData(GameMode_Easy);        const string &dataEasy = marble.getData(GameMode_Easy);
2175        if (dataHard.compare(dataEasy) != 0) {        if (dataHard.compare(dataEasy) != 0) {
2176          bMarblesDifferent = true;          bMarblesDifferent = true;
2177          needGameModeArr[GameMode_Hard] = true;          needGameModeArr[GameMode_Hard] = true;
2178          needGameModeArr[GameMode_Easy] = true;          needGameModeArr[GameMode_Easy] = true;
2179          break;          break;
2180        }        }
2181      }      }
2182    }    }
# Line 1967  bool unparseLevel(const Level &level, By Line 2184  bool unparseLevel(const Level &level, By
2184    bool bRubberBandsDifferent = false;    bool bRubberBandsDifferent = false;
2185    {    {
2186      if (level.getNumRubberBands(GameMode_Hard) !=      if (level.getNumRubberBands(GameMode_Hard) !=
2187          level.getNumRubberBands(GameMode_Easy)) {          level.getNumRubberBands(GameMode_Easy)) {
2188        bRubberBandsDifferent = true;        bRubberBandsDifferent = true;
2189      }      }
2190      for (int nRubberBand = 0;      for (int nRubberBand = 0;
2191           (nRubberBand < level.getNumRubberBands(GameMode_Hard) &&           (nRubberBand < level.getNumRubberBands(GameMode_Hard) &&
2192            nRubberBand < level.getNumRubberBands(GameMode_Easy));            nRubberBand < level.getNumRubberBands(GameMode_Easy));
2193           nRubberBand++) {           nRubberBand++) {
2194        const RubberBand &rubberBandHard = level.getRubberBand(GameMode_Hard,        const RubberBand &rubberBandHard = level.getRubberBand(GameMode_Hard,
2195                                                               nRubberBand);                                                               nRubberBand);
2196        const RubberBand &rubberBandEasy = level.getRubberBand(GameMode_Easy,        const RubberBand &rubberBandEasy = level.getRubberBand(GameMode_Easy,
2197                                                               nRubberBand);                                                               nRubberBand);
2198        if (rubberBandHard != rubberBandEasy) {        if (rubberBandHard != rubberBandEasy) {
2199          bRubberBandsDifferent = true;          bRubberBandsDifferent = true;
2200        }        }
2201      }      }
2202      if ((level.getBlackRubberBandPieceNaturalLength(GameMode_Hard) !=      if ((level.getBlackRubberBandPieceNaturalLength(GameMode_Hard) !=
2203           level.getBlackRubberBandPieceNaturalLength(GameMode_Easy)) ||           level.getBlackRubberBandPieceNaturalLength(GameMode_Easy)) ||
2204          (level.getBlackRubberBandPieceForce(GameMode_Hard) !=          (level.getBlackRubberBandPieceForce(GameMode_Hard) !=
2205           level.getBlackRubberBandPieceForce(GameMode_Easy)) ||           level.getBlackRubberBandPieceForce(GameMode_Easy)) ||
2206          (level.getWhiteRubberBandPieceNaturalLength(GameMode_Hard) !=          (level.getWhiteRubberBandPieceNaturalLength(GameMode_Hard) !=
2207           level.getWhiteRubberBandPieceNaturalLength(GameMode_Easy)) ||           level.getWhiteRubberBandPieceNaturalLength(GameMode_Easy)) ||
2208          (level.getWhiteRubberBandPieceForce(GameMode_Hard) !=          (level.getWhiteRubberBandPieceForce(GameMode_Hard) !=
2209           level.getWhiteRubberBandPieceForce(GameMode_Easy)) ||           level.getWhiteRubberBandPieceForce(GameMode_Easy)) ||
2210          (level.getRubberBandObjectNaturalLength(GameMode_Hard) !=          (level.getRubberBandObjectNaturalLength(GameMode_Hard) !=
2211           level.getRubberBandObjectNaturalLength(GameMode_Easy)) ||           level.getRubberBandObjectNaturalLength(GameMode_Easy)) ||
2212          (level.getRubberBandObjectForce(GameMode_Hard) !=          (level.getRubberBandObjectForce(GameMode_Hard) !=
2213           level.getRubberBandObjectForce(GameMode_Easy))) {           level.getRubberBandObjectForce(GameMode_Easy))) {
2214        bRubberBandsDifferent = true;        bRubberBandsDifferent = true;
2215      }      }
2216    
2217      if (bRubberBandsDifferent) {      if (bRubberBandsDifferent) {
2218        for (int curGameModeInt = GameMode_First;        for (int curGameModeInt = GameMode_First;
2219             curGameModeInt <= GameMode_Last;             curGameModeInt <= GameMode_Last;
2220             curGameModeInt++) {             curGameModeInt++) {
2221          GameMode curGameMode = GameMode(curGameModeInt);          GameMode curGameMode = GameMode(curGameModeInt);
2222          if (level.getNumRubberBands(curGameMode) > 0 ||          if (level.getNumRubberBands(curGameMode) > 0 ||
2223              level.getBlackRubberBandPieceNaturalLength(curGameMode) != -1 ||              level.getBlackRubberBandPieceNaturalLength(curGameMode) != -1 ||
2224              level.getBlackRubberBandPieceForce(curGameMode) != -1 ||              level.getBlackRubberBandPieceForce(curGameMode) != -1 ||
2225              level.getWhiteRubberBandPieceNaturalLength(curGameMode) != -1 ||              level.getWhiteRubberBandPieceNaturalLength(curGameMode) != -1 ||
2226              level.getWhiteRubberBandPieceForce(curGameMode) != -1 ||              level.getWhiteRubberBandPieceForce(curGameMode) != -1 ||
2227              level.getRubberBandObjectNaturalLength(curGameMode) != -1 ||              level.getRubberBandObjectNaturalLength(curGameMode) != -1 ||
2228              level.getRubberBandObjectForce(curGameMode) != -1) {              level.getRubberBandObjectForce(curGameMode) != -1) {
2229            needGameModeArr[curGameMode] = true;            needGameModeArr[curGameMode] = true;
2230          }          }
2231        }        }
2232      }      }
2233    }    }
# Line 2021  bool unparseLevel(const Level &level, By Line 2238  bool unparseLevel(const Level &level, By
2238        bResetDifferent = true;        bResetDifferent = true;
2239    
2240        for (int curGameModeInt = GameMode_First;        for (int curGameModeInt = GameMode_First;
2241             curGameModeInt <= GameMode_Last;             curGameModeInt <= GameMode_Last;
2242             curGameModeInt++) {             curGameModeInt++) {
2243          GameMode curGameMode = GameMode(curGameModeInt);          GameMode curGameMode = GameMode(curGameModeInt);
2244          if (level.getReset(curGameMode)) {          if (level.getReset(curGameMode)) {
2245            needGameModeArr[curGameMode] = true;            needGameModeArr[curGameMode] = true;
2246          }          }
2247        }        }
2248      }      }
2249    }    }
# Line 2034  bool unparseLevel(const Level &level, By Line 2251  bool unparseLevel(const Level &level, By
2251    bool bForceDifferent = false;    bool bForceDifferent = false;
2252    {    {
2253      if ((level.getFlatForce(GameMode_Hard) !=      if ((level.getFlatForce(GameMode_Hard) !=
2254           level.getFlatForce(GameMode_Easy)) ||           level.getFlatForce(GameMode_Easy)) ||
2255          (level.getSlopeForce(GameMode_Hard) !=          (level.getSlopeForce(GameMode_Hard) !=
2256           level.getSlopeForce(GameMode_Easy)) ||           level.getSlopeForce(GameMode_Easy)) ||
2257          (level.getFriction(GameMode_Hard) !=          (level.getFriction(GameMode_Hard) !=
2258           level.getFriction(GameMode_Easy))) {           level.getFriction(GameMode_Easy))) {
2259        bForceDifferent = true;        bForceDifferent = true;
2260    
2261        for (int curGameModeInt = GameMode_First;        for (int curGameModeInt = GameMode_First;
2262             curGameModeInt <= GameMode_Last;             curGameModeInt <= GameMode_Last;
2263             curGameModeInt++) {             curGameModeInt++) {
2264          GameMode curGameMode = GameMode(curGameModeInt);          GameMode curGameMode = GameMode(curGameModeInt);
2265          if (level.getFlatForce(curGameMode) != -1 ||          if (level.getFlatForce(curGameMode) != -1 ||
2266              level.getSlopeForce(curGameMode) != -1 ||              level.getSlopeForce(curGameMode) != -1 ||
2267              level.getFriction(curGameMode) != -1) {              level.getFriction(curGameMode) != -1) {
2268            needGameModeArr[curGameMode] = true;            needGameModeArr[curGameMode] = true;
2269          }          }
2270        }        }
2271      }      }
2272    }    }
2273    
2274    bool bOscillatorsDifferent = false;    bool bOscillatorsDifferent = false;
2275    {    {
2276      const set<Oscillator> &hardOscillators =      const OscillatorMap &hardOscillators =
2277        level.getOscillators(GameMode_Hard);        level.getOscillators(GameMode_Hard);
2278      const set<Oscillator> &easyOscillators =      const OscillatorMap &easyOscillators =
2279        level.getOscillators(GameMode_Easy);        level.getOscillators(GameMode_Easy);
2280    
2281      if (hardOscillators.size() != easyOscillators.size()) {      if (hardOscillators.size() != easyOscillators.size()) {
2282        bOscillatorsDifferent = true;        bOscillatorsDifferent = true;
2283      }      }
2284      set<Oscillator>::const_iterator hardIter = hardOscillators.begin();      OscillatorMap::const_iterator hardIter = hardOscillators.begin();
2285      set<Oscillator>::const_iterator hardEnd = hardOscillators.end();      OscillatorMap::const_iterator hardEnd = hardOscillators.end();
2286      set<Oscillator>::const_iterator easyIter = easyOscillators.begin();      OscillatorMap::const_iterator easyIter = easyOscillators.begin();
2287      set<Oscillator>::const_iterator easyEnd = easyOscillators.end();      OscillatorMap::const_iterator easyEnd = easyOscillators.end();
2288      for(;      for(;
2289          hardIter != hardEnd && easyIter != easyEnd;          hardIter != hardEnd && easyIter != easyEnd;
2290          ++hardIter, ++easyIter) {          ++hardIter, ++easyIter) {
2291        const Oscillator &hardOscillator = *hardIter;        const Block &hardBlock = hardIter->first;
2292        const Oscillator &easyOscillator = *easyIter;        const Block &easyBlock = easyIter->first;
2293        if (hardOscillator != easyOscillator) {        const Oscillator &hardOscillator = hardIter->second;
2294          bOscillatorsDifferent = true;        const Oscillator &easyOscillator = easyIter->second;
2295          if (hardBlock != easyBlock ||
2296              hardOscillator != easyOscillator) {
2297            bOscillatorsDifferent = true;
2298        }        }
2299      }      }
2300    
2301      if (bOscillatorsDifferent) {      if (bOscillatorsDifferent) {
2302        for (int curGameModeInt = GameMode_First;        for (int curGameModeInt = GameMode_First;
2303             curGameModeInt <= GameMode_Last;             curGameModeInt <= GameMode_Last;
2304             curGameModeInt++) {             curGameModeInt++) {
2305          GameMode curGameMode = GameMode(curGameModeInt);          GameMode curGameMode = GameMode(curGameModeInt);
2306          if (!level.getOscillators(curGameMode).empty()) {          const OscillatorMap &oscillators = level.getOscillators(curGameMode);
2307            needGameModeArr[curGameMode] = true;          OscillatorMap::const_iterator iter = oscillators.begin();
2308          }          OscillatorMap::const_iterator end = oscillators.end();
2309            for (; iter != end; ++iter) {
2310              const Oscillator &oscillator = iter->second;
2311              if (oscillator != Oscillator()) {
2312                needGameModeArr[curGameMode] = true;
2313              }
2314            }
2315        }        }
2316      }      }
2317    }    }
# Line 2112  bool unparseLevel(const Level &level, By Line 2338  bool unparseLevel(const Level &level, By
2338      bool bDone = false;      bool bDone = false;
2339      while (!bDone) {      while (!bDone) {
2340        if (gameMode == GameMode_Invalid ||        if (gameMode == GameMode_Invalid ||
2341            needGameModeArr[gameMode]) {            needGameModeArr[gameMode]) {
2342    
2343            GameMode realGameMode =
2344              (gameMode == GameMode_Invalid) ? GameMode_Hard : gameMode;
2345    
2346            if (gameMode == GameMode_Hard) {
2347              specialItems.push_back("[");
2348            }
2349            if (gameMode == GameMode_Easy) {
2350              specialItems.push_back("{");
2351            }
2352    
2353            // Marbles
2354            if ((bMarblesDifferent &&
2355                 gameMode != GameMode_Invalid) ||
2356                (!bMarblesDifferent &&
2357                 gameMode == GameMode_Invalid &&
2358                 bFirstPass)) {
2359    
2360              for (int nMarble = 0; nMarble < level.getNumMarbles(); nMarble++) {
2361                const Marble &marble = level.getMarble(nMarble);
2362    
2363                unsigned char marbleCode = 0x00;
2364                switch (marble.getMarbleType()) {
2365                case MarbleType_Black:          marbleCode = 'B'; break;
2366                case MarbleType_White:          marbleCode = 'b'; break;
2367                case MarbleType_Meditation:     marbleCode = 'M'; break;
2368                case MarbleType_Horse:          marbleCode = 'G'; break;
2369                case MarbleType_Jack:           marbleCode = 'K'; break;
2370                case MarbleType_LifeSpitter:    marbleCode = 'C'; break;
2371                case MarbleType_DynamiteHolder: marbleCode = 'D'; break;
2372                default:
2373                  pMsg->assign("Invalid marble type.");
2374                  return false;
2375                }
2376    
2377                string item;
2378                item.append(1, 'F');
2379                item.append(1, marbleCode);
2380                item.append(marble.getData(realGameMode));
2381    
2382          GameMode realGameMode =              specialItems.push_back(item);
2383            (gameMode == GameMode_Invalid) ? GameMode_Hard : gameMode;            }
2384            }
2385    
2386            // Rubber bands
2387            if ((bRubberBandsDifferent &&
2388                 gameMode != GameMode_Invalid) ||
2389                (!bRubberBandsDifferent &&
2390                 gameMode == GameMode_Invalid &&
2391                 bFirstPass)) {
2392    
2393              for (int nRubberBand = 0;
2394                   nRubberBand < level.getNumRubberBands(realGameMode);
2395                   nRubberBand++) {
2396                const RubberBand &rubberBand =
2397                  level.getRubberBand(realGameMode, nRubberBand);
2398                vector<int> numberList1;
2399                vector<int> numberList2;
2400                numberList1.push_back(rubberBand.getNaturalLength());
2401                numberList1.push_back(rubberBand.getForce());
2402                numberList2.push_back(rubberBand.getFirstEndMarble());
2403                if (rubberBand.isSecondEndMarble()) {
2404                  numberList1.push_back(-1);
2405                  numberList2.push_back(rubberBand.getSecondEndMarble());
2406                } else {
2407                  unsigned int x = rubberBand.getSecondEndPieceX();
2408                  unsigned int y = rubberBand.getSecondEndPieceY();
2409                  if (x > level.getWidth() ||
2410                      y > level.getHeight()) {
2411                    pMsg->assign("Rubber band block out of range.");
2412                    return false;
2413                  }
2414                  unsigned int blockNumber =
2415                    y * level.getWidth() + x;
2416                  numberList1.push_back(blockNumber);
2417                }
2418    
2419                string strNumberList1;
2420                unparseNumberList(numberList1, &strNumberList1);
2421                string strNumberList2;
2422                unparseNumberList(numberList2, &strNumberList2);
2423    
2424                string str;
2425                str.append(1, 'B');
2426                str.append(strNumberList1);
2427                str.append(1, (char)0xf9);
2428                str.append(strNumberList2);
2429                specialItems.push_back(str);
2430              }
2431    
2432              {
2433                vector<int> numberList1;
2434                numberList1.push_back(level.getBlackRubberBandPieceNaturalLength(realGameMode));
2435                numberList1.push_back(level.getBlackRubberBandPieceForce(realGameMode));
2436                if (numberList1[0] == -1 && numberList1[1] == -1) {
2437                  numberList1.clear();
2438                }
2439    
2440                vector<int> numberList2;
2441                numberList2.push_back(level.getWhiteRubberBandPieceNaturalLength(realGameMode));
2442                numberList2.push_back(level.getWhiteRubberBandPieceForce(realGameMode));
2443                if (numberList2[0] == -1 && numberList2[1] == -1) {
2444                  numberList2.clear();
2445                }
2446    
2447                vector<int> numberList3;
2448                numberList3.push_back(level.getRubberBandObjectNaturalLength(realGameMode));
2449                numberList3.push_back(level.getRubberBandObjectForce(realGameMode));
2450                if (numberList3[0] == -1 && numberList3[1] == -1) {
2451                  numberList3.clear();
2452                }
2453    
2454                if (!numberList1.empty() ||
2455                    !numberList2.empty() ||
2456                    !numberList3.empty()) {
2457                  string strNumberList1;
2458                  unparseNumberList(numberList1, &strNumberList1);
2459    
2460                  string str;
2461                  str.append(1, 'B');
2462                  str.append(strNumberList1);
2463                  specialItems.push_back(str);
2464                }
2465    
2466                if (!numberList2.empty() ||
2467                    !numberList3.empty()) {
2468                  string strNumberList2;
2469                  unparseNumberList(numberList2, &strNumberList2);
2470    
2471                  string str;
2472                  str.append(1, 'B');
2473                  str.append(strNumberList2);
2474                  specialItems.push_back(str);
2475                }
2476    
2477                if (!numberList3.empty()) {
2478                  string strNumberList3;
2479                  unparseNumberList(numberList3, &strNumberList3);
2480    
2481                  string str;
2482                  str.append(1, 'B');
2483                  str.append(strNumberList3);
2484                  specialItems.push_back(str);
2485                }
2486              }
2487            }
2488    
2489            // Reset
2490            if ((bResetDifferent &&
2491                 gameMode != GameMode_Invalid) ||
2492                (!bResetDifferent &&
2493                 gameMode == GameMode_Invalid &&
2494                 !bFirstPass)) {
2495    
2496              if (level.getReset(realGameMode)) {
2497                specialItems.push_back("s");
2498              }
2499            }
2500    
2501          if (gameMode == GameMode_Hard) {          // Force
2502            specialItems.push_back("[");          if ((bForceDifferent &&
2503          }               gameMode != GameMode_Invalid) ||
2504          if (gameMode == GameMode_Easy) {              (!bForceDifferent &&
2505            specialItems.push_back("{");               gameMode == GameMode_Invalid &&
2506          }               !bFirstPass)) {
2507    
2508          // Marbles            vector<int> numberList;
2509          if ((bMarblesDifferent &&            numberList.resize(3);
2510               gameMode != GameMode_Invalid) ||            numberList[0] = level.getFlatForce(realGameMode);
2511              (!bMarblesDifferent &&            numberList[1] = level.getFriction(realGameMode);
2512               gameMode == GameMode_Invalid &&            numberList[2] = level.getSlopeForce(realGameMode);
2513               bFirstPass)) {  
2514              int sz = 3;
2515            for (int nMarble = 0; nMarble < level.getNumMarbles(); nMarble++) {            while (sz > 0 && numberList[sz - 1] == -1) {
2516              const Marble &marble = level.getMarble(nMarble);              sz--;
2517              }
2518              unsigned char marbleCode = 0x00;            numberList.resize(sz);
2519              switch (marble.getMarbleType()) {  
2520              case MarbleType_Black:          marbleCode = 'B'; break;            if (sz > 0) {
2521              case MarbleType_White:          marbleCode = 'b'; break;              string strNumberList;
2522              case MarbleType_Meditation:     marbleCode = 'M'; break;              unparseNumberList(numberList, &strNumberList);
2523              case MarbleType_Horse:          marbleCode = 'G'; break;  
2524              case MarbleType_Jack:           marbleCode = 'K'; break;              string str;
2525              case MarbleType_LifeSpitter:    marbleCode = 'C'; break;              str.append(1, 'g');
2526              case MarbleType_DynamiteHolder: marbleCode = 'D'; break;              str.append(strNumberList);
2527              default:              specialItems.push_back(str);
2528                pMsg->assign("Invalid marble type.");            }
2529                return false;          }
2530              }  
2531            // Oscillators
2532              string item;          if ((bOscillatorsDifferent &&
2533              item.append(1, 'F');               gameMode != GameMode_Invalid) ||
2534              item.append(1, marbleCode);              (!bOscillatorsDifferent &&
2535              item.append(marble.getData(realGameMode));               gameMode == GameMode_Invalid &&
2536                 !bFirstPass)) {
2537              specialItems.push_back(item);            const OscillatorMap &oscillators =
2538            }              level.getOscillators(realGameMode);
2539          }            OscillatorMap::const_iterator iter = oscillators.begin();
2540              OscillatorMap::const_iterator end = oscillators.end();
2541          // Rubber bands            for (; iter != end; ++iter) {
2542          if ((bRubberBandsDifferent &&              const Block &block = iter->first;
2543               gameMode != GameMode_Invalid) ||              const Oscillator &oscillator = iter->second;
2544              (!bRubberBandsDifferent &&  
2545               gameMode == GameMode_Invalid &&              unsigned int x = block.getX();
2546               bFirstPass)) {              unsigned int y = block.getY();
2547                if (x > level.getWidth() || y > level.getHeight()) {
2548            for (int nRubberBand = 0;                pMsg->assign("Oscillator block out of range.");
2549                 nRubberBand < level.getNumRubberBands(realGameMode);                return false;
2550                 nRubberBand++) {              }
2551              const RubberBand &rubberBand =              unsigned int blockNumber =
2552                level.getRubberBand(realGameMode, nRubberBand);                y * level.getWidth() + x;
2553              vector<int> numberList1;  
2554              vector<int> numberList2;              if (oscillator.getPeriod() != 0) {
2555              numberList1.push_back(rubberBand.getNaturalLength());                vector<int> numberList;
2556              numberList1.push_back(rubberBand.getForce());                numberList.push_back(blockNumber);
2557              numberList2.push_back(rubberBand.getFirstEndMarble());                numberList.push_back(oscillator.getPeriod());
2558              if (rubberBand.isSecondEndMarble()) {  
2559                numberList1.push_back(-1);                string strNumberList;
2560                numberList2.push_back(rubberBand.getSecondEndMarble());                unparseNumberList(numberList, &strNumberList);
2561              } else {  
2562                unsigned int x = rubberBand.getSecondEndPieceX();                string str;
2563                unsigned int y = rubberBand.getSecondEndPieceY();                str.append(1, '~');
2564                if (x > level.getWidth() ||                str.append(strNumberList);
2565                    y > level.getHeight()) {                specialItems.push_back(str);
2566                  pMsg->assign("Rubber band block out of range.");              }
2567                  return false;            }
2568                }          }
2569                unsigned int blockNumber =  
2570                  y * level.getWidth() + x;          // Still oscillators
2571                numberList1.push_back(blockNumber);          if ((bOscillatorsDifferent &&
2572              }               gameMode != GameMode_Invalid) ||
2573                (!bOscillatorsDifferent &&
2574              string strNumberList1;               gameMode == GameMode_Invalid &&
2575              unparseNumberList(numberList1, &strNumberList1);               !bFirstPass)) {
2576              string strNumberList2;            const OscillatorMap &oscillators =
2577              unparseNumberList(numberList2, &strNumberList2);              level.getOscillators(realGameMode);
2578              OscillatorMap::const_iterator iter = oscillators.begin();
2579              string str;            OscillatorMap::const_iterator end = oscillators.end();
2580              str.append(1, 'B');            for (; iter != end; ++iter) {
2581              str.append(strNumberList1);              const Block &block = iter->first;
2582              str.append(1, (char)0xf9);              const Oscillator &oscillator = iter->second;
2583              str.append(strNumberList2);  
2584              specialItems.push_back(str);              unsigned int x = block.getX();
2585            }              unsigned int y = block.getY();
2586                if (x > level.getWidth() || y > level.getHeight()) {
2587            {                pMsg->assign("Oscillator block out of range.");
2588              vector<int> numberList1;                return false;
2589              numberList1.push_back(level.getBlackRubberBandPieceNaturalLength(realGameMode));              }
2590              numberList1.push_back(level.getBlackRubberBandPieceForce(realGameMode));              unsigned int blockNumber =
2591              if (numberList1[0] == -1 && numberList1[1] == -1) {                y * level.getWidth() + x;
2592                numberList1.clear();  
2593              }              if (!oscillator.getOn()) {
2594                  vector<int> numberList;
2595              vector<int> numberList2;                numberList.push_back(blockNumber);
2596              numberList2.push_back(level.getWhiteRubberBandPieceNaturalLength(realGameMode));  
2597              numberList2.push_back(level.getWhiteRubberBandPieceForce(realGameMode));                string strNumberList;
2598              if (numberList2[0] == -1 && numberList2[1] == -1) {                unparseNumberList(numberList, &strNumberList);
2599                numberList2.clear();  
2600              }                string str;
2601                  str.append(1, 'O');
2602              vector<int> numberList3;                str.append(strNumberList);
2603              numberList3.push_back(level.getRubberBandObjectNaturalLength(realGameMode));                specialItems.push_back(str);
2604              numberList3.push_back(level.getRubberBandObjectForce(realGameMode));              }
2605              if (numberList3[0] == -1 && numberList3[1] == -1) {            }
2606                numberList3.clear();          }
2607              }  
2608            if (gameMode == GameMode_Hard) {
2609              if (!numberList1.empty() ||            specialItems.push_back("]");
2610                  !numberList2.empty() ||          }
2611                  !numberList3.empty()) {          if (gameMode == GameMode_Easy) {
2612                string strNumberList1;            specialItems.push_back("}");
2613                unparseNumberList(numberList1, &strNumberList1);          }
   
               string str;  
               str.append(1, 'B');  
               str.append(strNumberList1);  
               specialItems.push_back(str);  
             }  
   
             if (!numberList2.empty() ||  
                 !numberList3.empty()) {  
               string strNumberList2;  
               unparseNumberList(numberList2, &strNumberList2);  
   
               string str;  
               str.append(1, 'B');  
               str.append(strNumberList2);  
               specialItems.push_back(str);  
             }  
   
             if (!numberList3.empty()) {  
               string strNumberList3;  
               unparseNumberList(numberList3, &strNumberList3);  
   
               string str;  
               str.append(1, 'B');  
               str.append(strNumberList3);  
               specialItems.push_back(str);  
             }  
           }  
         }  
   
         // Reset  
         if ((bResetDifferent &&  
              gameMode != GameMode_Invalid) ||  
             (!bResetDifferent &&  
              gameMode == GameMode_Invalid &&  
              !bFirstPass)) {  
   
           if (level.getReset(realGameMode)) {  
             specialItems.push_back("s");  
           }  
         }  
   
         // Force  
         if ((bForceDifferent &&  
              gameMode != GameMode_Invalid) ||  
             (!bForceDifferent &&  
              gameMode == GameMode_Invalid &&  
              !bFirstPass)) {  
   
           vector<int> numberList;  
           numberList.resize(3);  
           numberList[0] = level.getFlatForce(realGameMode);  
           numberList[1] = level.getFriction(realGameMode);  
           numberList[2] = level.getSlopeForce(realGameMode);  
   
           int sz = 3;  
           while (sz > 0 && numberList[sz - 1] == -1) {  
             sz--;  
           }  
           numberList.resize(sz);  
   
           if (sz > 0) {  
             string strNumberList;  
             unparseNumberList(numberList, &strNumberList);  
   
             string str;  
             str.append(1, 'g');  
             str.append(strNumberList);  
             specialItems.push_back(str);  
           }  
         }  
   
         // Oscillators  
         if ((bOscillatorsDifferent &&  
              gameMode != GameMode_Invalid) ||  
             (!bOscillatorsDifferent &&  
              gameMode == GameMode_Invalid &&  
              !bFirstPass)) {  
           const set<Oscillator> &oscillators =  
             level.getOscillators(realGameMode);  
           set<Oscillator>::const_iterator iter = oscillators.begin();  
           set<Oscillator>::const_iterator end = oscillators.end();  
           for (; iter != end; ++iter) {  
             const Oscillator &oscillator = *iter;  
   
             unsigned int x = oscillator.getX();  
             unsigned int y = oscillator.getY();  
             if (x > level.getWidth() || y > level.getHeight()) {  
               pMsg->assign("Oscillator block out of range.");  
               return false;  
             }  
             unsigned int blockNumber =  
               y * level.getWidth() + x;  
   
             vector<int> numberList;  
             numberList.push_back(blockNumber);  
             numberList.push_back(oscillator.getPeriod());  
   
             string strNumberList;  
             unparseNumberList(numberList, &strNumberList);  
   
             string str;  
             str.append(1, '~');  
             str.append(strNumberList);  
             specialItems.push_back(str);  
           }  
         }  
   
         if (gameMode == GameMode_Hard) {  
           specialItems.push_back("]");  
         }  
         if (gameMode == GameMode_Easy) {  
           specialItems.push_back("}");  
         }  
2614    
2615        }        }
2616    
2617        switch (gameMode) {        switch (gameMode) {
2618        case GameMode_Invalid:        case GameMode_Invalid:
2619          if (bFirstPass) {          if (bFirstPass) {
2620            bFirstPass = false;            bFirstPass = false;
2621            gameMode = GameMode_Hard;            gameMode = GameMode_Hard;
2622          } else {          } else {
2623            bDone = true;            bDone = true;
2624          }          }
2625          break;          break;
2626        case GameMode_Hard:        case GameMode_Hard:
2627          gameMode = GameMode_Easy;          gameMode = GameMode_Easy;
2628          break;          break;
2629        case GameMode_Easy:        case GameMode_Easy:
2630          gameMode = GameMode_Invalid;          gameMode = GameMode_Invalid;
2631          break;          break;
2632        default:        default:
2633          ;          ;
2634        }        }
2635      }      }
2636    }    }
# Line 2422  bool unparseLevel(const Level &level, By Line 2689  bool unparseLevel(const Level &level, By
2689      if (level.getNumScrambleItems() > 0) {      if (level.getNumScrambleItems() > 0) {
2690        vector<int> numberList;        vector<int> numberList;
2691        for (int nScrambleItem = 0;        for (int nScrambleItem = 0;
2692             nScrambleItem < level.getNumScrambleItems();             nScrambleItem < level.getNumScrambleItems();
2693             nScrambleItem++) {             nScrambleItem++) {
2694          const ScrambleItem &scrambleItem =          const ScrambleItem &scrambleItem =
2695            level.getScrambleItem(nScrambleItem);            level.getScrambleItem(nScrambleItem);
2696    
2697          unsigned int x = scrambleItem.getX();          unsigned int x = scrambleItem.getX();
2698          unsigned int y = scrambleItem.getY();          unsigned int y = scrambleItem.getY();
2699          if (x > level.getWidth() ||          if (x > level.getWidth() ||
2700              y > level.getHeight()) {              y > level.getHeight()) {
2701            pMsg->assign("Scramble item block out of range.");            pMsg->assign("Scramble item block out of range.");
2702            return false;            return false;
2703          }          }
2704          unsigned int blockNumber =          unsigned int blockNumber =
2705            y * level.getWidth() + x;            y * level.getWidth() + x;
   
         ScrambleDir dir = scrambleItem.getDir();  
         int dirInt = -1;  
         switch (dir) {  
         case ScrambleDir_Up:    dirInt = 0; break;  
         case ScrambleDir_Down:  dirInt = 1; break;  
         case ScrambleDir_Left:  dirInt = 2; break;  
         case ScrambleDir_Right: dirInt = 3; break;  
         default:  
           pMsg->assign("Invalid scramble item direction.");  
           return false;  
         }  
2706    
2707          numberList.push_back(blockNumber);          Direction dir = scrambleItem.getDir();
2708          numberList.push_back(dirInt);          int dirInt = -1;
2709            switch (dir) {
2710            case Direction_Up:    dirInt = 0; break;
2711            case Direction_Down:  dirInt = 1; break;
2712            case Direction_Left:  dirInt = 2; break;
2713            case Direction_Right: dirInt = 3; break;
2714            default:
2715              pMsg->assign("Invalid scramble item direction.");
2716              return false;
2717            }
2718    
2719            numberList.push_back(blockNumber);
2720            numberList.push_back(dirInt);
2721        }        }
2722    
2723        string strNumberList;        string strNumberList;
# Line 2464  bool unparseLevel(const Level &level, By Line 2731  bool unparseLevel(const Level &level, By
2731    }    }
2732    
2733    {    {
2734        // Lasers
2735        for (int nLaser = 0; nLaser < 3; nLaser++) {
2736          const Laser &laser = level.getLaser(nLaser);
2737          if (laser != s_defaultLasers[nLaser]) {
2738            vector<int> numberList;
2739    
2740            Direction dir = laser.getDir();
2741            int dirInt = -1;
2742            switch (dir) {
2743            case Direction_Up:    dirInt = 0; break;
2744            case Direction_Down:  dirInt = 1; break;
2745            case Direction_Left:  dirInt = 2; break;
2746            case Direction_Right: dirInt = 3; break;
2747            default:
2748              pMsg->assign("Invalid laser direction.");
2749              return false;
2750            }
2751    
2752            numberList.push_back(nLaser + 1);
2753            numberList.push_back(dirInt);
2754    
2755            string strNumberList;
2756            unparseNumberList(numberList, &strNumberList);
2757    
2758            string str;
2759            str.append(1, 'L');
2760            str.append(strNumberList);
2761            if (laser.getOn()) {
2762              str.append(1, (char)0xf9);
2763            }
2764    
2765            specialItems.push_back(str);
2766          }
2767        }
2768      }
2769    
2770      {
2771      // Stuff we don't know about yet      // Stuff we don't know about yet
2772      for (int i = 0; i < (int)level.getSpecialItems().size(); i++) {      for (int i = 0; i < (int)level.getSpecialItems().size(); i++) {
2773        specialItems.push_back(level.getSpecialItems()[i]);        specialItems.push_back(level.getSpecialItems()[i]);
# Line 2474  bool unparseLevel(const Level &level, By Line 2778  bool unparseLevel(const Level &level, By
2778      // Notes      // Notes
2779      for (int nNote = 0; nNote < 2; nNote++) {      for (int nNote = 0; nNote < 2; nNote++) {
2780        for (int nLang = Language_First;        for (int nLang = Language_First;
2781             nLang <= Language_Last;             nLang <= Language_Last;
2782             nLang++) {             nLang++) {
2783          Language lang = (Language)nLang;          Language lang = (Language)nLang;
2784          const string &noteText = level.getNoteText(nNote, lang);          const string &noteText = level.getNoteText(nNote, lang);
2785          if (!noteText.empty()) {          if (!noteText.empty()) {
2786            unsigned char noteCode = 0x00;            unsigned char noteCode = 0x00;
2787            switch (nNote) {            switch (nNote) {
2788            case 0: noteCode = 'Z'; break;            case 0: noteCode = 'Z'; break;
2789            case 1: noteCode = 'z'; break;            case 1: noteCode = 'z'; break;
2790            }            }
2791    
2792            unsigned char langCode = 0x00;            unsigned char langCode = 0x00;
2793            switch(lang) {            switch(lang) {
2794            case Language_German:  langCode = 'g'; break;            case Language_German:  langCode = 'g'; break;
2795            case Language_English: langCode = 'e'; break;            case Language_English: langCode = 'e'; break;
2796            case Language_French:  langCode = 'f'; break;            case Language_French:  langCode = 'f'; break;
2797            default:            default:
2798              pMsg->assign("Invalid language.");              pMsg->assign("Invalid language.");
2799              return false;              return false;
2800            }            }
2801    
2802            string noteItem;            string noteItem;
2803    
2804            noteItem.append(1, noteCode);            noteItem.append(1, noteCode);
2805            noteItem.append(1, langCode);            noteItem.append(1, langCode);
2806            noteItem.append(1, '"');            noteItem.append(1, '"');
2807            noteItem.append(noteText);            noteItem.append(noteText);
2808            noteItem.append(1, '"');            noteItem.append(1, '"');
2809    
2810            specialItems.push_back(noteItem);            specialItems.push_back(noteItem);
2811          }          }
2812        }        }
2813      }      }
2814    }    }
# Line 2540  bool unparseLevel(const Level &level, By Line 2844  bool unparseLevel(const Level &level, By
2844        out[cur++] = 0x20;        out[cur++] = 0x20;
2845      }      }
2846      copy(specialItems[nItem].begin(),      copy(specialItems[nItem].begin(),
2847           specialItems[nItem].end(),           specialItems[nItem].end(),
2848           out.begin() + cur);           out.begin() + cur);
2849      cur += specialItems[nItem].size();      cur += specialItems[nItem].size();
2850    }    }
2851    out[cur++] = 0x00;    out[cur++] = 0x00;
# Line 2549  bool unparseLevel(const Level &level, By Line 2853  bool unparseLevel(const Level &level, By
2853    // Surfaces    // Surfaces
2854    ByteVec unparsedSurfaces;    ByteVec unparsedSurfaces;
2855    if (!unparseGrid(level.getGrid(GridType_Surfaces),    if (!unparseGrid(level.getGrid(GridType_Surfaces),
2856                     &unparsedSurfaces, pMsg)) {                     &unparsedSurfaces, pMsg)) {
2857      return false;      return false;
2858    }    }
2859    
# Line 2567  bool unparseLevel(const Level &level, By Line 2871  bool unparseLevel(const Level &level, By
2871    // Pieces    // Pieces
2872    ByteVec unparsedPieces;    ByteVec unparsedPieces;
2873    if (!unparseGrid(level.getGrid(GridType_Pieces),    if (!unparseGrid(level.getGrid(GridType_Pieces),
2874                     &unparsedPieces, pMsg)) {                     &unparsedPieces, pMsg)) {
2875      return false;      return false;
2876    }    }
2877    
# Line 2585  bool unparseLevel(const Level &level, By Line 2889  bool unparseLevel(const Level &level, By
2889    // Objects    // Objects
2890    ByteVec unparsedObjects;    ByteVec unparsedObjects;
2891    if (!unparseGrid(level.getGrid(GridType_Objects),    if (!unparseGrid(level.getGrid(GridType_Objects),
2892                     &unparsedObjects, pMsg)) {                     &unparsedObjects, pMsg)) {
2893      return false;      return false;
2894    }    }
2895    
2896    out.resize(out.size() + 2 + 2 + unparsedObjects.size());    out.resize(out.size() + 2 + 2 + unparsedObjects.size());
2897    
2898    putInt2(out.begin() + cur, INFOPIECES);    putInt2(out.begin() + cur, INFOOBJECTS);
2899    cur += 2;    cur += 2;
2900    
2901    putInt2(out.begin() + cur, unparsedObjects.size());    putInt2(out.begin() + cur, unparsedObjects.size());
# Line 2617  bool unparseLevel(const Level &level, By Line 2921  bool unparseLevel(const Level &level, By
2921    
2922    return true;    return true;
2923  }  }
2924    
2925    }

Legend:
Removed from v.1.4  
changed lines
  Added in v.1.5

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26