home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Pascal / Games / Showwit! 1.0 / source code / Source / CShLevel.p < prev    next >
Encoding:
Text File  |  1996-02-04  |  13.2 KB  |  476 lines  |  [TEXT/PJMM]

  1. {****************************************************}
  2. {}
  3. {        CShLevel    .p                                                                                                                                                                                                            }
  4. {}
  5. {        Object class for a level in the Showwit game.                                                                                                    }
  6. {}
  7. {****************************************************}
  8.  
  9.  
  10. unit CShLevel;
  11.  
  12. interface
  13.  
  14.     uses
  15.         TCL, ShIntf;
  16.  
  17. implementation
  18.  
  19.     type
  20.         GridType = array[RowRange] of Integer;
  21.  
  22.     type
  23.         LEVLtemplate = record
  24.                 theStartConfig: GridType;
  25.                 theFlipGrids: array[TileRange] of GridType;
  26.             end;
  27.         LEVLtemplateP = ^LEVLtemplate;
  28.         LEVLtemplateH = ^LEVLtemplateP;
  29.  
  30.  
  31. {****************************************************}
  32. {}
  33. {        SetLEVL                                                                                                                                                                                                                    }
  34. {}
  35. {        Set the level details from a LEVL resource.                                                                                                            }
  36. {}
  37. {****************************************************}
  38.  
  39.     procedure CShLevel.SetLEVL (LEVLid: Integer);
  40.  
  41.         var
  42.             theLEVL: LEVLtemplateH;    { Handle to level resource. }
  43.             theRuleCount: TileRange;
  44.  
  45.         { Returns the default name, indicating an error. }
  46.         function DefaultName (LEVLid: Integer): Str15;
  47.  
  48.             var
  49.                 theNumStr: Str255;
  50.  
  51.         begin { DefaultName }
  52.             NumToString(LEVLid, theNumStr);
  53.             DefaultName := Concat('*** ', theNumStr, ' ***');
  54.         end; { DefaultName }
  55.  
  56.         { Returns the default start, which is quite dull. }
  57.         function DefaultStart: ConfigType;
  58.  
  59.             var
  60.                 theConfig: ConfigType;
  61.                 theTile: TileRange;
  62.  
  63.         begin { DefaultStart }
  64.             for theTile := 1 to kMaxTiles do begin
  65.                 theConfig[theTile] := TRUE;
  66.             end; { for }
  67.  
  68.             DefaultStart := theConfig;
  69.         end; { DefaultStart }
  70.  
  71.         { Returns the default rule for the given tile, which is well behaved but boring. }
  72.         function DefaultRule (aTileNum: TileRange): TileRuleType;
  73.  
  74.             var
  75.                 theTileRule: TileRuleType;
  76.  
  77.         begin { DefaultRule }
  78.             theTileRule.theNumDep := 1;
  79.             theTileRule.theDep[1] := aTileNum;
  80.  
  81.             DefaultRule := theTileRule;
  82.         end; { DefaultRule }
  83.  
  84.         { Returns the name of the level, from the resource information. }
  85.         function LEVLName (aLEVL: LEVLTemplateH): Str15;
  86.  
  87.             var
  88.                 rID: Integer;
  89.                 rType: ResType;
  90.                 rName: Str255;
  91.  
  92.         begin { LEVLName }
  93.             GetResInfo(Handle(aLEVL), rID, rType, rName);
  94.  
  95.             if rName = '' then begin
  96.                 { We don't want an empty string for the level name, }
  97.                 { otherwise CAbstract text complains when setting }
  98.                 { up the game window. }
  99.  
  100.                 LEVLName := DefaultName(rID);
  101.             end { if }
  102.             else if Length(rName) < 15 then begin
  103.                 { This section is not really required for THINK Pascal, }
  104.                 { where it is not an error to copy over the end of a string. }
  105.                 { However, in case we recompile under a different compiler }
  106.                 { may as well prevent problems now. }
  107.  
  108.                 LEVLName := Copy(rName, 1, Length(rName));
  109.             end { else if }
  110.             else begin
  111.                 LEVLName := Copy(rName, 1, 15);
  112.             end; { else }
  113.         end; { LEVLName }
  114.  
  115.         { Returns a configuration from the given grid as it appears in the resource. }
  116.         {   Need to be defensive, but fortunately this is fairly easy here. }
  117.         function ConfigFromGrid (aConfigGrid: GridType): ConfigType;
  118.  
  119.             var
  120.                 theConfig: ConfigType;
  121.  
  122.                 theRowCount: RowRange;
  123.                 theColCount: ColRange;
  124.  
  125.                 theGroup: array[ColRange] of Boolean;
  126.  
  127.         begin { ConfigFromGrid }
  128.             for theRowCount := 1 to kMaxGridDown do begin
  129.  
  130.                 { Unfortunately there is no type defined for 4 bytes (who needs it :) }
  131.                 { so we have to deal with the columns as byte groups. }
  132.  
  133.                 if aConfigGrid[theRowCount] >= 0 then begin
  134.                     theGroup[4] := aConfigGrid[theRowCount] mod $0010 <> 0;
  135.                     theGroup[3] := aConfigGrid[theRowCount] mod $0100 div $0010 <> 0;
  136.                     theGroup[2] := aConfigGrid[theRowCount] mod $1000 div $0100 <> 0;
  137.                     theGroup[1] := aConfigGrid[theRowCount] div $1000 <> 0;
  138.                 end { if }
  139.                 else begin
  140.                     { Effect of adding 65536 is to bring it back into range 0..65535 }
  141.                     { The result is of LongInt, because 65535 is of type LongInt. }
  142.  
  143.                     theGroup[4] := (aConfigGrid[theRowCount] + 65536) mod $0010 <> 0;
  144.                     theGroup[3] := (aConfigGrid[theRowCount] + 65536) mod $0100 div $0010 <> 0;
  145.                     theGroup[2] := (aConfigGrid[theRowCount] + 65536) mod $1000 div $0100 <> 0;
  146.                     theGroup[1] := (aConfigGrid[theRowCount] + 65536) div $1000 <> 0;
  147.                 end; { else }
  148.  
  149.                 for theColCount := 1 to kMaxGridAcross do begin
  150.                     theConfig[TileRange((theRowCount - 1) * kMaxGridAcross + theColCount)] := theGroup[theColCount];
  151.                 end; { for }
  152.             end; { for }
  153.  
  154.             ConfigFromGrid := theConfig;
  155.         end; { ConfigFromGrid }
  156.  
  157.         { Returns the tile rule for aTileNum is specified from aRuleGrid. Remember }
  158.         { that levels can be edited by other people, so we need to be extremely }
  159.         { defensive (as always). Hence the algorithm used here is much slower than }
  160.         { would be possible if everything was assumed to be fine. }
  161.         function RuleFromGrid (aTileNum: TileRange;
  162.                                         aRuleGrid: GridType): TileRuleType;
  163.  
  164.             var
  165.                 theRule: TileRuleType;
  166.  
  167.                 theDepCount: Integer;
  168.                 theRowCount: RowRange;
  169.                 theColCount: ColRange;
  170.  
  171.                 theGroup: array[ColRange] of 0..kMaxTiles;
  172.  
  173.                 newDepFound: Boolean;
  174.  
  175.         begin { RuleFromGrid }
  176.             with theRule do begin
  177.  
  178.                 { Iterating over theDepCount, we try and find a dependant numbered theDepCount. }
  179.                 { We terminate if we cannot find it . This guarantees that we have a valid list }
  180.                 { of dependants from 1..theDepCount . }
  181.  
  182.                 { We handle the case for the first dependant separately, enforcing the requirement }
  183.                 { that the first dependant of a tile be itself. }
  184.  
  185.                 theNumDep := 1;
  186.                 theDep[1] := aTileNum;
  187.  
  188.                 { Now look for other dependants. }
  189.                 { Note that the n-th dependant is actually numbered n-1 in the resource. }
  190.                 { This way we can have up to and including 15 dependants other than }
  191.                 { itself, and hence every tile can be a dependant of a given tile. }
  192.  
  193.                 theDepCount := 0;
  194.  
  195.                 repeat
  196.  
  197.                     newDepFound := FALSE;
  198.                     theDepCount := theDepCount + 1;
  199.                     { so from now on, theDepCount can be safely cast into TileRange. }
  200.  
  201.                     for theRowCount := 1 to kMaxGridDown do begin
  202.  
  203.                         { Unfortunately there is no type defined for 4 bytes (who needs it :) }
  204.                         { so we have to deal with the columns as byte groups. }
  205.  
  206.                         if aRuleGrid[theRowCount] >= 0 then begin
  207.                             theGroup[4] := aRuleGrid[theRowCount] mod $0010;
  208.                             theGroup[3] := aRuleGrid[theRowCount] mod $0100 div $0010;
  209.                             theGroup[2] := aRuleGrid[theRowCount] mod $1000 div $0100;
  210.                             theGroup[1] := aRuleGrid[theRowCount] div $1000;
  211.                         end { if }
  212.                         else begin
  213.                             { Effect of adding 65536 is to bring it back into range 0..65535 }
  214.                             { The result is of LongInt, because 65535 is of type LongInt. }
  215.  
  216.                             theGroup[4] := (aRuleGrid[theRowCount] + 65536) mod $0010;
  217.                             theGroup[3] := (aRuleGrid[theRowCount] + 65536) mod $0100 div $0010;
  218.                             theGroup[2] := (aRuleGrid[theRowCount] + 65536) mod $1000 div $0100;
  219.                             theGroup[1] := (aRuleGrid[theRowCount] + 65536) div $1000;
  220.                         end; { else }
  221.  
  222.                         for theColCount := 1 to kMaxGridAcross do begin
  223.                             if theGroup[theColCount] = TileRange(theDepCount) then begin
  224.  
  225.                                 { Set the number of dependants and the position. }
  226.  
  227.                                 theNumDep := TileRange(theDepCount + 1);    { n-th dependant is numbered n-1 in resource. }
  228.                                 theDep[theNumDep] := TileRange((theRowCount - 1) * kMaxGridAcross + theColCount);
  229.                                 newDepFound := TRUE;
  230.                                 LEAVE;
  231.                             end { if }
  232.                         end; { for }
  233.  
  234.                         if newDepFound then begin
  235.                             LEAVE;
  236.                         end; { if }
  237.  
  238.                     end; { for }
  239.  
  240.                 until not newDepFound or (theDepCount = kMaxTiles - 1);
  241.  
  242.             end; { with }
  243.  
  244.             RuleFromGrid := theRule;
  245.         end; { RuleFromGrid }
  246.  
  247.     begin { SetLEVL }
  248.         { The following check could also probably be done }
  249.         { by the exception handler, except that they are }
  250.         { straightforward, and recoverable at this level. }
  251.  
  252.         { If anything really goes wrong, it will be caught first }
  253.         { by the exception handler at the document or application }
  254.         { reader level, then either in the main event handler }
  255.         { or the pre-loading handler. }
  256.  
  257.         theLEVL := LEVLtemplateH(Get1Resource(kLEVLResType, LEVLid));
  258.  
  259.         if theLEVL = nil then begin
  260.             itsName := DefaultName(LEVLid);
  261.  
  262.             itsStart := DefaultStart;
  263.  
  264.             for theRuleCount := 1 to kMaxTiles do begin
  265.                 itsRules[theRuleCount] := DefaultRule(theRuleCount);
  266.             end; { for }
  267.         end { if }
  268.         else begin
  269.  
  270.             itsName := LEVLName(theLEVL);
  271.  
  272.             itsStart := ConfigFromGrid(theLEVL^^.theStartConfig);
  273.  
  274.             for theRuleCount := 1 to kMaxTiles do begin
  275.                 itsRules[theRuleCount] := RuleFromGrid(theRuleCount, theLEVL^^.theFlipGrids[theRuleCount]);
  276.             end; { for }
  277.  
  278.             ForgetResource(theLEVL);
  279.  
  280.         end; { else }
  281.     end; { SetLEVL }
  282.  
  283.  
  284. {****************************************************}
  285. {}
  286. {        SetBEST                                                                                                                                                                                                                    }
  287. {}
  288. {        Set the best player details from a BEST resource.                                                                                        }
  289. {}
  290. {****************************************************}
  291.  
  292.     procedure CShLevel.SetBEST (BESTid: Integer);
  293.  
  294.         var
  295.             theBEST: BESTtemplateH; { Handle to best player resource. }
  296.  
  297.     begin { SetBEST }
  298.         theBEST := BESTtemplateH(Get1Resource(kBESTResType, BESTid));
  299.  
  300.         { The following check could also probably be done }
  301.         { by the exception handler, except that they are }
  302.         { straightforward, and recoverable at this level. }
  303.  
  304.         { If anything really goes wrong, it will be caught first }
  305.         { by the exception handler at the document or application }
  306.         { reader level, then either in the main event handler }
  307.         { or the pre-loading handler. }
  308.  
  309.         if theBEST = nil then begin
  310.             SetDefaultBestPlayer;
  311.         end { if }
  312.         else begin
  313.             SetPlayer(theBest^^.thePlayer);
  314.             SetMoves(theBest^^.theMoves);
  315.             SetTime(theBest^^.theTime);
  316.  
  317.             ForgetResource(theBEST);
  318.         end; { else }
  319.     end; { SetBEST }
  320.  
  321.  
  322. {****************************************************}
  323. {}
  324. {        SetDefaultBestPlayer                                                                                                                                                                            }
  325. {}
  326. {        Set the best player details to some safe, default values.                                                                    }
  327. {}
  328. {****************************************************}
  329.  
  330.     procedure CShLevel.SetDefaultBestPlayer;
  331.  
  332.     begin { SetDefaultBestPlayer }
  333.         { Don't want these to be editable, so put them here, not in a resource. }
  334.  
  335.         SetPlayer('Showwit!');
  336.         SetMoves(10000);
  337.         SetTime(36000);
  338.     end; { SetDefaultBestPlayer }
  339.  
  340.  
  341. {****************************************************}
  342. {}
  343. {        GetName                                                                                                                                                                                                                    }
  344. {}
  345. {        Returns the name of the level.                                                                                                                                                    }
  346. {}
  347. {****************************************************}
  348.  
  349.     function CShLevel.GetName: Str15;
  350.  
  351.     begin { GetName }
  352.         GetName := itsName;
  353.     end; { GetName }
  354.  
  355.  
  356. {****************************************************}
  357. {}
  358. {        GetStart                                                                                                                                                                                                                    }
  359. {}
  360. {        Returns the starting configuration of the level.                                                                                                }
  361. {}
  362. {****************************************************}
  363.  
  364.     function CShLevel.GetStart: ConfigType;
  365.  
  366.     begin { GetStart }
  367.         GetStart := itsStart;
  368.     end; { GetStart }
  369.  
  370.  
  371. {****************************************************}
  372. {}
  373. {        GetRules                                                                                                                                                                                                                    }
  374. {}
  375. {        Returns the rules for the level.                                                                                                                                                }
  376. {}
  377. {****************************************************}
  378.  
  379.     function CShLevel.GetRules: RulesType;
  380.  
  381.     begin { GetRules }
  382.         GetRules := itsRules;
  383.     end; { GetRules }
  384.  
  385.  
  386. {****************************************************}
  387. {}
  388. {        GetPlayer                                                                                                                                                                                                                }
  389. {}
  390. {        Returns the name of the current best player of the level.                                                                    }
  391. {}
  392. {****************************************************}
  393.  
  394.     function CShLevel.GetPlayer: Str15;
  395.  
  396.     begin { GetPlayer }
  397.         GetPlayer := itsPlayer;
  398.     end; { GetPlayer }
  399.  
  400.  
  401. {****************************************************}
  402. {}
  403. {        SetPlayer                                                                                                                                                                                                                }
  404. {}
  405. {        Sets the name of the current best player of the level.                                                                            }
  406. {}
  407. {****************************************************}
  408.  
  409.     procedure CShLevel.SetPlayer (aPlayer: Str15);
  410.  
  411.     begin { SetPlayer }
  412.         itsPlayer := aPlayer;
  413.     end; { SetPlayer }
  414.  
  415.  
  416. {****************************************************}
  417. {}
  418. {        GetMoves                                                                                                                                                                                                                }
  419. {}
  420. {        Returns the moves taken by the current best player of the level.                                            }
  421. {}
  422. {****************************************************}
  423.  
  424.     function CShLevel.GetMoves: Integer;
  425.  
  426.     begin { GetMoves }
  427.         GetMoves := itsMoves;
  428.     end; { GetMoves }
  429.  
  430.  
  431. {****************************************************}
  432. {}
  433. {        SetMoves                                                                                                                                                                                                                }
  434. {}
  435. {        Sets the moves taken by the current best player of the level.                                                        }
  436. {}
  437. {****************************************************}
  438.  
  439.     procedure CShLevel.SetMoves (aMoves: Integer);
  440.  
  441.     begin { SetMoves }
  442.         itsMoves := aMoves;
  443.     end; { SetMoves }
  444.  
  445.  
  446. {****************************************************}
  447. {}
  448. {        GetTime                                                                                                                                                                                                                    }
  449. {}
  450. {        Returns the time taken by the current best player of the level.                                                    }
  451. {}
  452. {****************************************************}
  453.  
  454.     function CShLevel.GetTime: LongInt;
  455.  
  456.     begin { GetTime }
  457.         GetTime := itsTime;
  458.     end; { GetTime }
  459.  
  460.  
  461. {****************************************************}
  462. {}
  463. {        SetTime                                                                                                                                                                                                                    }
  464. {}
  465. {        Sets the time taken by the current best player of the level.                                                            }
  466. {}
  467. {****************************************************}
  468.  
  469.     procedure CShLevel.SetTime (aTime: LongInt);
  470.  
  471.     begin { SetTime }
  472.         itsTime := aTime;
  473.     end; { SetTime }
  474.  
  475.  
  476. end. { CShLevel }