Advertisement
mixster

mixster

Jun 16th, 2009
202
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 38.55 KB | None | 0 0
  1. program ScaRPG_Map_Editor;
  2. {
  3.     ScaRPG Map Editor
  4.     A tool that allows anyone to create an intricate map
  5.     Author for used procedures and functions is 'mixster' unless otherwise stated
  6.     Extremely heavy commenting required. If distributed without, kill whoever did it
  7.     Designed primarily for adaptation. If you don't like it, change it - that's why heavy commenting required
  8. }
  9. type
  10.   TSheet = record // Record of information on a sheet e.g. tilesheet; spritesheet.
  11.     b: Integer; // Bitmap holder for the sheet
  12.     h: Integer; // Height in tiles of sheet
  13.     w: Integer; // Width in tiles of sheet
  14.     c: TCanvas; // Holds the canvas for the bitmap 'b'
  15.   end;
  16.  
  17.   TMap = record //Record of information for the entire map
  18.     layers: array of T2DPointArray; // 3D integer array with the information for drawing the tiles. The TPoint holds the actual top left corner on the tilesheet
  19.     attribs: T2DIntArray; // layer that holds attributes for a tile
  20.     width, height, depth, sprite: Integer; // Width, height and depth for dimensions; sprite is layer where sprites are drawn on top of
  21.     vis: TIntegerArray; // Holds bitmap for visible layers
  22.     mC: TPoint; // Holds the top left position so we know which bits to draw
  23.     saved: Boolean; // Holds whether or not the map is currently saved
  24.     fp: string; // Holds filepath of where it is currently saved
  25.     fn: string; // Holds filename of map
  26.   end;
  27.  
  28. var
  29.   maps: array of TMap; // Holds the currently open maps
  30.   curMap: Integer; // Holds the index of currently visible map
  31.   curLay: Integer; // Holds the layer that everything is drawn onto
  32.   bitDeb: string; // Holds the string that has the info about all the bitmaps currently in use
  33.   bitLoc: TStringArray; // Holds the location from where the relating bitmap was created
  34.   drawSize: TPoint; // Holds the number of tiles to draw in regards to .x = width .y = height
  35.   shTile: TSheet; // See TSheet. shTile for tilesheet
  36.   drawTiles: T2DPointArray; // Holds the tiles in a box shape of which to draw
  37.   drawArea: TPoint; // Holds the position where the mouse was pressed down on the map
  38.   drawMode: Integer; // Holds which method of drawing should be used
  39.  
  40.   fMain: TForm; // Main form for editing or creating a map
  41.   iMain: TImage; // Main visible component for displaying the map
  42.   mMain: TMainMenu; // Main menu holder thingy
  43.   mFile: TMenuItem; // Menu that holds file relating stuff
  44.   mFileOpts: array of TMenuItem; // Run of the mill menu options stored in an array
  45.   menuNames: TStringArray; // Holds the names for the options in the mFileOpts array
  46.   pSheet: TPanel; // Holds all the tilesheet relating stuff
  47.   iSheet: TImage; // Visible component for displaying the tilesheet
  48.   pTile: TPanel; // Panel to hold the currently selected tile(s) and similar stuff
  49.   iTile: TImage; // Visible component for displaying currently selected tile
  50.   bTools: array of TButton; // Buttons that switch to different map tools
  51.   toolHints: TStringArray; // Holds the hints for the buttons
  52.   tcMain: TTabControl; // Main tab bit for holding the maps
  53.   sbHorz, sbVert: TScrollBar; // Main scrollbars for scrolling map movement
  54.   sbSheet: TScrollBox; // Scrollbox that the tilesheet goes into
  55.   bLayUp, bLayDo: TButton; // Change the layer that is currently being overwritten
  56.   lCurLay: TLabel; // Holds the visual display of currently select layer
  57.  
  58. procedure Crash(str: string); // Simple procedure to allow the script to crash easily from a single line due to laziness
  59. begin
  60.   Writeln('Crashing: ' + str); // Print the crashing reason
  61.   TerminateScript; // Stop the script running
  62. end;
  63.  
  64. function MBitmap(w, h: Integer; str, from: string): Integer; // Creation half of the memory leak debugging
  65. begin
  66.   Result := BitmapFromString(w, h, str); // Start by actually making the bitmap since we need the reference number
  67.   while (Length(bitDeb) < Result + 1) do // While the string is too short
  68.     bitDeb := bitDeb + '2'; // Increase the length of the string by adding a 2 which signifies bitmap created by alternate means
  69.   bitDeb[Result + 1] := '1'; // Set the index to 1 to signify in use - string's start at 1 not 0, hence the + 1
  70.   SetLength(bitLoc, Length(bitDeb) + 1); // This is 1 longer than the string due to it starting on 0 and me wanting them in line
  71.   bitLoc[Result + 1] := from; // Set where the bitmap was created from
  72. end;
  73.  
  74.  
  75. procedure MFreeBitmap(b: Integer); // Destroying half of the memory leak debugging
  76. begin
  77.   FreeBitmap(b); // Start by freeing it as the reference remains afterwards
  78.   b := b + 1 // Increment it to line it up with the arrays
  79.   if (b > Length(bitDeb)) then // If the debug string is too short
  80.     exit; // Then we don't need to change anything (created by LoadBitmap or something similar) so exit procedure
  81.   bitDeb[b] := '0'; // Set to 0 to signify not in use
  82.   bitLoc[b] := ''; // Set to blank
  83. end;
  84.  
  85. procedure LoadSheet(var sheet: TSheet; filename: string); // Loads a sheet from a file
  86. var
  87.   s: TPoint;
  88. begin
  89.   sheet.b := LoadBitmap(filename); // Load the bitmap
  90.   GetBitmapSize(sheet.b, s.x, s.y); // Get actual dimensions
  91.   sheet.w := s.x div 32; // Convert to tile dimenions
  92.   sheet.h := s.y div 32; // As above
  93.   sheet.c := GetBitmapCanvas(sheet.b); // Get the canvas for the bitmap
  94. end;
  95.  
  96. procedure ConvertTile(var p: TPoint; i: Integer); // Changes integer based reference to an actual position
  97. begin
  98.   p.x := (i mod shTile.w) * 32; // mod by width to get the .x then * 32 to get actual location
  99.   p.y := (i div shTile.w) * 32; // div by width to get the .y then same as above
  100. end;
  101.  
  102. function ConvertBack(p: TPoint): Integer; // Change actual location back to integer reference
  103. begin
  104.   Result := ((p.y div 32) * shTile.w) + (p.x div 32); // div both by 32 to get tile reference then .y * width and add on .x
  105. end;
  106.  
  107. procedure FreeVisibleMap(tempMap: TMap); // Frees all the drawing bitmaps
  108. var
  109.   z: Integer;
  110. begin
  111.   for z := 0 to tempMap.depth - 1 do // Loop through all the layers
  112.     MFreeBitmap(tempMap.vis[z]); // and free the bitmap used for drawing
  113. end;
  114.  
  115. procedure CreateVisibleMap(var tempMap: TMap);
  116. var
  117.   z: Integer;
  118. begin
  119.   SetLength(tempMap.vis, tempMap.depth);
  120.   for z := 0 to tempMap.depth - 1 do
  121.     tempMap.vis[z] := MBitmap(drawSize.x * 32, drawSize.y * 32, '', 'CreateVisibleMap');
  122. end;
  123.  
  124. procedure GenerateBlankMap(var map: TMap; w, h, d: Integer);
  125. var
  126.   z, y, x: Integer;
  127. begin
  128.   map.depth := d;
  129.   map.height := h;
  130.   map.width := w;
  131.   map.sprite := Round(h / 1.5);
  132.   map.mC := Point(0, 0);
  133.   map.fp := ScriptPath;
  134.   map.saved := true;
  135.  
  136.   SetLength(map.layers, d);
  137.   SetLength(map.vis, d);
  138.  
  139.   for z := 0 to d - 1 do
  140.   begin
  141.     SetLength(map.layers[z], h);
  142.     if (z = 0) then
  143.       SetLength(map.attribs, h);
  144.     for y := 0 to h - 1 do
  145.     begin
  146.       SetLength(map.layers[z][y], w);
  147.       if (z = 0) then
  148.         SetLength(map.attribs[y], w);
  149.       for x := 0 to w - 1 do
  150.       begin
  151.         map.layers[z][y][x] := Point(-32, 0);
  152.         if (z = 0) then
  153.           map.attribs[y][x] := 0;
  154.       end;
  155.     end;
  156.   end;
  157.   CreateVisibleMap(map);
  158. end;
  159.  
  160. procedure PaintMap; // Paints the layers on to the form so we can see the map
  161. var
  162.   t, i: Integer;
  163. begin
  164.   t := MBitmap(480, 480, '', 'PaintMap'); // Create temp bitmap
  165.   FastDrawClear(t, 16448505); // Ensure temp bitmap is blank
  166.  
  167.   for i := 0 to maps[curMap].depth - 1 do // Loop through all layers
  168.   begin
  169.     SetTransparentColor(maps[curMap].vis[i], 16448505); // Set transparent colour so the layers work nicely
  170.     FastDrawTransparent(0, 0, maps[curMap].vis[i], t); // Draw sprite layer on with transparency so bottom layer is visible
  171.   end;
  172.  
  173.   SafeDrawBitmap(t, iMain.Canvas, 0, 0); // Draw the map onto the visual component
  174.   MFreeBitmap(t); // Free our temp bitmap
  175. end;
  176.  
  177. procedure RedrawMap(tempMap: TMap); // Draw the map entirely from scratch - can be very confusing to understand, but straight forward enough
  178. var
  179.   z, y, x, t, d: Integer;
  180.   p: TPoint;
  181.   ts, ds: TCanvas;
  182. begin
  183.   t := MBitmap(drawSize.x * 32, drawSize.y * 32, '', 'RedrawMap'); // Create temp bitmap
  184.  
  185.   ts := shTile.c; // Get the tilesheet's canvas
  186.   ds := GetBitmapCanvas(t); // Get the temp bitmap's canvas
  187.  
  188.   for z := 0 to tempMap.depth - 1 do // Loop through all the layers
  189.   begin
  190.     FastDrawClear(tempMap.vis[z], clBlack); // Ensure layer is clear
  191.     d := tempMap.vis[z]; // Set d to current layer
  192.     FastDrawClear(t, clBlack); // Clear the temp bitmap
  193.     p.y := -32; // Holds where to draw on the visible map - reset it here
  194.     for y := tempMap.mC.y to tempMap.mC.y + drawSize.y do // Loop through all on screen vertical tiles
  195.     begin
  196.       p.y := p.y + 32; // Increment the position by the height of a tile (32)
  197.       if (y < 0) then // If y is off the top of the map
  198.         continue // Go back to the beginning of the loop
  199.       else if (y >= tempMap.height) then // If y is off the bottom of the map
  200.         break; // It won't go back on, so break the loop
  201.  
  202.       p.x := -32; // Holds where to draw on the visible map - reset it here
  203.       for x := tempMap.mC.x to tempMap.mC.x + drawSize.x do // Loop through all on screen horizontal tiles
  204.       begin
  205.         p.x := p.x + 32; // Increment the position by the width of a tile
  206.         if (x < 0) then // If x is off the left of the map
  207.           continue // Go back to the beginning of the loop
  208.         else if (x >= tempMap.width) then // If x is off the right of the map
  209.           break; // It won't go back on, so break the loop
  210.         SafeCopyCanvas(ts, ds, tempMap.layers[z][y][x].x, tempMap.layers[z][y][x].y, tempMap.layers[z][y][x].x + 32, tempMap.layers[z][y][x].y + 32, p.x, p.y, p.x + 32, p.y + 32); // Using the 3D TPoint array, copy the tile onto the temp bitmap using TPoint p for where to draw
  211.       end;
  212.     end;
  213.     FastDrawTransparent(0, 0, t, d); // Draw the layer without transparency onto appropriate bitmap
  214.   end;
  215.  
  216.   MFreeBitmap(t); // Free our temp bitmap
  217. end;
  218.  
  219. procedure RepaintArea(ts, te, dp: TPoint);
  220. var
  221.   t, p, z, w, h: Integer;
  222.   tempMap: TMap;
  223. begin
  224.   tempMap := maps[curMap];
  225.   w := ((te.x + 1) - ts.x) * 32; // Get the width to draw by getting the difference in start and end then multiplying by tile width
  226.   h := ((te.y + 1) - ts.y) * 32; // As above, only height
  227.   t := MBitmap(w, h, '', 'RepaintArea');
  228.   p := MBitmap(w, h, '', 'RepaintArea');
  229.   FastDrawClear(p, clBlack);
  230.   for z := 0 to tempMap.depth - 1 do
  231.   begin
  232.     SafeCopyCanvas(GetBitmapCanvas(tempMap.vis[z]), GetBitmapCanvas(t), dp.x, dp.y, dp.x + w, dp.y + h, 0, 0, w, h);
  233.     SetTransparentColor(t, 16448505); // Set transparent colour so the layers work nicely
  234.     FastDrawTransparent(0, 0, t, p);
  235.     FastDrawClear(t, 16448505);
  236.   end;
  237.  
  238.   MFreeBitmap(t);
  239.   SafeDrawBitmap(p, iMain.Canvas, dp.x, dp.y); // Draw the map onto the visual component
  240.   MFreeBitmap(p);
  241. end;
  242.  
  243. procedure RedrawArea(ts, te, dp: TPoint); // A procedure similar to RedrawMap, but with alterations so it only redraws the set area and then draws it where told
  244. var
  245.   t, d, z, y, x, w, h: Integer;
  246.   tc, tsc: TCanvas;
  247.   p: TPoint;
  248.   tempMap: TMap;
  249. begin
  250.   tempMap := maps[curMap];
  251.   w := (te.x - ts.x) * 32; // Get the width to draw by getting the difference in start and end then multiplying by tile width
  252.   h := (te.y - ts.y) * 32; // As above, only height
  253.   t := MBitmap(w + 32, h + 32, '', 'RedrawArea'); // Setup the bitmap used to draw the new stuff
  254.   tsc := shTile.c; // Get the tilesheet's canvas
  255.   tc := GetBitmapCanvas(t); // Get the temp bitmap's canvas
  256.  
  257.   for z := 0 to tempMap.depth - 1 do // Loop through all layers
  258.   begin
  259.     d := tempMap.vis[z];
  260.     FastDrawClear(t, clBlack); // Clear temp bitmap
  261.     p.y := -32; // Reset p.y
  262.     for y := ts.y to te.y do
  263.     begin
  264.       p.y := p.y + 32; // Increment position to draw to
  265.       p.x := -32;
  266.       if (y < 0) then // If y is not valid due to being too far up
  267.         Continue // Skip to beginning of loop
  268.       else if (y >= tempMap.width) then // If y is not valid due to being too far down
  269.         break; // Break the loop as there's no hope of it returning
  270.  
  271.       for x := ts.x to te.x do // Loop through all columns
  272.       begin
  273.         p.x := p.x + 32; // Increment position to draw to
  274.         if (x < 0) then // If x is not valid due to being too far left
  275.           Continue // Skip to beginning of loop
  276.         else if (x >= tempMap.width) then // If x is not valid due to being too far right
  277.           break; // Break the loop as there's no hope of it returning
  278.  
  279.         SafeCopyCanvas(tsc, tc, tempMap.layers[z][y][x].x, tempMap.layers[z][y][x].y, tempMap.layers[z][y][x].x + 32, tempMap.layers[z][y][x].y + 32, p.x, p.y, p.x + 32, p.y + 32); // Using the 3D TPoint array, copy the tile onto the temp bitmap using TPoint p for where to draw
  280.       end;
  281.     end;
  282.  
  283.     FastDrawTransparent(dp.x, dp.y, t, d); // Draw the layer onto appropriate bitmap without transparency for this bit
  284.   end;
  285.  
  286.   MFreeBitmap(t); // Free our temp bitmap
  287.   RepaintArea(ts, te, dp);
  288. end;
  289.  
  290. procedure HandleMovement(amount: Integer; dir: Integer); // Wrapper procedure for RedrawArea
  291. var
  292.   t, z: Integer;
  293.   tc: TCanvas;
  294.   s, e, o, d: TPoint;
  295. begin
  296.   if (amount < 0) then
  297.     amount := - amount;
  298.   if (not (InRange(dir, 1, 4))) then
  299.   begin
  300.     Writeln('Invalid dir passed to HandleMovement');
  301.     exit;
  302.   end;
  303.  
  304.   t := MBitmap((drawSize.x + 1) * 32, (drawSize.y + 1) * 32, '', 'HandleMovement');
  305.   tc := GetBitmapCanvas(t);
  306.   SafeCopyCanvas(iMain.Canvas, tc, 0, 0, iMain.Width, iMain.Height, 0, 0, iMain.Width, iMain.Height);
  307.   s := maps[curMap].mC;
  308.   e := Point(s.x + drawSize.x, s.y + drawSize.y);
  309.   o := Point(0, 0);
  310.   d := Point(0, 0);
  311.   case dir of
  312.     1: begin
  313.       e.y := s.y + amount;
  314.       o.y := amount * 32;
  315.     end;
  316.     2: begin
  317.       e.x := s.x + amount;
  318.       o.x := amount * 32;
  319.     end;
  320.     3: begin
  321.       s.y := e.y - amount;
  322.       o.y := - (amount * 32);
  323.       d.y := (drawSize.y - amount) * 32;
  324.     end;
  325.     4: begin
  326.       s.x := e.x - amount;
  327.       o.x := - (amount * 32);
  328.       d.x := (drawSize.x - amount) * 32;
  329.     end;
  330.   end;
  331.  
  332.   SafeDrawBitmap(t, iMain.Canvas, o.x, o.y);
  333.   FastDrawClear(t, clBlack);
  334.  
  335.   for z := 0 to maps[curMap].depth - 1 do
  336.   begin
  337.     SafeDrawBitmap(maps[curMap].vis[z], tc, 0, 0);
  338.     SafeDrawBitmap(t, GetBitmapCanvas(maps[curMap].vis[z]), o.x, o.y);
  339.   end;
  340.  
  341.   MFreeBitmap(t);
  342.  
  343.   RedrawArea(s, e, d);
  344. end;
  345.  
  346. procedure AddMap(w, h, d: Integer); // Handles the setting up of a new map
  347. var
  348.   l: Integer;
  349. begin
  350.   l := Length(maps); // Get the length of the array
  351.   SetLength(maps, l + 1); // Increase the length of the array by 1 for the new map
  352.   GenerateBlankMap(maps[l], w, h, d); // See 'GenerateBlankMap'
  353.   tcMain.Tabs.Append('Untitled'); // Add a new tab to access it
  354.   tcMain.TabIndex := tcMain.Tabs.Count - 1; // Switch to the new tab
  355.   curMap := l; // Update curMap as well so that drawing isn't done to random maps
  356.   maps[curMap].fp := ScriptPath;
  357.   maps[curMap].fn := 'Untitled';
  358.   curLay := d - 1; // Set the drawing layer to the top layer by default
  359.   lCurLay.Caption := 'Layer ' + IntToStr(curLay) + ' selected'; // Update the layer caption so we know where we are at
  360. end;
  361.  
  362. procedure NewMap;
  363. begin
  364.   AddMap(25, 25, 3);
  365.   RedrawMap(maps[curMap]);
  366.   PaintMap;
  367. end;
  368.  
  369. procedure SetMapInfo(index: Integer; fpstr: string);
  370. begin
  371.   maps[index].saved := True; // Toggle saved to true to show that it has been saved and not modified
  372.   maps[index].fp := ExtractFilePath(fpstr); // Update the filepath to the map
  373.   maps[index].fn := ExtractFileName(fpstr); // Update the filename of the map
  374.   maps[index].fn := Copy(maps[index].fn, 1, LastPos('.', maps[curMap].fn) - 1); // And remove the file extension
  375.   tcMain.Tabs[index] := maps[index].fn; // Update the tab to show the filename minus extension
  376. end;
  377.  
  378. procedure MapImplode(var arr: TStringArray; var tempMap: TMap); // Breaks down the map into an array to be used for saving maps
  379. var
  380.   z, y, x, i: Integer;
  381. begin
  382.   SetLength(arr, 0); // Ensure array passed is empty
  383.   if ((tempMap.depth <= 0) or (tempMap.height <= 0) or (tempMap.width <= 0)) then // If map is blank/invalid size
  384.     Crash('Imploding map of invalid dimensions (one is set to zero)'); // Crash
  385.   i := 2 + (((tempMap.depth + 1) * (tempMap.height + 1)) - 1); // 2 is for the first line to hold dimension size then a blank line after. Layers held in "paragraphs", so for every layer, there should be height + 1 strings to allow for blank line underneath and then you take one away as bottom "paragraph" doesn't need blank line and 1 as added to depth for the attributes layer
  386.   SetLength(arr, i); // Set the length so it's the right length for the data
  387.   arr[0] := IntToStr(tempMap.width) + ',' + IntToStr(tempMap.height) + ',' + IntToStr(tempMap.depth); // Set first array index to hold dimenions info (x by y by z)
  388.   for x := 1 to i - 1 do // Loop through all arrays
  389.     arr[x] := ''; // Set to blank to ensure no corruption
  390.   i := 1; // Set i to 1 as 0 is used for dimensions, then 1 as a blank line - i is incremented once before being used for the first time
  391.   for z := 0 to tempMap.depth do // Loop through all layers and the attributes
  392.   begin
  393.     for y := 0 to tempMap.height - 1 do // Loop through all rows
  394.     begin
  395.       i := i + 1; // Increment i so it points to next blank array
  396.       for x := 0 to tempMap.width - 1 do // Loop through all columns
  397.         if (z < tempMap.depth) then // if it is a visual layer
  398.           arr[i] := arr[i] + IntToStr(ConvertBack(tempMap.layers[z][y][x])) + ',' // Append the converted tile and a comma to the end of the array
  399.         else // if it is the attirbutes layer
  400.           arr[i] := arr[i] + IntToStr(tempMap.attribs[y][x]) + ','; // Append the attribute and a comma to the end of the array
  401.       Delete(arr[i], Length(arr[i]), 1); // Remove the trailing comma
  402.     end;
  403.     i := i + 1; // Increment i to give the blank line between "paragraphs"
  404.   end;
  405. end;
  406.  
  407. procedure SaveMap(filename: string); // Outputs the map to a file
  408. var
  409.   f, i: Integer;
  410.   s: TStringArray;
  411. begin
  412.   f := RewriteFile(filename, False); // Open file and wipe it or create the file then assign to f
  413.   MapImplode(s, maps[curMap]); // See MapImplode
  414.   for i := 0 to High(s) do // Loop through s
  415.     WriteFileString(f, s[i] + #13 + #10); // Write to file with new line after
  416.   CloseFile(f); // Close the file
  417. end;
  418.  
  419. procedure ExportMap; // GUI method of saving a map by opening a TSaveDialog
  420. var
  421.   dialog: TSaveDialog;
  422. begin
  423.   dialog := TSaveDialog.Create(nil); // Create parentless save dialog
  424.   dialog.Filter := 'ScaRPG map|*.srpg'; // Set filter to only allow the the extension specified
  425.   dialog.InitialDir := maps[curMap].fp; // Set starting directory to same as where script is saved if not saved, else to same place if previously saved
  426.   if (not dialog.Execute) then // If no file is specified after opening the dialog and it is closed
  427.     exit; // exit procedure
  428.   SaveMap(dialog.filename); // See SaveMap - the chosen file is passed as where to save it to
  429.   SetMapInfo(curMap, dialog.filename);
  430. end;
  431.  
  432. procedure MExplode(var arr: TStringArray; str, del: string); // Standard Explode procedure written for older Scar versions
  433. var
  434.   i, h, l: Integer;
  435. begin
  436.   SetLength(arr, 0); // Ensure passed array is blank
  437.   h := -1; // Set high of array to -1
  438.   l := Length(del) - 1; // Amount to delete by based on del's length to ensure it is removed if longer than 1 char
  439.   while (true) do // Endless loop
  440.   begin
  441.     h := h + 1; // Increment h
  442.     SetLength(arr, h + 1); // Make array longer by one
  443.     i := Pos(del, str); // Find first occurence of del in str
  444.     if (i = 0) then // If it is not found
  445.       break; // Break from loop
  446.     arr[h] := Copy(str, 1, i - 1); // Copy the text until del (not including del) to the array
  447.     Delete(str, 1, i + l); // Remove copied text as well as del
  448.   end;
  449.   arr[h] := Copy(str, 1, Length(str)); // Copy remaining text into the array - del should not be on it, so no need to copy shorter than the length
  450. end;
  451.  
  452. function StrInt(s: string): Integer; // "Safe" version of IntToStr to catch dodgy map files specifically
  453. begin
  454.   try
  455.     Result := StrToInt(s); // Try standard conversion
  456.   except // If it is non-numeric
  457.     if (s = '') then // If it is blank
  458.       Result := 0 // Set to 0
  459.     else // If non-numeric and not blank
  460.       Crash('StrInt passed invalid string - "' + s + '"'); // Crash
  461.   end;
  462. end;
  463.  
  464. procedure MapExplode(var tempMap: TMap; str: string); // Creates the backend for the visual map from a string
  465. var
  466.   lineArr: TStringArray;
  467.   mapArr: array of TStringArray;
  468.   i, z, y, x: Integer;
  469. begin
  470.   if (Pos(#13 + #10, str) = 0) then // If no enter's are found in the string
  471.     Crash('Exploding map from an invalid input string'); // Crash
  472.  
  473.   MExplode(lineArr, str, #13 + #10); // See MExplode - breaks into seperate lines
  474.   SetLength(mapArr, Length(lineArr)); // Set 2D array to the same length as the number of lines
  475.   for i := 0 to High(lineArr) do // Loop through all the lines
  476.     MExplode(mapArr[i], lineArr[i], ','); //See MExplode - breaks into seperate values between the comma's
  477.    
  478.   tempMap.width := StrInt(mapArr[0][0]); // Set the dimension of the map based on the extracted values
  479.   tempMap.height := StrInt(mapArr[0][1]); // As above
  480.   tempMap.depth := StrInt(mapArr[0][2]); // As above
  481.  
  482.   i := 2; // Set i to 2 - the first array relating to the map
  483.  
  484.   // This section is like the inverse of the main loop in MapImplode
  485.   SetLength(tempMap.layers, tempMap.depth); // Set the 3D TPoint array to length of the depth
  486.   for z := 0 to tempMap.depth - 1 do // Loop through all layers and the attribute layer
  487.   begin
  488.     SetLength(tempMap.layers[z], tempMap.height); // Set a 2D TPoint array to length of the height
  489.     for y := 0 to tempMap.height - 1 do // Loop through all rows
  490.     begin
  491.       SetLength(tempMap.layers[z][y], tempMap.width); // Set the TPoint array to the length of the width
  492.       for x := 0 to tempMap.width - 1 do // Loop through all columns
  493.         ConvertTile(tempMap.layers[z][y][x], StrInt(mapArr[i][x])); // See ConvertTile - this is done so that map painting requires less calculations
  494.       i := i + 1; // Go onto the next line of the loaded "paragraph"
  495.     end;
  496.     i := i + 1; // Would be a blank line here, so go on to the next
  497.   end;
  498.  
  499.   SetLength(tempMap.attribs, tempMap.height); // Set the height of the 2DIntArray
  500.   for y := 0 to tempMap.height - 1 do // Loop through all rows
  501.   begin
  502.     SetLength(tempMap.attribs[y], tempMap.width); // Set the width of the TIntegerArray
  503.     for x := 0 to tempMap.width - 1 do // Loop through all columns
  504.       tempMap.attribs[y][x] := StrInt(mapArr[i][x]); // Convert the string into an integer attribute value
  505.     i := i + 1;
  506.   end;
  507. end;
  508.  
  509. procedure LoadMap(filename: string); // Handles the loading of a map file and doing what needs to be done
  510. var
  511.   f: Integer;
  512.   s: string;
  513. begin
  514.   if (not FileExists(filename)) then // If file does not exist
  515.     Crash('File specified to load does not exist - "' + filename + '"'); // Crash
  516.   f := OpenFile(filename, False); // Open the file specified
  517.   ReadFileString(f, s, FileSize(f)); // Read the contents of the file
  518.   CloseFile(f); // Close the file
  519.   MapExplode(maps[curMap], s); // See MapExplode - pass the file contents to break apart
  520. end;
  521.  
  522. procedure ImportMap; // GUI method of opening a map by opening a TOpemDialog
  523. var
  524.   dialog: TOpenDialog;
  525. begin
  526.   dialog := TOpenDialog.Create(nil); // Create a parentless open dialog
  527.   dialog.Filter := 'ScaRPG map|*.srpg'; // Set the filter to only show map files
  528.   if (ScriptPath <> '') then // If the script is saved
  529.     dialog.InitialDir := ScriptPath; // Set the starting directory to the place where the script is saved in
  530.   if (not dialog.Execute) then // If the dialog is launched and no file is selected when closed
  531.     exit; // exit procedure
  532.   if (not maps[curMap].saved) then // If map isn't saved
  533.     AddMap(1, 1, 1); // Then open a new tab instead
  534.   FreeVisibleMap(maps[curMap]); // Need to "refresh" the visible bitmap holders
  535.   LoadMap(dialog.filename); // See LoadMap - passing the selected file as the one to load
  536.   CreateVisibleMap(maps[curMap]); // Set up the visible layers
  537.   SetMapInfo(curMap, dialog.filename);
  538.   RedrawMap(maps[curMap]); // Redraw the map as it is unconstructed
  539.   PaintMap; // Then paint it onto the form
  540. end;
  541.  
  542. procedure CloseMap(var index: Integer);
  543. var
  544.   i: Integer;
  545. begin
  546.   FreeVisibleMap(maps[index]);
  547.   if (index < High(maps)) then
  548.   begin
  549.     for i := index to High(maps) - 1 do
  550.       Swap(maps[i], maps[i + 1]);
  551.   end
  552.   else if (index = 0) then
  553.   begin
  554.     AddMap(25, 25, 3);
  555.     curMap := 0;
  556.     Swap(maps[0], maps[1]);
  557.     RedrawMap(maps[0]);
  558.   end;
  559.   SetLength(maps, High(maps));
  560.   tcMain.Tabs.Delete(index);
  561.   if (index > High(maps)) then
  562.     index := index - 1;
  563.   PaintMap;
  564. end;
  565.  
  566. procedure PaintDrawTiles;
  567. var
  568.   w, h, x, y: Integer;
  569.   r: Extended;
  570. begin
  571.   h := High(drawTiles);
  572.   if (h >= 0) then
  573.     w := High(drawTiles[0])
  574.   else
  575.     w := -1;
  576.   if (w = -1) then
  577.   begin
  578.     h := BitmapFromString(64, 64, '');
  579.     FastDrawClear(h, clBlack);
  580.     SafeDrawBitmap(h, iTile.Canvas, 0, 0);
  581.     iTile.Canvas.TextOut(16, 8, 'None');
  582.   end
  583.   else
  584.   begin
  585.     r := 64.0 / (Max(w, h) + 1);
  586.     for y := 0 to h do
  587.       for x := 0 to w do
  588.         SafeCopyCanvas(shTile.c, iTile.Canvas, drawTiles[y][x].x, drawTiles[y][x].y, drawTiles[y][x].x + 32, drawTiles[y][x].y + 32, Round(x * r), Round(y * r), Round((x + 1) * r), Round((y + 1) * r));
  589.   end;
  590. end;
  591.  
  592. procedure OnMapMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  593. begin
  594.   if (not ((drawMode = 0) or (drawMode = 2) or (drawMode = 3))) then
  595.     exit;
  596.   X := Trunc(X / 32.0);
  597.   Y := Trunc(Y / 32.0);
  598.   drawArea := Point(X, Y);
  599. end;
  600.  
  601. procedure OnMapMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  602. var
  603.   d, t, r: TPoint;
  604.   a, b, w, h: Integer;
  605.   s: Boolean;
  606.   sT: T2DPointArray;
  607. begin
  608.   if (not ((drawMode = 0) or (InRange(drawMode, 2, 4)))) then
  609.     exit;
  610.   X := Trunc(X / 32.0);
  611.   Y := Trunc(Y / 32.0);
  612.   if (X >= maps[curMap].width) then
  613.     X := maps[curMap].width - 1
  614.   else if (X < 0) then
  615.     X := 0;
  616.   if (Y >= maps[curMap].height) then
  617.     Y := maps[curMap].height - 1
  618.   else if (Y < 0) then
  619.     Y := 0;
  620.   d := Point(X, Y);
  621.   if (d.x < drawArea.x) then
  622.     Swap(d.x, drawArea.x);
  623.   if (d.y < drawArea.y) then
  624.     Swap(d.y, drawArea.y);
  625.   X := maps[curMap].mC.x + drawArea.x;
  626.   Y := maps[curMap].mC.y + drawArea.y;
  627.   t := Point(d.x - drawArea.x, d.y - drawArea.y);
  628.   s := False;
  629.   if (drawMode = 0) then
  630.   begin
  631.     SetLength(drawTiles, t.y + 1);
  632.     for a := 0 to t.y do
  633.       SetLength(drawTiles[a], t.x + 1);
  634.   end
  635.   else if (drawMode = 3) then
  636.   begin
  637.     h := Length(drawTiles);
  638.     if (h <> 0) then
  639.       w := Length(drawTiles[0])
  640.     else
  641.       w := 0;
  642.     if ((h < 3) or (w < 3) or (t.y < 3) or (t.x < 3)) then
  643.     begin
  644.       s := True;
  645.       drawMode := 2;
  646.     end
  647.     else
  648.     begin
  649.       h := h - 1;
  650.       w := w - 1;
  651.       SetLength(sT, h - 1);
  652.       for a := 0 to h - 2 do
  653.       begin
  654.         SetLength(sT[a], w - 1);
  655.         for b := 0 to w - 2 do
  656.           sT[a][b] := drawTiles[(a mod (h - 1)) + 1][(b mod (w - 1)) + 1];
  657.       end;
  658.       maps[curMap].layers[curLay][Y][X] := drawTiles[0][0];
  659.       maps[curMap].layers[curLay][Y + t.y][X] := drawTiles[h][0];
  660.       maps[curMap].layers[curLay][Y][X + t.x] := drawTiles[0][w];
  661.       maps[curMap].layers[curLay][Y + t.y][X + t.x] := drawTiles[h][w];
  662.       for a := 1 to t.y - 1 do
  663.       begin
  664.         maps[curMap].layers[curLay][Y + a][X] := drawTiles[((a - 1) mod (h - 1)) + 1][0];
  665.         maps[curMap].layers[curLay][Y + a][X + t.x] := drawTiles[((a - 1) mod (h - 1)) + 1][w];
  666.       end;
  667.       for b := 1 to t.x - 1 do
  668.       begin
  669.         maps[curMap].layers[curLay][Y][X + b] := drawTiles[0][((b - 1) mod (w - 1)) + 1];
  670.         maps[curMap].layers[curLay][Y + t.y][X + b] := drawTiles[h][((b - 1) mod (w - 1)) + 1];
  671.       end;
  672.     end;
  673.   end
  674.   else if (drawMode = 4) then
  675.   begin
  676.     t := Point(0, 0);
  677.     for a := 0 to maps[curMap].height - 1 do
  678.       for b := 0 to maps[curMap].width - 1 do
  679.         maps[curMap].layers[curLay][a][b] := drawTiles[a mod Length(drawTiles)][b mod Length(drawTiles[0])];
  680.  
  681.   end;
  682.   for a := 0 to t.y do
  683.     for b := 0 to t.x do
  684.       case drawMode of
  685.         0: drawTiles[a][b] := maps[curMap].layers[curLay][Y + a][X + b];
  686.         2: maps[curMap].layers[curLay][Y + a][X + b] := drawTiles[a mod Length(drawTiles)][b mod Length(drawTiles[0])];
  687.         3: if (not ((a = 0) or (b = 0) or (a = t.y) or (b = t.x))) then
  688.              maps[curMap].layers[curLay][Y + a][X + b] := sT[(a - 1) mod Length(sT)][(b - 1) mod Length(sT[0])];
  689.         4: break;
  690.       end;
  691.   if (drawMode = 0) then
  692.     PaintDrawTiles
  693.   else if (drawMode = 4) then
  694.   begin
  695.     RedrawMap(maps[curMap]);
  696.     PaintMap;
  697.   end
  698.   else
  699.   begin
  700.     if (s) then
  701.       drawMode := 3;
  702.     r := Point(drawArea.x * 32, drawArea.y * 32);
  703.     RedrawArea(Point(X, Y), Point(X + t.x, Y + t.y), r);
  704.   end;
  705. end;
  706.  
  707. procedure OnMapMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  708. var
  709.   dp: TPoint;
  710. begin
  711.   if (drawMode <> 1) then
  712.     exit;
  713.   if (not (ssLeft in Shift)) then
  714.     exit;
  715.   dp := Point(Trunc(X / 32.0), Trunc(Y / 32.0));
  716.   X := dp.x + maps[curMap].mC.x;
  717.   Y := dp.y + maps[curMap].mC.y;
  718.   dp := Point(dp.x * 32, dp.y * 32);
  719.   if (X >= maps[curMap].Width) then
  720.   begin
  721.     X := maps[curMap].Width - 1;
  722.     dp.x := iMain.Width - 32;
  723.   end
  724.   else if (X < 0) then
  725.   begin
  726.     X := 0;
  727.     dp.x := 0;
  728.   end;
  729.   if (Y >= maps[curMap].Height) then
  730.   begin
  731.     Y := maps[curMap].Height - 1;
  732.     dp.y := iMain.Height - 32;
  733.   end
  734.   else if (Y < 0) then
  735.   begin
  736.     Y := 0;
  737.     dp.y := 0;
  738.   end;
  739.  
  740.   if (High(drawTiles) <> -1) then
  741.     if (High(drawTiles[0]) <> -1) then
  742.      if ((maps[curMap].layers[curLay][Y][X].x = drawTiles[0][0].x) and (maps[curMap].layers[curLay][Y][X].y = drawTiles[0][0].y)) then
  743.        exit;
  744.   maps[curMap].layers[curLay][Y][X] := drawTiles[0][0];
  745.   RedrawArea(Point(X, Y), Point(X , Y), dp);
  746. end;
  747.  
  748. procedure OnToolClick(Sender: TObject);
  749. var
  750.   i, t: Integer;
  751. begin
  752.   t := -1;
  753.   for i := 0 to High(bTools) do
  754.     if (Sender = bTools[i]) then
  755.     begin
  756.       t := i;
  757.       break;
  758.     end;
  759.   if (t = -1) then
  760.     exit;
  761.   drawMode := t;
  762. end;
  763.  
  764. procedure OnMapScroll(Sender: TObject; ScrollCode: TScrollCode; var ScrollPos: Integer);
  765. var
  766.   dir, amo: Integer;
  767. begin
  768.   dir := 0;
  769.   if (Sender = sbHorz) then
  770.   begin
  771.     amo := maps[curMap].mC.x - sbHorz.Position;
  772.     maps[curMap].mC.x := sbHorz.Position;
  773.     if (amo < 0) then
  774.       dir := 4
  775.     else if (amo > 0) then
  776.       dir := 2;
  777.   end
  778.   else if (Sender = sbVert) then
  779.   begin
  780.     amo := maps[curMap].mC.y - sbVert.Position;
  781.     maps[curMap].mC.y := sbVert.Position;
  782.     if (amo < 0) then
  783.       dir := 3
  784.     else if (amo > 0) then
  785.       dir := 1;
  786.   end;
  787.   if (dir = 0) then
  788.     exit;
  789.   HandleMovement(amo, dir);
  790. end;
  791.  
  792. procedure OnTilesheetMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  793. begin
  794.   drawArea := Point(Trunc(X / 32.0), Trunc(Y / 32.0));
  795. end;
  796.  
  797. procedure OnTilesheetMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  798. var
  799.   w, h, a, b: Integer;
  800. begin
  801.   X := Trunc(X / 32.0);
  802.   Y := Trunc(Y / 32.0);
  803.   if (X >= shTile.w) then
  804.     X := shTile.w - 1
  805.   else if (X < 0) then
  806.     X := 0;
  807.   if (Y >= shTile.h) then
  808.     Y := shTile.h - 1
  809.   else if (Y < 0) then
  810.     Y := 0;
  811.   if (X < drawArea.x) then
  812.     Swap(X, drawArea.x);
  813.   if (Y < drawArea.y) then
  814.     Swap(Y, drawArea.y);
  815.  
  816.   h := Y - drawArea.y;
  817.   w := X - drawArea.x;
  818.   SetLength(drawTiles, h + 1);
  819.   for a := 0 to h do
  820.   begin
  821.     SetLength(drawTiles[a], w + 1);
  822.     for b := 0 to w do
  823.       drawTiles[a][b] := Point((drawArea.x + b) * 32, (drawArea.y + a) * 32);
  824.   end;
  825.  
  826.   PaintDrawTiles;
  827. end;
  828.  
  829. procedure OnButtonClick(Sender: TObject);
  830. begin
  831.   if (Sender = bLayUp) then
  832.   begin
  833.     curLay := curLay + 1;
  834.     if (curLay >= maps[curMap].depth) then
  835.       curLay := 0;
  836.   end
  837.   else
  838.   begin
  839.     curLay := curLay - 1;
  840.     if (curLay <= -1) then
  841.       curLay := maps[curMap].depth - 1;
  842.   end;
  843.   lCurLay.Caption := 'Layer ' + IntToStr(curLay) + ' selected'; // Update the layer caption so we know where we are drawing at
  844. end;
  845.  
  846. procedure OnMenuClick(Sender: TObject);
  847. var
  848.   i, opt: Integer;
  849. begin
  850.   opt := -1;
  851.   for i := 0 to High(mFileOpts) do
  852.     if (Sender = mFileOpts[i]) then
  853.     begin
  854.       opt := i;
  855.       break;
  856.     end;
  857.   if (opt = -1) then
  858.   begin
  859.     Writeln('I don''t know how you managed it, but you clicked on a non-existent menu item');
  860.     exit;
  861.   end;
  862.   case opt of
  863.     0: NewMap;
  864.     1: ImportMap;
  865.     2: ExportMap;
  866.     3: CloseMap(curMap);
  867.   end;
  868.  
  869.   sbHorz.Position := maps[curMap].mC.x;
  870.   sbVert.Position := maps[curMap].mC.y;
  871. end;
  872.  
  873. procedure OnTabChange(Sender: TObject);
  874. begin
  875.   curMap := tcMain.TabIndex;
  876.   sbHorz.Position := maps[curMap].mC.x;
  877.   sbVert.Position := maps[curMap].mC.y;
  878.   PaintMap;
  879. end;
  880.  
  881. procedure ApplyGrid(var img: TImage; col: Integer);
  882. var
  883.   x, y, xl, yl, tc: Integer;
  884. begin
  885.   xl := img.Width div 32;
  886.   yl := img.Height div 32;
  887.   tc := img.Canvas.Pen.Color;
  888.   img.Canvas.Pen.Color := col;
  889.   if (yl > 2) then
  890.     for y := 1 to yl - 1 do
  891.     begin
  892.       img.Canvas.MoveTo(0, y * 32);
  893.       img.Canvas.LineTo(img.Width, y * 32);
  894.     end;
  895.   if (xl > 2) then
  896.     for x := 1 to xl - 1 do
  897.     begin
  898.       img.Canvas.MoveTo(x * 32, 0);
  899.       img.Canvas.LineTo(x * 32, img.Height);
  900.     end;
  901.   img.Canvas.Pen.Color := tc;
  902. end;
  903.  
  904. // Standard form setup procedure - no comments
  905. procedure SetupForm;
  906. var
  907.   i: Integer;
  908. begin
  909.   fMain := CreateForm;
  910.  
  911.   mMain := TMainMenu.Create(fMain);
  912.   mFile := TMenuItem.Create(fMain);
  913.   mFIle.Caption := 'File';
  914.   menuNames := ['New', 'Open', 'Save', 'Close'];
  915.   SetLength(mFileOpts, Length(menuNames));
  916.  
  917.   for i := 0 to High(mFileOpts) do
  918.   begin
  919.     mFileOpts[i] := TMenuItem.Create(fMain);
  920.     mFileOpts[i].Caption := menuNames[i];
  921.     mFileOpts[i].OnClick := @OnMenuClick;
  922.     mFIle.Add(mFileOpts[i]);
  923.   end;
  924.  
  925.   mMain.Items.Add(mFile);
  926.  
  927.   with fMain do
  928.   begin
  929.     Caption := 'ScaRPG - Map Editor';
  930.     ClientWidth := ((drawSize.x + 1) * 32) + ((shTile.w + 1) * 32) + 32;
  931.     ClientHeight := ((drawSize.y + 1) * 32) + 32;
  932.     Position := poDesktopCenter;
  933.   end;
  934.  
  935.   pSheet := TPanel.Create(fMain);
  936.   with pSheet do
  937.   begin
  938.     Parent := fMain;
  939.     Width := (shTile.w + 1) * 32;
  940.     Height := fMain.ClientHeight;
  941.     Left := fMain.ClientWidth - Width;
  942.     Top := 0;
  943.   end;
  944.  
  945.   sbSheet := TScrollBox.Create(pSheet);
  946.   with sbSheet do
  947.   begin
  948.     Parent := pSheet;
  949.     Align := alClient;
  950.     VertScrollBar.Increment := 32;
  951.   end;
  952.  
  953.   iSheet := TImage.Create(sbSheet);
  954.   with iSheet do
  955.   begin
  956.     Parent := sbSheet;
  957.     Left := 0;
  958.     Top := 0;
  959.     Width := (shTile.w * 32);
  960.     Height := (shTile.h * 32);
  961.     SafeDrawBitmap(shTile.b, Canvas, 0, 0);
  962.     OnMouseDown := @OnTilesheetMouseDown;
  963.     OnMouseUp := @OnTilesheetMouseUp;
  964.     ApplyGrid(iSheet, clRed);
  965.   end;
  966.  
  967.   pTile := TPanel.Create(pSheet);
  968.   with pTile do
  969.   begin
  970.     Parent := pSheet;
  971.     Align := alBottom;
  972.     Height := 96;
  973.   end;
  974.  
  975.   iTile := TImage.Create(pTile);
  976.   with iTile do
  977.   begin
  978.     Parent := pTile;
  979.     Left := 16;
  980.     Top := 16;
  981.     Width := 64;
  982.     Height := 64;
  983.     PaintDrawTiles;
  984.   end;
  985.  
  986.   bLayUp := TButton.Create(pTile);
  987.   with bLayUp do
  988.   begin
  989.     Parent := pTile;
  990.     Left := 96;
  991.     Top := 16;
  992.     Width := 32;
  993.     Height := 32;
  994.     Caption := '^';
  995.     OnClick := @OnButtonClick;
  996.   end;
  997.  
  998.   bLayDo := TButton.Create(pTile);
  999.   with bLayDo do
  1000.   begin
  1001.     Parent := pTile;
  1002.     Left := 96;
  1003.     Top := 48;
  1004.     Width := 32;
  1005.     Height := 32;
  1006.     Caption := 'v';
  1007.     OnClick := @OnButtonClick;
  1008.   end;
  1009.  
  1010.   toolHints := ['Picker', 'Pencil', 'Tiled box', 'Smart box', 'Flood fill', 'Pencil Erase', 'Box Erase', 'Select'];
  1011. //  toolHints := ['Draw', 'Erase', 'Select', 'Flood', 'Pencil', 'Tile', 'Box', 'Save'];
  1012.   SetLength(bTools, Length(toolHints));
  1013.   for i := 0 to High(toolHints) do
  1014.   begin
  1015.     bTools[i] := TButton.Create(pTile);
  1016.     with bTools[i] do
  1017.     begin
  1018.       Parent := pTile;
  1019.       Left := 144 + ((i mod 4) * 32);
  1020.       Top := 16 + ((i div 4) * 32);
  1021.       Width := 32;
  1022.       Height := 32;
  1023.       Hint := toolHints[i];
  1024.       Caption := Copy(toolHints[i], 1, 4);
  1025.       OnClick := @OnToolClick;
  1026.     end;
  1027.   end;
  1028.  
  1029.   lCurLay := TLabel.Create(pTile);
  1030.   with lCurLay do
  1031.   begin
  1032.     Parent := pTile;
  1033.     Left := 144;
  1034.     Top := 32;
  1035.     Caption := 'Layer ' + IntToStr(curLay) + ' selected';
  1036.   end;
  1037.  
  1038.   tcMain := TTabControl.Create(fMain);
  1039.   with tcMain do
  1040.   begin
  1041.     Parent := fMain;
  1042.     Left := 0;
  1043.     Top := 0;
  1044.     Width := (drawSize.x * 32) + 48;
  1045.     Height := (drawSize.y * 32) + 64;
  1046.     AddMap(20, 20, 3);
  1047.     OnChange := @OnTabChange;
  1048.   end;
  1049.  
  1050.   iMain := TImage.Create(tcMain);
  1051.   with iMain do
  1052.   begin
  1053.     Parent := tcMain;
  1054.     Left := 16;
  1055.     Top := 32;
  1056.     Width := drawSize.x * 32;
  1057.     Height := drawSize.y * 32;
  1058.     OnMouseDown := @OnMapMouseDown;
  1059.     OnMouseUp := @OnMapMouseUp;
  1060.     OnMouseMove := @OnMapMouseMove;
  1061.     ApplyGrid(iMain, clRed);
  1062.   end;
  1063.  
  1064.   sbHorz := TScrollBar.Create(tcMain);
  1065.   with sbHorz do
  1066.   begin
  1067.     Parent := tcMain;
  1068.     Left := 16;
  1069.     Top := 32 + iMain.Height;
  1070.     Width := iMain.Width;
  1071.     Height := 16;
  1072.     Kind := sbHorizontal;
  1073.     Max := maps[curMap].Width - drawSize.x;
  1074.     OnScroll := @OnMapScroll;
  1075.   end;
  1076.  
  1077.   sbVert := TScrollBar.Create(tcMain);
  1078.   with sbVert do
  1079.   begin
  1080.     Parent := tcMain;
  1081.     Left := 16 + iMain.Width;
  1082.     Top := 32;
  1083.     Width := iMain.Width;
  1084.     Height := 16;
  1085.     Kind := sbVertical;
  1086.     Max := maps[curMap].Height - drawSize.y;
  1087.     OnScroll := @OnMapScroll;
  1088.   end;
  1089.  
  1090.   RedrawMap(maps[curMap]);
  1091.   PaintMap;
  1092.   fMain.ShowModal;
  1093. end;
  1094.  
  1095. var
  1096.   v: TVariantArray;
  1097.   m, z, i: Integer;
  1098. // Main loop - no comments
  1099. begin
  1100.   Writeln('begin');
  1101.   drawSize := Point(15, 15);
  1102.   drawMode := 1;
  1103.   LoadSheet(shTile, ScriptPath + 'Tiles.bmp');
  1104.  
  1105.   ThreadSafeCall('SetupForm', v);
  1106. //  SetupForm; // Use without SafeCall for debugging unknown errors, though very prone to self destruct when done so - use at own risk
  1107.   FreeForm(fMain);
  1108.  
  1109.   for m := 0 to High(maps) do
  1110.     for z := 0 to maps[m].depth - 1 do
  1111.       MFreeBitmap(maps[m].vis[z]);
  1112.   FreeBitmap(shTile.b);
  1113.  
  1114.   // Section for debugging memory leaks - see MBitmap and MFreeBitmap
  1115.   // Don't rely on it for fixing all leaks - only works when you use MBitmap and not LoadBitmap etc.
  1116.   while True do
  1117.   begin
  1118.     i := Pos('1', bitDeb);
  1119.     if (i = 0) then
  1120.       Break;
  1121.     Writeln('Bitmap created from ''' + bitLoc[i] + ''' not freed!');
  1122.     MFreeBitmap(i - 1);
  1123.   end;
  1124.  
  1125.   Writeln('end');
  1126. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement