rollmorad hinzugefügt
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
|
||||
int main(int argc, char** pp_args)
|
||||
{
|
||||
if(argc == 1)
|
||||
{
|
||||
std::cout << "Usage: addnewline file1 file2 file3 ..." << std::endl;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int numErrors = 0;
|
||||
|
||||
for(int i = 1; i < argc; ++i)
|
||||
{
|
||||
FILE* p_file = fopen(pp_args[i], "rb");
|
||||
if(!p_file)
|
||||
{
|
||||
std::cerr << "Couldn't open file " << pp_args[i] << std::endl;
|
||||
++numErrors;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::cout << pp_args[i] << ": ";
|
||||
|
||||
fseek(p_file, 0, SEEK_END);
|
||||
long fileSize = ftell(p_file);
|
||||
|
||||
bool addNewLine = fileSize == 0;
|
||||
if(fileSize)
|
||||
{
|
||||
fseek(p_file, fileSize - 1, SEEK_SET);
|
||||
int ch = fgetc(p_file);
|
||||
addNewLine = ch != '\n';
|
||||
}
|
||||
|
||||
fclose(p_file);
|
||||
|
||||
if(addNewLine)
|
||||
{
|
||||
p_file = fopen(pp_args[i], "ab");
|
||||
fputc('\n', p_file);
|
||||
fclose(p_file);
|
||||
|
||||
std::cout << "added newline" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "OK" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return numErrors;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
# AngelCode Bitmap Font Generator configuration file
|
||||
fileVersion=1
|
||||
|
||||
# font settings
|
||||
fontName=Bell Gothic Std Black
|
||||
charSet=0
|
||||
fontSize=125
|
||||
aa=4
|
||||
scaleH=100
|
||||
useSmoothing=1
|
||||
isBold=0
|
||||
isItalic=0
|
||||
useUnicode=1
|
||||
disableBoxChars=1
|
||||
|
||||
# character alignment
|
||||
paddingDown=0
|
||||
paddingUp=0
|
||||
paddingRight=0
|
||||
paddingLeft=0
|
||||
spacingHoriz=4
|
||||
spacingVert=4
|
||||
|
||||
# output file
|
||||
outWidth=1024
|
||||
outHeight=1024
|
||||
outBitDepth=32
|
||||
fontDescFormat=1
|
||||
fourChnlPacked=0
|
||||
textureFormat=png
|
||||
textureCompression=0
|
||||
|
||||
# outline
|
||||
outlineThickness=4
|
||||
is1ChnlEncoded=0
|
||||
|
||||
# selected chars
|
||||
chars=32-126,160-255
|
||||
|
||||
# imported icon images
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
@@ -0,0 +1,383 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Bitmap Font Generator - Documentation</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a name="#top"></a>
|
||||
<h1>Bitmap Font Generator - Documentation</h1>
|
||||
|
||||
<p>The Bitmap Font Generator is a free program to generate bitmap fonts from true type fonts.
|
||||
The bitmaps are generated in such a way as to leave as little unused space as possible. The
|
||||
position of the characters in the bitmap is not regular so you'll need the generated font
|
||||
descriptor file to determine how to draw each character.</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="#settings">Font settings</a>
|
||||
<li><a href="#cmdline">Command line parameters</a>
|
||||
<li><a href="#tags">File tags</a>
|
||||
<li><a href="#bin">Binary file layout</a>
|
||||
<li><a href="#shader">Pixel shader sample</a>
|
||||
<li><a href="#issues">Known issues</a>
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
<a href="#top">top</a>
|
||||
<hr>
|
||||
|
||||
<a name="#settings"></a>
|
||||
<h2>Font settings</h2>
|
||||
|
||||
<p><img src="doc/font_settings.png"></p>
|
||||
|
||||
<p>You can open the font settings dialog by going to the Options menu and choosing Font
|
||||
settings, or you can just press F on the keyboard.</p>
|
||||
|
||||
<p>The left half of this dialog controls the properties of the font, i.e. the character
|
||||
set, and looks. The right half controls how the font will be stored, i.e. texture layout,
|
||||
file format, etc. The left half is pretty self explanatory, so I'll explain only the
|
||||
right half.</p>
|
||||
|
||||
<h3>Padding</h3>
|
||||
|
||||
<p>Padding is useful when you want to add some post processing effects in another
|
||||
paint program. For example, if you want to add a blurring effect that uses a 5x5 kernel,
|
||||
you would add a padding of 2 on all sides. Similarly if you want to add a drop shadow, you
|
||||
would add a bit of padding below and to the right of the characters (assuming that's the
|
||||
direction of the drop shadow that you want).
|
||||
|
||||
<h3>Spacing</h3>
|
||||
|
||||
<p>The spacing controls how much minimum space is left between characters in the font
|
||||
texture. If you're using mipmapping to scale the font texture when drawing the font, you'll
|
||||
need to add spacing to avoid bleeding when the texture is downscaled. The more mipmap levels
|
||||
you use the more spacing you need.</p>
|
||||
|
||||
<p>Bilinear filtering may also cause bleeding, so unless you use pixel perfect drawing, where
|
||||
each texel is perfectly mapped to a pixel on the screen with a 1-to-1 releation ship you'll
|
||||
want to use at least 1 for vertical and horizontal spacing.</p>
|
||||
|
||||
<h3>Texture</h3>
|
||||
|
||||
<p>BMFont supports several different texture layouts. The width and height, of course control
|
||||
the size of the texture. You'll want to keep the texture as small as possible, while
|
||||
still allowing all characters to fit in one texture.</p>
|
||||
|
||||
<p>If you're importing colored icons, or planning on using post processing to add colors to the
|
||||
characters, then you'll want to choose the 32bit format, otherwise the 8bit format may be sufficient.</p>
|
||||
|
||||
<p>If you choose the 32bit format, you may still optimize the usage of the texture memory if you
|
||||
choose to pack characters in each channel, though that will require a special <a href="#shader">pixel shader</a> to
|
||||
decode during drawing. In this mode you can still import colored icons, the characters will be
|
||||
properly packed around them.</p>
|
||||
|
||||
<p>The font outline can also be encoded together with the character in 8 bits, allowing you to
|
||||
store many more characters in the same space than if you had stored the outlined characters as
|
||||
colored images. This too require a special <a href="#shader">pixel shader</a> to
|
||||
decode during drawing.</p>
|
||||
|
||||
<h3>File format</h3>
|
||||
|
||||
<p>Finally you can choose the file format for both the font descriptor and textures. This is mostly
|
||||
a matter of choice, rather than one having more benefits than the other. Though if you want to save
|
||||
disc space, you may want to choose binary file descriptor with png textures.</p>
|
||||
|
||||
<hr>
|
||||
<a href="#top">top</a>
|
||||
<hr>
|
||||
|
||||
<a name="#cmdline"></a>
|
||||
<h2>Command line parameters</h2>
|
||||
|
||||
<p>The application can be used from the command line, to performed automated generation of font files. The
|
||||
prerequisite is a font configuration file, that you can save from the application, or even generate yourself.
|
||||
The command line parameters are:</p>
|
||||
|
||||
<ul>
|
||||
<li>-c fontconfig.bmfc : Names the configuration file with the options for generating the font.
|
||||
<li>-o outputfile.fnt : Names of the output font file.
|
||||
<li>-t textfile.txt : Optional argument that names a text file. All characters present in the text file will be
|
||||
added to the font.
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
<a href="#top">top</a>
|
||||
<hr>
|
||||
|
||||
<a name="#tags"></a>
|
||||
<h2>File tags</h2>
|
||||
|
||||
<h3>info</h3>
|
||||
|
||||
<p>This tag holds information on how the font was generated.</p>
|
||||
|
||||
<table>
|
||||
<tr><td width=100>face</td><td>This is the name of the true type font.</td></tr>
|
||||
<tr><td>size</td><td>The size of the true type font.</td></tr>
|
||||
<tr><td>bold</td><td>The font is bold.</td></tr>
|
||||
<tr><td>italic</td><td>The font is italic.</td></tr>
|
||||
<tr><td>charset</td><td>The name of the OEM charset used (when not unicode).</td></tr>
|
||||
<tr><td>unicode</td><td>Set to 1 if it is the unicode charset.</td></tr>
|
||||
<tr><td>stretchH</td><td>The font height stretch in percentage. 100% means no stretch.</td></tr>
|
||||
<tr><td>smooth</td><td>Set to 1 if smoothing was turned on.</td></tr>
|
||||
<tr><td>aa</td><td>The supersampling level used. 1 means no supersampling was used.</td></tr>
|
||||
<tr><td>padding</td><td>The padding for each character (up, right, down, left).</td></tr>
|
||||
<tr><td>spacing</td><td>The spacing for each character (horizontal, vertical).</td></tr>
|
||||
<tr><td>outline</td><td>The outline thickness for the characters.</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>common</h3>
|
||||
|
||||
<p>This tag holds information common to all characters.</p>
|
||||
|
||||
<table>
|
||||
<tr><td width=100>lineHeight</td><td>This is the distance in pixels between each line of text.</td></tr>
|
||||
<tr><td>base</td><td>The number of pixels from the absolute top of the line to the base of the characters.</td></tr>
|
||||
<tr><td>scaleW</td><td>The width of the texture, normally used to scale the x pos of the character image.</td></tr>
|
||||
<tr><td>scaleH</td><td>The height of the texture, normally used to scale the y pos of the character image.</td></tr>
|
||||
<tr><td>pages</td><td>The number of texture pages included in the font.</td></tr>
|
||||
<tr><td>packed</td><td>Set to 1 if the monochrome characters have been packed into each of the texture channels.</td></tr>
|
||||
<tr><td>encoded</td><td>Set to 1 if the black outline is encoded together with the white char in the alpha channel.</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>page</h3>
|
||||
|
||||
<p>This tag gives the name of a texture file. There is one for each page in the font.</p>
|
||||
|
||||
<table>
|
||||
<tr><td width=100>id</td><td>The page id.</td></tr>
|
||||
<tr><td>file</td><td>The texture file name.</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>char</h3>
|
||||
|
||||
<p>This tag describes on character in the font. There is one for each included character in the font.</p>
|
||||
|
||||
<table>
|
||||
<tr><td width=100>id</td><td>The character id.</td></tr>
|
||||
<tr><td>x</td><td>The left position of the character image in the texture.</td></tr>
|
||||
<tr><td>y</td><td>The top position of the character image in the texture.</td></tr>
|
||||
<tr><td>width</td><td>The width of the character image in the texture.</td></tr>
|
||||
<tr><td>height</td><td>The height of the character image in the texture.</td></tr>
|
||||
<tr><td>xoffset</td><td>How much the current position should be offset when copying the image from the texture to
|
||||
the screen.</td></tr>
|
||||
<tr><td>yoffset</td><td>How much the current position should be offset when copying the image from the texture to
|
||||
the screen.</td></tr>
|
||||
<tr><td>xadvance</td><td>How much the current position should be advanced after drawing the character.</td></tr>
|
||||
<tr><td>page</td><td>The texture page where the character image is found.</td></tr>
|
||||
<tr><td>chnl</td><td>The texture channel where the character image is found
|
||||
(1 = blue, 2 = green, 4 = red, 8 = alpha, 15 = all channels).</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>kerning</h3>
|
||||
|
||||
<p>The kerning information is used to adjust the distance between certain characters, e.g. some characters should
|
||||
be placed closer to each other than others.</p>
|
||||
|
||||
<table>
|
||||
<tr><td width=100>first</td><td>The first character id.</td></tr>
|
||||
<tr><td>second</td><td>The second character id.</td></tr>
|
||||
<tr><td>amount</td><td>How much the x position should be adjusted when drawing the second character immediately
|
||||
following the first.</td></tr>
|
||||
</table>
|
||||
|
||||
<hr>
|
||||
<a href="#top">top</a>
|
||||
<hr>
|
||||
|
||||
<a name="#bin"></A>
|
||||
<h2>Binary file layout</h2>
|
||||
|
||||
<p>This section describes the layout of the tags in the binary file format. To understand what each tag means refer
|
||||
to the <a href="#tags">file tags</A> section.</p>
|
||||
|
||||
<p>The first three bytes are the file identifier and must always be 66, 77, 70, or "BMF". The fourth byte gives
|
||||
the format version, currently it must be the binary 1 or 2. Version 2 sees the addition of outline in the
|
||||
infoBlock and encoded in the commonBlock.</p>
|
||||
|
||||
<p>Following the first four bytes is a series of blocks with information. Each block starts with a one byte block
|
||||
type identifier, followed by a 4 byte integer that gives the size of the block, including the 4 byte size value,
|
||||
but not the block type identifier.</p>
|
||||
|
||||
<h3>Block type 1: info</h3>
|
||||
|
||||
<pre>
|
||||
#pragma pack(1)
|
||||
struct infoBlock
|
||||
{
|
||||
int blockSize;
|
||||
WORD fontSize;
|
||||
BYTE reserved:4;
|
||||
BYTE bold :1;
|
||||
BYTE italic :1;
|
||||
BYTE unicode :1;
|
||||
BYTE smooth :1;
|
||||
BYTE charSet;
|
||||
WORD stretchH;
|
||||
BYTE aa;
|
||||
BYTE paddingUp;
|
||||
BYTE paddingRight;
|
||||
BYTE paddingDown;
|
||||
BYTE paddingLeft;
|
||||
BYTE spacingHoriz;
|
||||
BYTE spacingVert;
|
||||
BYTE outline; // Added with version 2
|
||||
char fontName[1];
|
||||
};
|
||||
</pre>
|
||||
|
||||
<p>This structure gives the layout of the fields. Remember that there should be no
|
||||
padding between members. Allocate the size of the block using the blockSize, as
|
||||
following the block comes the font name, including the terminating null char.
|
||||
Most of the time this block can simply be ignored.</p>
|
||||
|
||||
<h3>Block type 2: common</h3>
|
||||
|
||||
<pre>
|
||||
#pragma pack(1)
|
||||
struct commonBlock
|
||||
{
|
||||
int blockSize;
|
||||
WORD lineHeight;
|
||||
WORD base;
|
||||
WORD scaleW;
|
||||
WORD scaleH;
|
||||
WORD pages;
|
||||
BYTE packed :1;
|
||||
BYTE encoded :1; // Added with version 2
|
||||
BYTE reserved:6;
|
||||
};
|
||||
</pre>
|
||||
|
||||
<h3>Block type 3: pages</h3>
|
||||
|
||||
<pre>
|
||||
#pragma pack(1)
|
||||
struct pagesBlock
|
||||
{
|
||||
int blockSize;
|
||||
char pageNames[1];
|
||||
};
|
||||
</pre>
|
||||
|
||||
<p>This block gives the name of each texture file with the image data for the characters.
|
||||
The string pageNames holds the names separated and terminated by null chars. Each filename
|
||||
has the same length, so once you know the size of the first name, you can easily determine
|
||||
the position of each of the names. The id of each page is the zero-based index of the string name.</p>
|
||||
|
||||
<h3>Block type 4: chars</h3>
|
||||
|
||||
<pre>
|
||||
#pragma pack(1)
|
||||
struct charsBlock
|
||||
{
|
||||
int blockSize;
|
||||
struct charInfo
|
||||
{
|
||||
WORD id;
|
||||
WORD x;
|
||||
WORD y;
|
||||
WORD width;
|
||||
WORD height;
|
||||
short xoffset;
|
||||
short yoffset;
|
||||
short xadvance;
|
||||
BYTE page;
|
||||
BYTE chnl;
|
||||
} chars[1];
|
||||
};
|
||||
</pre>
|
||||
|
||||
<p>The number of characters in the file can be computed by taking the size of the block
|
||||
and dividing with the size of the charInfo structure, i.e.: numChars = (charsBlock.blockSize - 4)/18.</p>
|
||||
|
||||
<h3>Block type 5: kerning pairs</h3>
|
||||
|
||||
<pre>
|
||||
#pragma pack(1)
|
||||
struct kerningPairsBlock
|
||||
{
|
||||
int blockSize;
|
||||
struct kerningPair
|
||||
{
|
||||
WORD first;
|
||||
WORD second;
|
||||
short amount;
|
||||
} kerningPairs[1];
|
||||
};
|
||||
</pre>
|
||||
|
||||
<p>This block is only in the file if there are any kerning pairs with amount differing from 0.</p>
|
||||
|
||||
<hr>
|
||||
<a href="#top">top</a>
|
||||
<hr>
|
||||
|
||||
<a name="#shader"></a>
|
||||
<h2>Pixel shader sample</h2>
|
||||
|
||||
<p>This pixel shader shows how to decode the color from a font texture with characters packed
|
||||
into all 4 channels, and each channel using special encoding to store the character with the
|
||||
outline. The texture is also allowed to store full 32bit images for some characters.</p>
|
||||
|
||||
<pre>
|
||||
// DirectX 9 pixel shader
|
||||
float4 PixScene( float4 color : COLOR0,
|
||||
int4 chnl : TEXCOORD1,
|
||||
float2 tex0 : TEXCOORD0 ) : COLOR0
|
||||
{
|
||||
float4 pixel = tex2D(g_samScene, tex0);
|
||||
|
||||
if( dot(vector(1,1,1,1), chnl) )
|
||||
{
|
||||
float val = dot(pixel, chnl);
|
||||
|
||||
pixel.rgb = val > 0.5 ? 2*val-1 : 0;
|
||||
pixel.a = val > 0.5 ? 1 : 2*val;
|
||||
}
|
||||
|
||||
return pixel * color;
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>The chnl texture coordinate is a 4D vector that shows which channel the character should be read
|
||||
from. If this is (0,0,0,0) the character is interpreted as a 32 bit image. The texture coordinate
|
||||
can be stored in a UBYTE4 type, so it doesn't require much bandwidth when being sent to the video card.</p>
|
||||
|
||||
<hr>
|
||||
<a href="#top">top</a>
|
||||
<hr>
|
||||
|
||||
<a name="#issues"></a>
|
||||
<h2>Known issues</h2>
|
||||
|
||||
<h3>Cropped characters</h3>
|
||||
|
||||
<p>With some fonts, some characters are cropped. An example is Bitstream's Cyberbit font, where the bottom of the
|
||||
square bracket characters are cropped off in some font sizes.</p>
|
||||
|
||||
<p>This is a compatibility problem between the font and GDI, not a problem in this application by itself. You get
|
||||
the same problem in WordPad for example. I will however try out other font rasterizers, to see if I can fix this
|
||||
problem in a future version.</p>
|
||||
|
||||
<h3>Characters are disabled, yet they have images</h3>
|
||||
|
||||
<p>Depending on your Windows configuration you may see that with some fonts characters are disabled, yet have a
|
||||
character image. Especially with the asian character sets. This is because Windows automatically fills in the
|
||||
missing characters by taking them from another font when the international language pack is installed.</p>
|
||||
|
||||
<p>I do not consider this an error in BMFont, but it may be fixed in a future version, especially if I end up using
|
||||
another font rasterizer.</p>
|
||||
|
||||
<h3>Rotated characters</h3>
|
||||
|
||||
<p>Some font files have some but not all subsets with characters rotated by 90 degrees. For example @Arial Unicode MS,
|
||||
with subset Enclosed Alphanumerics. This is not an error, but a feature of that font file. With the font rotated
|
||||
like this it permits writing texts in normal text editors as if they were in vertical lines.</p>
|
||||
|
||||
<hr>
|
||||
<a href="#top">top</a>
|
||||
<hr>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,113 @@
|
||||
Bitmap Font Generator v1.9c by Andreas Jönsson (www.AngelCode.com)
|
||||
----------------------------------------------------------------------------------------
|
||||
This program will allow you to generate bitmap fonts from TrueType and other Windows fonts. The application generates both image files and character descriptions that can be read by a game for easy rendering of fonts.
|
||||
|
||||
Disclaimer
|
||||
------------------------------
|
||||
This program is provided 'as-is' and no responsibility for any type of damage taken to your system as a consequence of installing or using this program is taken by the author.
|
||||
|
||||
Freeware
|
||||
-------------------------------
|
||||
This program is freeware and may be used freely without charge. If you wish to distribute this program contact the author for his permission.
|
||||
|
||||
Support
|
||||
--------------------------------
|
||||
This program has very limited support as it is freeware, but you are welcome to send your suggestions and questions to the author.
|
||||
|
||||
Contact
|
||||
--------------------------------
|
||||
The program and any possible upgrades can be found at www.AngelCode.com. The author may also be contacted through this site.
|
||||
|
||||
Changes
|
||||
-------------------------------
|
||||
1.9c - 2007/11/16
|
||||
- Fixed the reversed spacing values in the font settings dialog.
|
||||
- The font generation can now be aborted while the characters are being added to the texture.
|
||||
- Greatly improved the speed of generating textures.
|
||||
|
||||
1.9b - 2007/10/28
|
||||
- Fixed the padding.
|
||||
- Improved documentation.
|
||||
|
||||
1.9a - 2007/09/16
|
||||
- Allowing unicode for all fonts, even fonts that have only one code page.
|
||||
- Fixed the status messages when generating fonts.
|
||||
|
||||
1.9 - 2007/08/19
|
||||
- Added support for importing colored icons.
|
||||
- Supported input image formats are: bmp, tga, png, jpg, dds.
|
||||
- Added support for giving a black outline to characters.
|
||||
- Characters with outline may be encoded in 1 channel to save space.
|
||||
- Outline is generated with rounded corners.
|
||||
- Increased the binary file version because there is new information.
|
||||
|
||||
1.8c - 2007/01/25
|
||||
- Fixed a bug where the font saver got confused with the 4 chnl packed flag set, even though saving in 8bit format.
|
||||
|
||||
1.8b - 2007/01/06
|
||||
- Fixed kerning amount in binary file format when using super sampling.
|
||||
|
||||
1.8a - 2006/11/23
|
||||
- Fixed alignment bug with 8bit TGA and DDS files with non-power-of-4 widths.
|
||||
- Fixed crash on Windows with installed Input Method Editors, e.g. Japanese and Chinese Windows.
|
||||
|
||||
1.8 - 2006/11/11
|
||||
- Added support for binary font descriptor file.
|
||||
- Added support for saving PNG texture files.
|
||||
- The application now remembers the configuration from last execution.
|
||||
- Improved useability for selecting characters in unicode mode.
|
||||
- Added option to select all characters from a text file.
|
||||
- Kerning pairs with amount 0 are no longer output.
|
||||
- XML font descriptor file now groups the pages, chars, and kerning pairs.
|
||||
- The font configuration can be saved to disk, and later reloaded.
|
||||
- Added support for generating fonts via command line using a saved configuration.
|
||||
- Added support for saving DDS texture files (no compression).
|
||||
|
||||
1.7a - 2006/09/12
|
||||
- Fixed the creation of non-unicode fonts.
|
||||
|
||||
1.7 - 2006/09/08
|
||||
- Added the standard xml header.
|
||||
- Added support for unicode charsets.
|
||||
- Added the option to pack monochrome characters into each of the 4 channels of a 32 bit texture.
|
||||
- Added tag with texture file names in the font descriptor file.
|
||||
- The generation of textures is now done in a background thread.
|
||||
|
||||
1.6 - 2006/02/18
|
||||
- It's now possible to choose between XML and text for the format of the font descriptor file.
|
||||
- Fixed kerning sizes with super-sampling.
|
||||
|
||||
1.5 - 2005/10/01
|
||||
- Implemented stretching so that fonts can now be non-uniformly scaled (only works on Win2K or later).
|
||||
|
||||
1.4a - 2005/08/26
|
||||
- Non-TrueType fonts, such as Script and System, are now supported as well.
|
||||
- Minor fix to rendering when padding is used.
|
||||
|
||||
1.4 - 2005/07/17
|
||||
- The preview window now shows the page number in the title.
|
||||
- Characters without a defined glyph may now be automatically removed (only works on Win2K or later).
|
||||
- Kerning pairs are now saved as well.
|
||||
- Added support for chooseable charset, e.g. arabic and hebrew fonts.
|
||||
|
||||
1.3 - 2005/05/08
|
||||
- Added support for italic fonts.
|
||||
- Application no longer crashes when visualizing with no characters selected.
|
||||
|
||||
1.2 - 2005/03/09
|
||||
- User can now choose to generate the bitmap font with or without font smoothing.
|
||||
- Font smoothing is now done without ClearType, so that artifacts are no longer generated in the output texture.
|
||||
- Added program icon.
|
||||
|
||||
1.1 - 2005/03/05
|
||||
- User can now choose to save in 32bit and 8bit TGAs.
|
||||
- The spacing between characters can now be manually set.
|
||||
- Fixed the bug where some fonts weren't visible in the font list.
|
||||
|
||||
1.0a - 2004/11/27
|
||||
- Fixed a problem with values that where not adjusted to compensate for antialiasing level.
|
||||
|
||||
1.0 - 2004/02/14
|
||||
- First public version.
|
||||
|
||||
copyright (c) 2004-2007 Andreas Jönsson
|
||||
@@ -0,0 +1,57 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<style type="text/css">@import 'style.css';</style>
|
||||
<script type="text/javascript" src="js/af_Toolkit.js"></script>
|
||||
<script type="text/javascript" src="js/JSON2.js"></script>
|
||||
<script type="text/javascript" src="js/RllmrdLevelEditr.js"></script>
|
||||
<script type="text/javascript">
|
||||
function initRLE() {
|
||||
window.RLE = new RllmrdLevelEditr(
|
||||
document.getElementById('editor')
|
||||
);
|
||||
// window.RLE.loadLevel('level2.xml');
|
||||
}
|
||||
</script>
|
||||
<title>Rollmorad Level Editr beta</title>
|
||||
</head>
|
||||
<body onload="initRLE()" onunload="RLE.unloadLevel()">
|
||||
|
||||
<h1>rollmorad guhase 2010 level edit<span>r</span> <sup>pre-pre-alpha</sup></h1>
|
||||
|
||||
<div id="editor"></div>
|
||||
|
||||
<div id="menu">
|
||||
|
||||
<a href="#" class="toggle" onclick="return RLE.toggle('level');">Level</a>
|
||||
<div id="level">
|
||||
<form action="#" onsubmit="return RLE.loadLevel(document.getElementById('level_filename').value);">
|
||||
<label for="level_filename">Level:</label>
|
||||
<input type="text" name="level_filename" id="level_filename" />
|
||||
<input type="submit" value="Laden" />
|
||||
</form>
|
||||
<button onclick="return RLE.unloadLevel();">Level schließen</button>
|
||||
<button onclick="return RLE.saveLevel();">Level exportieren</button>
|
||||
<br />
|
||||
|
||||
<div id="levelform"></div>
|
||||
</div>
|
||||
|
||||
<a href="#" class="toggle" onclick="return RLE.toggle('layers');">Layer</a>
|
||||
<div id="layers">
|
||||
<div></div>
|
||||
<a href="#" onclick="return RLE.addTilemapLayer();">+TilemapLayer</a>
|
||||
<a href="#" onclick="return RLE.addImageLayer();">+ImageLayer</a>
|
||||
</div>
|
||||
|
||||
<a href="#" class="toggle" onclick="return RLE.toggle('tiles');">Tiles</a>
|
||||
<div id="tiles"></div>
|
||||
</div>
|
||||
|
||||
<div id="statusbar">
|
||||
Statusbar
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,568 @@
|
||||
RllmrdLevelEditr = function(_editor) {
|
||||
|
||||
var that = this;
|
||||
|
||||
that.data = '../../data/';
|
||||
that.currentTile = 0;
|
||||
that.tilePainting = false;
|
||||
that.erasing = false;
|
||||
that.tiles = {};
|
||||
that.layers = {};
|
||||
that.currentLayer = 0;
|
||||
that.nextLayer = 1;
|
||||
that.level = {}
|
||||
|
||||
that.tileSize = 64;
|
||||
that.tileSetSize = 1024;
|
||||
that.zoom = 0.5;
|
||||
|
||||
that.width = 0;
|
||||
that.height = 0;
|
||||
|
||||
that.defaultImageLayer = {
|
||||
id: 0,
|
||||
type: 'imagelayer',
|
||||
z: 0.0,
|
||||
imageFilename: '',
|
||||
imageOffset: '',
|
||||
tiling: '',
|
||||
movement: '',
|
||||
color: '',
|
||||
};
|
||||
|
||||
that.defaultTilemapLayer = {
|
||||
id: 0,
|
||||
tileSetFilename: '',
|
||||
visible: 1,
|
||||
enablePhysics: 1,
|
||||
type: 'tilemaplayer',
|
||||
z: 0
|
||||
};
|
||||
|
||||
that.defaultLevel = {
|
||||
name: '',
|
||||
size: '(40, 15)',
|
||||
backgroundColor: '(1.0, 1.0, 1.0, 1.0)',
|
||||
gravity: '(0.0, 9.81)',
|
||||
musicFilename: '',
|
||||
supportedGameModes: 'GM_STORY',
|
||||
};
|
||||
|
||||
that.editor = _editor;
|
||||
|
||||
that.addImageLayer = function() {
|
||||
var layerID = that.nextLayer++;
|
||||
that.layers[layerID] = {};
|
||||
for (var z in that.defaultImageLayer) {
|
||||
that.layers[layerID][z] = that.defaultImageLayer[z];
|
||||
}
|
||||
that.layers[layerID].id = layerID;
|
||||
that.updateLayerList();
|
||||
return false;
|
||||
}
|
||||
|
||||
that.addTilemapLayer = function(layerID) {
|
||||
if (typeof layerID == 'undefined') {
|
||||
layerID = that.nextLayer++;
|
||||
var grid = [];
|
||||
for (var y = 0; y < that.height; ++y) {
|
||||
grid[y] = [];
|
||||
for (var x = 0; x < that.width; ++x) {
|
||||
grid[y][x] = 0;
|
||||
}
|
||||
}
|
||||
that.layers[layerID] = {};
|
||||
for (var z in that.defaultTilemapLayer) {
|
||||
that.layers[layerID][z] = that.defaultTilemapLayer[z];
|
||||
}
|
||||
that.layers[layerID].id = layerID;
|
||||
that.layers[layerID].grid = grid;
|
||||
}
|
||||
that.updateLayerList();
|
||||
that.selectLayer(layerID);
|
||||
var div = document.getElementById('layer_' + layerID);
|
||||
if (div) {
|
||||
div.parentNode.removeChild(div);
|
||||
}
|
||||
var html = '<div class="layer" id="layer_' + layerID + '"><table border="0" cellspacing="0" cellpadding="0">';
|
||||
for (var y = 0; y < that.height; ++y) {
|
||||
html += '<tr>';
|
||||
for (var x = 0; x < that.width; ++x) {
|
||||
html += '<td><div id="box_' + layerID + '_' + y + '_' + x + '" onclick="return RLE.applyTile(event)" onmouseover="return RLE.hoverBox(event)" onmousemove="return RLE.hoverBox(event)" onmousedown="return RLE.applyTile(event)" style="width: ' + parseInt(that.tileSize * that.zoom) + 'px; height: ' + parseInt(that.tileSize * that.zoom) + 'px;">'
|
||||
var tile = that.tiles[parseInt(that.layers[layerID].grid[y][x])];
|
||||
if (tile) {
|
||||
html += '<img src="' + that.data + "tilesets/" + tile.filename + '" style="' + 'top: -' + parseInt(tile.posY * that.zoom) + 'px; left: -' + parseInt(tile.posX * that.zoom) + 'px; width: ' + parseInt(that.tileSetSize * that.zoom) + 'px; height: ' + parseInt(that.tileSetSize * that.zoom) + 'px;" onmousedown="return false;" />';
|
||||
}
|
||||
html += '</div></td>';
|
||||
}
|
||||
html += '</tr>';
|
||||
}
|
||||
html += '</table></div>';
|
||||
that.editor.innerHTML += html;
|
||||
return false;
|
||||
}
|
||||
|
||||
that.deleteLayer = function(id) {
|
||||
if (!confirm("Wirklich?")) return;
|
||||
delete that.layers[id];
|
||||
var elem = document.getElementById('layer_' + id);
|
||||
if (elem) {
|
||||
elem.parentNode.removeChild(elem);
|
||||
}
|
||||
that.updateLayerList();
|
||||
return false;
|
||||
}
|
||||
|
||||
that.layerComparator = function(a, b) {
|
||||
return that.layers[a].z - that.layers[b].z;
|
||||
}
|
||||
|
||||
that.getLayerOrder = function() {
|
||||
var ids = [];
|
||||
for (var i in that.layers) {
|
||||
ids.push(i);
|
||||
}
|
||||
ids.sort(that.layerComparator);
|
||||
return ids;
|
||||
}
|
||||
|
||||
that.updateLayerList = function() {
|
||||
var layerlist = document.getElementById('layers').getElementsByTagName('div')[0];
|
||||
var html = '';
|
||||
var layerOrder = that.getLayerOrder();
|
||||
for (var j = 0; j < layerOrder.length; ++j) {
|
||||
var i = layerOrder[j];
|
||||
html += '<div id="layerselector_' + i + '"';
|
||||
if (i == that.currentLayer) {
|
||||
html += ' style="background-color: #ffc;"';
|
||||
}
|
||||
html += '>';
|
||||
var refLayer;
|
||||
switch (that.layers[i].type) {
|
||||
case 'imagelayer':
|
||||
html += i + ': image';
|
||||
refLayer = that.defaultImageLayer;
|
||||
break;
|
||||
case 'tilemaplayer':
|
||||
html += '<a href="#" onclick="return RLE.selectLayer(' + i + ')">' + i + ': tilemap</a>';
|
||||
refLayer = that.defaultTilemapLayer;
|
||||
break;
|
||||
}
|
||||
html += ' [<a href="#" onclick="return RLE.toggle(\'editlayer_' + i + '\');">edit</a>] ';
|
||||
html += ' [<a href="#" onclick="return RLE.deleteLayer(' + i + ');">entf.</a>]';
|
||||
html += '<div id="editlayer_' + i + '" style="display: none;">';
|
||||
html += '<form action="#" onsubmit="return RLE.updateLayer(this);">';
|
||||
html += '<input type="hidden" name="__layerid" value="' + i + '" >';
|
||||
for (var z in refLayer) {
|
||||
if (z == 'grid' || z == 'objects' || z == 'type') {
|
||||
continue;
|
||||
}
|
||||
html += '<label for="editlayer_' + i + '_' + z + '">' + z + ': </label>';
|
||||
html += '<input type="text" id="editlayer_' + i + '_' + z + '" name="' + z + '" value="' + (that.layers[i][z] || refLayer[z]) + '"/><br />';
|
||||
}
|
||||
html += '<input type="submit" value="Speichern" />';
|
||||
html += '</form>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
}
|
||||
layerlist.innerHTML = html;
|
||||
}
|
||||
|
||||
that.updateLayer = function(form) {
|
||||
var layerInfo = {};
|
||||
for (var i = 0; i < form.elements.length; ++i) {
|
||||
var e = form.elements[i];
|
||||
if (e.id) {
|
||||
layerInfo[e.name] = e.value;
|
||||
}
|
||||
}
|
||||
if (!layerInfo.id || !that.layers[layerInfo.id]) {
|
||||
return false;
|
||||
}
|
||||
for (var i in layerInfo) {
|
||||
that.layers[layerInfo.id][i] = layerInfo[i];
|
||||
}
|
||||
that.updateLayerList();
|
||||
that.selectLayer(layerInfo.id);
|
||||
return false;
|
||||
}
|
||||
|
||||
that.selectLayer = function(id) {
|
||||
if (that.layers[id].type != 'tilemaplayer') {
|
||||
return false;
|
||||
}
|
||||
var elem = document.getElementById('layerselector_' + that.currentLayer);
|
||||
if (elem) {
|
||||
that.toggle2('layer_' + that.currentLayer);
|
||||
elem.style.backgroundColor = '';
|
||||
}
|
||||
that.currentLayer = id;
|
||||
that.toggle2('layer_' + that.currentLayer);
|
||||
that.loadTileset(that.data + "tilesets/" + that.layers[that.currentLayer].tileSetFilename, true);
|
||||
document.getElementById('layerselector_' + that.currentLayer).style.backgroundColor = '#ffc';
|
||||
return false;
|
||||
}
|
||||
|
||||
that.hoverBox = function(event) {
|
||||
var ret = that.applyTile(event);
|
||||
var box = event.currentTarget;
|
||||
var info = /box_(\d+)_(\d+)_(\d+)/.exec(box.getAttribute('id'));
|
||||
if (!info) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
var layerID = info[1];
|
||||
var y = parseInt(info[2]);
|
||||
var x = parseInt(info[3]);
|
||||
|
||||
var html = '<strong>Tile</strong> ' + that.layers[layerID].grid[y][x] + ' @ X: ' + x + ' Y: ' + y + ' ';
|
||||
|
||||
var levelX = x + parseFloat(event.layerX / that.zoom / that.tileSize);
|
||||
var levelY = y + parseFloat(event.layerY / that.zoom / that.tileSize);
|
||||
html += '<strong>Level</strong> X: ' + levelX + ' Y: ' + levelY + ' ';
|
||||
|
||||
document.getElementById('statusbar').innerHTML = html;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
that.setSize = function(width, height) {
|
||||
if (width == that.width && height == that.height) {
|
||||
// nothing changed
|
||||
return;
|
||||
}
|
||||
|
||||
that.width = width;
|
||||
that.height = height;
|
||||
|
||||
for (var layerID in that.layers) {
|
||||
var layer = that.layers[layerID];
|
||||
if (layer.type != 'tilemaplayer') {
|
||||
continue;
|
||||
}
|
||||
var grid = []
|
||||
for (var y = 0; y < height; ++y) {
|
||||
grid[y] = [];
|
||||
for (var x = 0; x < width; ++x) {
|
||||
if (layer.grid[y] && layer.grid[y][x]) {
|
||||
grid[y][x] = layer.grid[y][x];
|
||||
} else {
|
||||
grid[y][x] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
that.layers[layerID].grid = grid;
|
||||
that.addTilemapLayer(layerID);
|
||||
}
|
||||
|
||||
if (that.currentLayer) {
|
||||
that.selectLayer(that.currentLayer);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
that.createLevelForm = function() {
|
||||
var html = '<form action="#" id="level_info" onsubmit="return RLE.processLevelForm(this);">';
|
||||
for (var z in that.defaultLevel) {
|
||||
html += ' <label for="level_' + z + '">' + z + '</label>';
|
||||
html += ' <input type="text" name="level_' + z + '" id="level_' + z + '" value="' + that.defaultLevel[z] + '" />';
|
||||
html += ' <br />\n';
|
||||
}
|
||||
html += ' <input type="submit" value="Speichern" />';
|
||||
html += '</form>';
|
||||
document.getElementById('levelform').innerHTML = html;
|
||||
}
|
||||
|
||||
that.processLevelForm = function(form) {
|
||||
var info = {};
|
||||
for (var z in that.defaultLevel) {
|
||||
if (!form['level_' + z]) continue;
|
||||
info[z] = form['level_' + z].value;
|
||||
}
|
||||
that.setLevelInfo(info);
|
||||
return false;
|
||||
}
|
||||
|
||||
that.setLevelInfo = function(info) {
|
||||
that.level = info;
|
||||
var size = /\((\d+), (\d+)\)/.exec(that.level.size);
|
||||
if (size) {
|
||||
that.setSize(size[1], size[2]);
|
||||
}
|
||||
var form = document.getElementById('level_info');
|
||||
for (var z in info) {
|
||||
form['level_' + z].value = that.level[z] || that.defaultLevel[z];
|
||||
}
|
||||
}
|
||||
|
||||
that.applyTile = function(event) {
|
||||
if ((event.type == 'mouseover' || event.type == 'mousemove') && !that.tilePainting && !that.erasing) {
|
||||
return false;
|
||||
}
|
||||
var element = event.currentTarget;
|
||||
var box = /box_(\d+)_(\d+)_(\d+)/.exec(element.id);
|
||||
if (!box || !box[1] || !box[2] || !box[3]) {
|
||||
return false;
|
||||
}
|
||||
var layer = box[1];
|
||||
var y = box[2];
|
||||
var x = box[3];
|
||||
|
||||
if (event.button == 2 || that.erasing || that.currentTile == 'eraser') {
|
||||
that.layers[layer].grid[y][x] = 0;
|
||||
element.innerHTML = '';
|
||||
return false;
|
||||
}
|
||||
that.layers[layer].grid[y][x] = that.currentTile;
|
||||
var tile = that.tiles[that.currentTile];
|
||||
element.innerHTML = '<img src="' + that.data + "tilesets/" + tile.filename + '" style="' + 'top: -' + parseInt(tile.posY * that.zoom) + 'px; left: -' + parseInt(tile.posX * that.zoom) + 'px; width: ' + parseInt(that.tileSetSize * that.zoom) + 'px; height: ' + parseInt(that.tileSetSize * that.zoom) + 'px;" onmousedown="return false;" />';
|
||||
return false;
|
||||
}
|
||||
|
||||
that.loadTileset = function(filename, silent) {
|
||||
var ajax = new af_AJAX();
|
||||
try {
|
||||
var resp = ajax.getSync(filename);
|
||||
} catch(e) {
|
||||
alert(
|
||||
'Tileset konnte nicht geladen werden!\n'
|
||||
+ 'Um den Editor lokal zu benutzen, muss in die Adresszeile "about:config" eingegeben werden und dann\n'
|
||||
+ '"security.fileuri.strict_origin_policy" auf false gesetzt werden.\n\n'
|
||||
+ e
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!resp.responseXML) {
|
||||
if (!silent) {
|
||||
alert('Tileset konnte nicht geladen werden!');
|
||||
}
|
||||
return;
|
||||
}
|
||||
var tileset = resp.responseXML;
|
||||
var root = tileset.getElementsByTagName('TileSet')[0];
|
||||
if (!root) return
|
||||
var img = root.getAttribute('imageFilename');
|
||||
var tileDefs = tileset.getElementsByTagName('Tile');
|
||||
|
||||
var tileSelector = document.getElementById('tiles');
|
||||
var html = '<div id="tile_eraser" onclick="return RLE.selectTile(\'eraser\');"></div>';
|
||||
for (var i = 0; i < tileDefs.length; ++i) {
|
||||
var pos = /(\d+), ?(\d+)/.exec(tileDefs[i].getAttribute('position'));
|
||||
var id = parseInt(tileDefs[i].getAttribute('id'));
|
||||
that.tiles[id] = { filename: img, posX: pos[1], posY: pos[2] };
|
||||
html += '<div style="background: url(\'' + that.data + "tilesets/" + img + '\'); float: left; ';
|
||||
html += 'background-position: -' + pos[1] + 'px -' + pos[2] + 'px;" ';
|
||||
html += 'onclick="return RLE.selectTile(' + id + ');" id="tile_' + id + '"></div>';
|
||||
}
|
||||
tileSelector.innerHTML = html;
|
||||
that.selectTile('eraser');
|
||||
}
|
||||
|
||||
that.selectTile = function(id) {
|
||||
var elem = document.getElementById('tile_' + that.currentTile)
|
||||
if (elem) {
|
||||
elem.style.borderColor = '';
|
||||
}
|
||||
that.currentTile = id;
|
||||
document.getElementById('tile_' + that.currentTile).style.borderColor = '#f00';
|
||||
return false;
|
||||
}
|
||||
|
||||
that.loadLevel = function(filename) {
|
||||
that.unloadLevel();
|
||||
var file = that.data + "levels/" + filename;
|
||||
var ajax = new af_AJAX;
|
||||
try {
|
||||
var resp = ajax.getSync(file);
|
||||
} catch (e) {
|
||||
alert(
|
||||
'Level konnte nicht geladen werden!\n'
|
||||
+ 'Um den Editor lokal zu benutzen, muss in die Adresszeile "about:config" eingegeben werden und dann\n'
|
||||
+ '"security.fileuri.strict_origin_policy" auf false gesetzt werden.\n\n'
|
||||
+ e
|
||||
);
|
||||
return;
|
||||
}
|
||||
var xml = resp.responseXML;
|
||||
if (!xml) {
|
||||
alert('Level konnte nicht geladen werden!');
|
||||
return false;
|
||||
}
|
||||
document.getElementById('level_filename').value = filename;
|
||||
var root = xml.getElementsByTagName('Level')[0];
|
||||
|
||||
that.setLevelInfo(that.getObjectFromAttributes(root.attributes));
|
||||
|
||||
var layers = xml.getElementsByTagName('Layers')[0].childNodes;
|
||||
for (var n = 0; n < layers.length; ++n) {
|
||||
var layer = layers[n];
|
||||
switch (layer.tagName) {
|
||||
case 'ImageLayer':
|
||||
var layerAttributes = that.getObjectFromAttributes(layer.attributes);
|
||||
layerAttributes.type = 'imagelayer';
|
||||
that.layers[layerAttributes.id] = layerAttributes;
|
||||
that.nextLayer = Math.max(that.nextLayer, parseInt(layerAttributes.id) + 1);
|
||||
break;
|
||||
case 'TileMapLayer':
|
||||
var objects = layer.getElementsByTagName('Objects')[0];
|
||||
var layerObjects = [];
|
||||
if (objects) {
|
||||
for (var i = 0; i < objects.childNodes.length; ++i) {
|
||||
var object = objects.childNodes[i];
|
||||
if (object.nodeType != 1) {
|
||||
continue;
|
||||
}
|
||||
var obj = that.getObjectFromAttributes(objects.childNodes[i].attributes);
|
||||
obj.__type = object.nodeName;
|
||||
layerObjects.push(obj);
|
||||
}
|
||||
}
|
||||
var rows = layer.getElementsByTagName('Row');
|
||||
var i = 0;
|
||||
var grid = [];
|
||||
for (var y = 0; y < that.height; ++y) {
|
||||
grid[y] = [];
|
||||
var row = rows[i++].textContent.split(', ');
|
||||
var j = 0;
|
||||
for (var x = 0; x < that.width; ++x) {
|
||||
grid[y][x] = (row[j++] - 0) || 0;
|
||||
}
|
||||
}
|
||||
var layerAttributes = that.getObjectFromAttributes(layer.attributes);
|
||||
layerAttributes.type = 'tilemaplayer';
|
||||
layerAttributes.objects = layerObjects;
|
||||
layerAttributes.grid = grid;
|
||||
that.layers[layerAttributes.id] = layerAttributes;
|
||||
that.nextLayer = Math.max(that.nextLayer, parseInt(layerAttributes.id) + 1);
|
||||
that.addTilemapLayer(layerAttributes.id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
that.updateLayerList();
|
||||
return false;
|
||||
}
|
||||
|
||||
that.unloadLevel = function() {
|
||||
that.currentTile = 0;
|
||||
that.tilePainting = false;
|
||||
that.erasing = false;
|
||||
that.tiles = {};
|
||||
that.layers = {};
|
||||
that.currentLayer = 0;
|
||||
that.nextLayer = 1;
|
||||
|
||||
that.setLevelInfo(that.defaultLevel);
|
||||
|
||||
document.getElementById('tiles').innerHTML = '';
|
||||
that.editor.innerHTML = '';
|
||||
that.updateLayerList();
|
||||
|
||||
document.getElementById('level_filename').value = '';
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
that.saveLevel = function() {
|
||||
var xml = '';
|
||||
xml += '<?xml version="1.0" ?>\n';
|
||||
xml += '<Level' + that.getAttributesFromObject(that.level) + '> \n';
|
||||
xml += ' <Layers>\n';
|
||||
for (var i in that.layers) {
|
||||
var layer = that.layers[i];
|
||||
switch (layer.type) {
|
||||
case 'imagelayer':
|
||||
xml += ' <ImageLayer' + that.getAttributesFromObject(layer, ['type']) + ' />\n';
|
||||
break;
|
||||
case 'tilemaplayer':
|
||||
xml += ' <TileMapLayer' + that.getAttributesFromObject(layer, ['grid', 'objects', 'type']) + '>\n';
|
||||
xml += ' <Objects>\n';
|
||||
for (var i in layer.objects) {
|
||||
var obj = layer.objects[i];
|
||||
xml += ' <' + obj.__type + that.getAttributesFromObject(obj, ['__type']) + ' />\n';
|
||||
}
|
||||
xml += ' </Objects>\n';
|
||||
for (var y = 0; y < that.height; y++) {
|
||||
xml += ' <Row>' + layer.grid[y].join(', ') + '</Row>\n';
|
||||
}
|
||||
xml += ' </TileMapLayer>\n';
|
||||
break;
|
||||
}
|
||||
}
|
||||
xml += ' </Layers>\n';
|
||||
xml += '</Level>\n';
|
||||
|
||||
var win = window.open('about:blank', 'rollmorad level editor output', '');
|
||||
win.document.open('text/xml');
|
||||
win.document.write(xml);
|
||||
win.document.close();
|
||||
}
|
||||
|
||||
that.getObjectFromAttributes = function(attributes) {
|
||||
var obj = {};
|
||||
for (var i = 0; i < attributes.length; ++i) {
|
||||
obj[attributes[i].nodeName] = attributes[i].value;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
that.getAttributesFromObject = function(object, exclude) {
|
||||
var exc = {}
|
||||
exclude = exclude || [];
|
||||
for (var i = 0; i < exclude.length; ++i) {
|
||||
exc[exclude[i]] = true;
|
||||
}
|
||||
var attributes = '';
|
||||
for (var z in object) {
|
||||
if (exc[z] || object[z] === '' || typeof object[z] == undefined) {
|
||||
continue;
|
||||
}
|
||||
attributes += ' ' + z + '="' + object[z] + '"';
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
|
||||
that.toggle2 = function(id) {
|
||||
// return that.toggle(id)
|
||||
var elem = document.getElementById(id)
|
||||
if (!elem) return
|
||||
if (elem.style.MozOpacity != 0.5) elem.style.MozOpacity = 0.5
|
||||
else elem.style.MozOpacity = 1.0
|
||||
if (elem.style.zIndex != 10) elem.style.zIndex = 10
|
||||
else elem.style.zIndex = 100
|
||||
return false
|
||||
}
|
||||
|
||||
that.toggle = function(id) {
|
||||
var elem = document.getElementById(id);
|
||||
if (!elem) {
|
||||
return;
|
||||
}
|
||||
if (elem.style.display != 'none') {
|
||||
elem.style.display = 'none';
|
||||
} else {
|
||||
elem.style.display = '';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
that.startTilePainting = function(event) {
|
||||
if (event.button == 2) {
|
||||
that.erasing = true;
|
||||
} else {
|
||||
that.tilePainting = true;
|
||||
}
|
||||
}
|
||||
|
||||
that.stopTilePainting = function(event) {
|
||||
that.tilePainting = false;
|
||||
that.erasing = false;
|
||||
af_Events.stopEvent(event);
|
||||
return false;
|
||||
}
|
||||
|
||||
af_Events.addEventListener(window, 'mousedown', that.startTilePainting);
|
||||
af_Events.addEventListener(window, 'mouseup', that.stopTilePainting);
|
||||
that.createLevelForm();
|
||||
that.setLevelInfo(that.defaultLevel);
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
af_DragNDrop = function() {
|
||||
|
||||
var that = this;
|
||||
|
||||
// offset inside clicked element
|
||||
that.mouseOffset = {};
|
||||
// all drop targets
|
||||
that.dropTargets = {};
|
||||
|
||||
// container which is actually being moved around
|
||||
that.dragContainer = null;
|
||||
// element that is currently being dragged
|
||||
that.currentlyDragging = null;
|
||||
// drag-Id
|
||||
that.currentId = '';
|
||||
// dragging already initialized?
|
||||
that.draggingInitialized = false;
|
||||
// position, where we started dragging
|
||||
that.startPosition = {};
|
||||
|
||||
that.dragRegex = /\bdrag_(.*?)\b/;
|
||||
that.dropRegex = /\bdrop_(.*?)\b/;
|
||||
// @TODO: maybe this can be replaced by manually setting the regex.global flag?
|
||||
that.dropRegexG = /\bdrop_(.*?)\b/g;
|
||||
|
||||
that.load = function() {
|
||||
|
||||
// create drag container
|
||||
that.dragContainer = document.createElement('div');
|
||||
that.dragContainer.className = 'dragcontainer';
|
||||
// better solution for this?
|
||||
document.getElementsByTagName('body')[0].appendChild(that.dragContainer);
|
||||
|
||||
// find draggable elements
|
||||
var elements = af_CSS.getElementsByClass(that.dragRegex);
|
||||
for (var i = 0; i < elements.length; ++i) {
|
||||
af_Events.addEventListener(elements[i], 'mousedown', that.startDrag);
|
||||
af_Events.addEventListener(elements[i], 'click', that.interceptClick);
|
||||
// af_Events.addEventListener(elements[i], 'click', function(event) {alert('Clicked!'); });
|
||||
}
|
||||
|
||||
// find drop targets
|
||||
var elements = af_CSS.getElementsByClass(that.dropRegex);
|
||||
var match;
|
||||
for (var i = 0; i < elements.length; ++i) {
|
||||
// an elment can serve as a drop target for differend IDs
|
||||
while (match = that.dropRegexG.exec(elements[i].className)) {
|
||||
var id = match[1];
|
||||
that.dropTargets[id] = that.dropTargets[id] || new Array();
|
||||
that.dropTargets[id].push(elements[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
that.startDrag = function(event) {
|
||||
event = event || window.event;
|
||||
|
||||
var mpos = af_Events.getMousePosition(event);
|
||||
var epos = af_CSS.getPosition(this);
|
||||
|
||||
// record mouse offset
|
||||
that.mouseOffset = {
|
||||
x: mpos.x - epos.x,
|
||||
y: mpos.y - epos.y
|
||||
}
|
||||
|
||||
that.startPosition = mpos;
|
||||
that.currentlyDragging = this;
|
||||
that.draggingInitialized = false;
|
||||
|
||||
af_Events.stopEvent(event);
|
||||
return false;
|
||||
}
|
||||
|
||||
that.initDrag = function(event) {
|
||||
|
||||
// find drag id
|
||||
var match = that.dragRegex.exec(that.currentlyDragging.className);
|
||||
if (!match || !match[1]) {
|
||||
return false;
|
||||
}
|
||||
that.currentId = match[1];
|
||||
|
||||
// are there any drop targets?
|
||||
if (!that.dropTargets[that.currentId]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// highlight drop targets
|
||||
for (var i = 0; i < that.dropTargets[that.currentId].length; ++i) {
|
||||
af_CSS.addClass(that.dropTargets[that.currentId][i], 'active_' + that.currentId);
|
||||
}
|
||||
|
||||
var mpos = af_Events.getMousePosition(event);
|
||||
|
||||
// prepare drag container
|
||||
that.dragContainer.innerHTML = '';
|
||||
that.dragContainer.style.top = mpos.y - that.mouseOffset.y + 'px';
|
||||
that.dragContainer.style.left = mpos.x - that.mouseOffset.x + 'px';
|
||||
// copy element into drag container
|
||||
var clone = that.currentlyDragging.cloneNode(true)
|
||||
var dims = af_CSS.getDimensions(that.currentlyDragging);
|
||||
clone.style.width = dims.width + 'px';
|
||||
clone.style.height = dims.height + 'px';
|
||||
that.dragContainer.appendChild(clone);
|
||||
that.dragContainer.style.display = 'block';
|
||||
// mark element as being dragged
|
||||
af_CSS.addClass(that.currentlyDragging, 'dragging');
|
||||
that.draggingInitialized = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
that.runDrag = function(event) {
|
||||
if (!that.currentlyDragging) {
|
||||
return;
|
||||
}
|
||||
event = event || window.event;
|
||||
|
||||
if (!that.draggingInitialized) {
|
||||
// first mouse move, set up dragging
|
||||
if (!that.initDrag(event)) {
|
||||
af_Events.stopEvent(event);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var mpos = af_Events.getMousePosition(event);
|
||||
|
||||
// move drag container
|
||||
that.dragContainer.style.left = (mpos.x - that.mouseOffset.x) + 'px';
|
||||
that.dragContainer.style.top = (mpos.y - that.mouseOffset.y) + 'px';
|
||||
|
||||
var dropTarget = null;
|
||||
for (var i = 0; i < that.dropTargets[that.currentId].length; ++i) {
|
||||
if (
|
||||
that.dropTargets[that.currentId][i] != that.currentlyDragging &&
|
||||
that.testBoundingBox(that.getBoundingBox(that.dropTargets[that.currentId][i]), mpos)
|
||||
) {
|
||||
af_CSS.addClass(that.dropTargets[that.currentId][i], 'hover_' + that.currentId);
|
||||
} else {
|
||||
af_CSS.removeClass(that.dropTargets[that.currentId][i], 'hover_' + that.currentId);
|
||||
}
|
||||
}
|
||||
|
||||
// required for Internet Explorer:
|
||||
return false;
|
||||
}
|
||||
|
||||
that.endDrag = function(event) {
|
||||
if (!that.draggingInitialized) {
|
||||
that.currentlyDragging = null;
|
||||
}
|
||||
if (!that.currentlyDragging) {
|
||||
return;
|
||||
}
|
||||
event = event || window.event;
|
||||
|
||||
// find drop target
|
||||
if (!that.dropTargets[that.currentId]) {
|
||||
return;
|
||||
}
|
||||
var dropTarget = null;
|
||||
var mpos = af_Events.getMousePosition(event);
|
||||
for (var i = 0; i < that.dropTargets[that.currentId].length; ++i) {
|
||||
if (that.testBoundingBox(that.getBoundingBox(that.dropTargets[that.currentId][i]), mpos)) {
|
||||
dropTarget = that.dropTargets[that.currentId][i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// reset highlighted drop targets
|
||||
for (var i = 0; i < that.dropTargets[that.currentId].length; ++i) {
|
||||
af_CSS.removeClass(that.dropTargets[that.currentId][i], 'active_' + that.currentId);
|
||||
af_CSS.removeClass(that.dropTargets[that.currentId][i], 'hover_' + that.currentId);
|
||||
}
|
||||
|
||||
// backup element
|
||||
var element = that.currentlyDragging;
|
||||
|
||||
// stop dragging
|
||||
af_CSS.removeClass(that.currentlyDragging, 'dragging');
|
||||
that.currentlyDragging = null;
|
||||
that.dragContainer.style.display = 'none';
|
||||
that.dragContainer.style.top = 0;
|
||||
that.dragContainer.style.left = 0;
|
||||
that.dragContainer.innerHTML = '';
|
||||
|
||||
af_Events.stopEvent(event);
|
||||
|
||||
if (dropTarget && that['drop' + that.currentId]) {
|
||||
return that['drop' + that.currentId](element, dropTarget);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// intercepts clicks if mouse has moved
|
||||
that.interceptClick = function(event) {
|
||||
event = event || window.event;
|
||||
var mpos = af_Events.getMousePosition(event);
|
||||
if (mpos.x != that.startPosition.x || mpos.y != that.startPosition.y) {
|
||||
// mouse was moved => dragging took place => intercept click
|
||||
af_Events.stopEvent(event);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
that.getBoundingBox = function(element) {
|
||||
var coords = af_CSS.getPosition(element);
|
||||
var dimensions = af_CSS.getDimensions(element);
|
||||
return {
|
||||
xMin: coords.x,
|
||||
yMin: coords.y,
|
||||
xMax: coords.x + dimensions.width,
|
||||
yMax: coords.y + dimensions.height
|
||||
}
|
||||
}
|
||||
|
||||
that.testBoundingBox = function(bbox, mpos) {
|
||||
return (
|
||||
mpos.x > bbox.xMin &&
|
||||
mpos.x < bbox.xMax &&
|
||||
mpos.y > bbox.yMin &&
|
||||
mpos.y < bbox.yMax
|
||||
);
|
||||
}
|
||||
|
||||
af_Events.addOnEvent(window, 'load', that.load);
|
||||
af_Events.addEventListener(document, 'mousemove', that.runDrag);
|
||||
af_Events.addEventListener(document, 'mouseup', that.endDrag);
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
function af_var_dump(obj) {
|
||||
var str = typeof(obj) + '\n';
|
||||
for (x in obj) {
|
||||
str += x + ' = ' + obj[x] + '\n';
|
||||
}
|
||||
return str;
|
||||
}
|
||||
af_CSS = {
|
||||
addClass: function(element, className) {
|
||||
element.className += ' ' + className;
|
||||
},
|
||||
|
||||
removeClass: function(element, className) {
|
||||
if (!element || !element.className) {
|
||||
return;
|
||||
}
|
||||
var classes = element.className.split(' ');
|
||||
var newclasses = new Array();
|
||||
for (var i = 0; i < classes.length; ++i) {
|
||||
if (classes[i] != className) {
|
||||
newclasses.push(classes[i]);
|
||||
}
|
||||
}
|
||||
element.className = newclasses.join(' ');
|
||||
},
|
||||
|
||||
getElementsByClass: function(pattern, node, tag) {
|
||||
node = node || document;
|
||||
tag = tag || '*';
|
||||
|
||||
var nodes = new Array();
|
||||
var elements = node.getElementsByTagName(tag);
|
||||
for (var i = 0; i < elements.length; ++i) {
|
||||
if (pattern.test(elements[i].className)) {
|
||||
nodes.push(elements[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return nodes;
|
||||
},
|
||||
|
||||
getPosition: function(element) {
|
||||
var coords = {x:0, y:0};
|
||||
var e = element;
|
||||
do {
|
||||
coords.x += e.offsetLeft;
|
||||
coords.y += e.offsetTop;
|
||||
e = e.offsetParent;
|
||||
} while (e && e.offsetParent)
|
||||
|
||||
return coords;
|
||||
},
|
||||
|
||||
getDimensions: function(element, includeBorder) {
|
||||
if (includeBorder) {
|
||||
return {width:element.offsetWidth, height:element.offsetHeight};
|
||||
} else {
|
||||
// @TODO: check IE compatibility
|
||||
return {width:element.clientWidth, height:element.clientHeight};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
af_Events = {
|
||||
|
||||
addEventListener: function(element, event, handler, capture) {
|
||||
if (element.addEventListener) {
|
||||
element.addEventListener(event, handler, false);
|
||||
return;
|
||||
}
|
||||
if (element.attachEvent) {
|
||||
// @TODO: find a cleaner solution
|
||||
var mname = '_____on'+event;
|
||||
element[mname] = handler;
|
||||
element.attachEvent('on' + event, function(event) { return element[mname](event); });
|
||||
}
|
||||
},
|
||||
|
||||
removeEventListener: function(element, event, handler) {
|
||||
if (element.removeEventListener) {
|
||||
element.removeEventListener(event, handler, false);
|
||||
return;
|
||||
}
|
||||
if (element.detachEvent) {
|
||||
// @TODO: remove handler from element
|
||||
element.detachEvent('on' + event, handler);
|
||||
}
|
||||
},
|
||||
|
||||
addOnEvent: function(element, event, handler) {
|
||||
event = 'on' + event;
|
||||
var tmp = element[event];
|
||||
if (typeof tmp != 'function') {
|
||||
element[event] = handler;
|
||||
} else {
|
||||
element[event] = function(e) {
|
||||
if (tmp) {
|
||||
tmp(e);
|
||||
}
|
||||
handler(e);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
stopEvent: function(event) {
|
||||
if (typeof window.event != 'undefined') {
|
||||
window.event.cancelBubble = true;
|
||||
window.event.returnValue = false;
|
||||
} else {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
},
|
||||
|
||||
getMousePosition: function(event) {
|
||||
if (event.pageX || event.pageY) {
|
||||
return {x: event.pageX, y:event.pageY};
|
||||
}
|
||||
return {
|
||||
x: event.clientX + document.body.scrollLeft - document.body.clientLeft,
|
||||
y: event.clientY + document.body.scrollTop - document.body.clientTop
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function af_AJAX() {
|
||||
|
||||
var that = this;
|
||||
|
||||
that.enabled = true;
|
||||
|
||||
if (typeof XMLHttpRequest == 'undefined') {
|
||||
try {
|
||||
XMLHttpRequest = function() {
|
||||
return new ActiveXObject('Microsoft.XMLHTTP');
|
||||
}
|
||||
} catch (msex) {}
|
||||
}
|
||||
|
||||
if (typeof XMLHttpRequest == 'undefined') {
|
||||
that.enabled = false;
|
||||
}
|
||||
|
||||
that.getSync = function(url) {
|
||||
req = new XMLHttpRequest();
|
||||
req.open('GET', url, false);
|
||||
req.send(null);
|
||||
return req;
|
||||
}
|
||||
|
||||
that.getAsync = function(url, callback) {
|
||||
req = new XMLHttpRequest();
|
||||
req.open('GET', url);
|
||||
req.onreadystatechange = function() {
|
||||
if (req.readyState == 4) {
|
||||
callback(req);
|
||||
}
|
||||
}
|
||||
req.send(null);
|
||||
}
|
||||
|
||||
that.postSync = function(url, data) {
|
||||
req = new XMLHttpRequest();
|
||||
req.open('POST', url, false);
|
||||
var encodedData = that.urlencode(data);
|
||||
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
req.setRequestHeader("Content-length", encodedData.length);
|
||||
req.setRequestHeader("Connection", "close");
|
||||
req.send(encodedData);
|
||||
return req;
|
||||
}
|
||||
|
||||
that.postAsync = function(url, data, callback) {
|
||||
req = new XMLHttpRequest();
|
||||
req.open('POST', url);
|
||||
req.onreadystatechange = function() {
|
||||
if (req.readyState == 4) {
|
||||
callback(req);
|
||||
}
|
||||
}
|
||||
req.send(that.urlencode(data));
|
||||
}
|
||||
|
||||
that.urlencode = function(data) {
|
||||
encodedData = new Array();
|
||||
for (i in data) {
|
||||
encodedData.push(i + '=' + encodeURIComponent(data[i]));
|
||||
}
|
||||
return encodedData.join('&');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
@CHARSET "UTF-8";
|
||||
html, body { margin: 0; padding: 0; border: none; height: 100%; width: 100%; font-family: sans-serif; font-size: x-small; }
|
||||
h1 { width: 100%; height: 36pt; font-size: 16pt; margin: 0 0 -0.5em 0; padding: 0.5em 0 0 0; font-family: 'Trebuchet MS', sans-serif; text-align: center; color: #33f; }
|
||||
h1 span { color: #f0f; }
|
||||
h1 sup { font-size: 8pt; color: #ccc; font-weight: bold; }
|
||||
a { color: #33f; }
|
||||
input, button { font-size: 100%; }
|
||||
#editor { width: 80%; height: 90%; float: left; overflow: auto; background: transparent; position: relative; }
|
||||
#editor .layer { position: absolute; top: 0; left: 0; }
|
||||
#editor .layer table td div { border: 1px #ccc solid; position: relative; overflow: hidden; }
|
||||
#editor .layer table td div img { position: absolute; }
|
||||
#menu { width: 20%; height: 90%; float: left; overflow: auto; }
|
||||
#menu a.toggle { display: block; background: #ccc; outline: none; text-decoration: none; padding: 0.1em; }
|
||||
#menu #tiles div { width: 64px; height: 64px; border: 2px #000 solid; margin: 5px; }
|
||||
#statusbar { width: 100%; position: absolute; bottom: 0; background: #ccc; }
|
||||
@@ -0,0 +1,7 @@
|
||||
Tiles in Tile-Auswahl kleiner machen
|
||||
|
||||
???
|
||||
zoom: td div größe ändern td div img größe und offset ändern=======
|
||||
|
||||
Vorschlag:
|
||||
Gamemodes über Checkboxen
|
||||
Binary file not shown.
@@ -0,0 +1,31 @@
|
||||
@echo off
|
||||
|
||||
IF [%1] == [] GOTO datei
|
||||
|
||||
echo =================================================
|
||||
echo los gehts
|
||||
echo =================================================
|
||||
echo.
|
||||
|
||||
set pfad=%~dp0
|
||||
cd %pfad%
|
||||
|
||||
java -jar Mirror.jar -in=%1 -l -f
|
||||
|
||||
echo.
|
||||
echo =================================================
|
||||
echo wenn keine Exceptions kamen, sind wir fertig :D
|
||||
echo =================================================
|
||||
echo.
|
||||
|
||||
GOTO ende
|
||||
|
||||
|
||||
:datei
|
||||
echo ziehe eine Level-Datei auf diese Datei, um sie automatisch zu spiegeln
|
||||
|
||||
|
||||
:ende
|
||||
pause
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Tiles>
|
||||
<Tile id="0">0</Tile>
|
||||
<Tile id="1">3</Tile>
|
||||
<Tile id="2">2</Tile>
|
||||
<Tile id="3">1</Tile>
|
||||
<Tile id="4">6</Tile>
|
||||
<Tile id="5">5</Tile>
|
||||
<Tile id="6">4</Tile>
|
||||
<Tile id="7">9</Tile>
|
||||
<Tile id="8">8</Tile>
|
||||
<Tile id="9">7</Tile>
|
||||
<Tile id="10">14</Tile>
|
||||
<Tile id="11">15</Tile>
|
||||
<Tile id="12">24</Tile>
|
||||
<Tile id="13">25</Tile>
|
||||
<Tile id="14">10</Tile>
|
||||
<Tile id="15">11</Tile>
|
||||
<Tile id="16">20</Tile>
|
||||
<Tile id="17">21</Tile>
|
||||
<Tile id="18">22</Tile>
|
||||
<Tile id="19">23</Tile>
|
||||
<Tile id="20">16</Tile>
|
||||
<Tile id="21">17</Tile>
|
||||
<Tile id="22">18</Tile>
|
||||
<Tile id="23">19</Tile>
|
||||
<Tile id="24">12</Tile>
|
||||
<Tile id="25">13</Tile>
|
||||
<Tile id="101">103</Tile>
|
||||
<Tile id="102">102</Tile>
|
||||
<Tile id="103">101</Tile>
|
||||
<Tile id="104">106</Tile>
|
||||
<Tile id="105">105</Tile>
|
||||
<Tile id="106">104</Tile>
|
||||
<Tile id="107">109</Tile>
|
||||
<Tile id="108">108</Tile>
|
||||
<Tile id="109">107</Tile>
|
||||
<Tile id="200">200</Tile>
|
||||
<Tile id="201">201</Tile>
|
||||
<Tile id="202">202</Tile>
|
||||
<Tile id="300">301</Tile>
|
||||
<Tile id="301">300</Tile>
|
||||
<Tile id="302">303</Tile>
|
||||
<Tile id="303">302</Tile>
|
||||
<Tile id="304">304</Tile>
|
||||
<Tile id="305">307</Tile>
|
||||
<Tile id="306">308</Tile>
|
||||
<Tile id="307">305</Tile>
|
||||
<Tile id="308">306</Tile>
|
||||
<Tile id="309">311</Tile>
|
||||
<Tile id="310">312</Tile>
|
||||
<Tile id="311">309</Tile>
|
||||
<Tile id="312">310</Tile>
|
||||
<Tile id="313">315</Tile>
|
||||
<Tile id="314">316</Tile>
|
||||
<Tile id="315">313</Tile>
|
||||
<Tile id="316">314</Tile>
|
||||
<Tile id="317">319</Tile>
|
||||
<Tile id="318">320</Tile>
|
||||
<Tile id="319">317</Tile>
|
||||
<Tile id="320">318</Tile>
|
||||
</Tiles>
|
||||
|
||||
@@ -0,0 +1,340 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
@@ -0,0 +1,9 @@
|
||||
Description:
|
||||
png2ico converts .PNG files to Windows .ICO icon resources
|
||||
|
||||
Homepage:
|
||||
http://www.winterdrache.de/freeware (in the Utilities section)
|
||||
|
||||
Maintainer:
|
||||
Matthias S. Benkmann <matthias@winterdrache.de>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#define version "png2ico 2002-12-08 (c) Matthias S. Benkmann"
|
||||
@@ -0,0 +1,119 @@
|
||||
png2ico(1) png2ico(1)
|
||||
|
||||
|
||||
|
||||
NAME
|
||||
png2ico - convert .PNG file(s) to Windows .ICO icon
|
||||
resource
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
png2ico outfile.ico [--colors <num>] infile1.png
|
||||
[infile2.png ...]
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
png2ico takes the input files and stores them in the out
|
||||
put file as a Windows icon resource. Usually the input
|
||||
files would all represent the same image in different res
|
||||
olutions (common resolutions are 16x16, 32x32 and 64x64).
|
||||
A program reading the icon resource will pick the image
|
||||
closest to its desired resolution and will then scale it
|
||||
if necessary.
|
||||
|
||||
Using the parameter --colors you can specify the number of
|
||||
colors to use for the images that follow --colors on the
|
||||
command line. Allowed values are 2, 16 and 256. If omit
|
||||
ted, 256 colors will be used. --colors can be specified
|
||||
multiple times to store images with different numbers of
|
||||
colors in the same icon file. If the source image has more
|
||||
than the specified number of colors, color reduction will
|
||||
be performed.
|
||||
|
||||
|
||||
FAVICON.ICO
|
||||
Most graphical browsers today support the favicon.ico
|
||||
file. When a user bookmarks a web page, the browser will
|
||||
automatically check if it finds a favicon.ico file on the
|
||||
web server and display it in the bookmarks menu. Depend
|
||||
ing on the browser and configuration the favicon.ico may
|
||||
also appear in other places.
|
||||
|
||||
To create a favicon.ico simply create a 16x16 .PNG file
|
||||
and convert it to an icon resource with png2ico. You may
|
||||
of course add other alternative resolutions but most
|
||||
browsers only use a 16x16 image. Keep in mind that for a
|
||||
user with a slow modem a favicon.ico may increase the page
|
||||
loading time by a few seconds if it is too large, so don't
|
||||
overdo it. Adding a 32x32 alternative should be enough to
|
||||
make sure the image will look good even in contexts with
|
||||
larger icons. Adding even more and larger alternatives is
|
||||
unnecessary bloat. Try to keep the number of colors below
|
||||
16 and create a 16-color icon using the --colors 16 switch
|
||||
of png2ico (or even create a b/w icon using the --colors 2
|
||||
switch). This will result in a smaller file that loads
|
||||
faster.
|
||||
|
||||
Don't forget that the favicon.ico may be composed against
|
||||
backgrounds of different colors so you should use trans
|
||||
parency rather than a solid background if you want to
|
||||
avoid that your icon appears inside a box.
|
||||
|
||||
To add your new favicon.ico to a web page put it on the
|
||||
server into the same directory as the web page. That is
|
||||
the 1st place a browser will look. If it doesn't find an
|
||||
icon there, it checks the top-level directory of the web
|
||||
server, so by putting it there you can have a default
|
||||
favicon for all the pages in your domain. Depending on
|
||||
browser and configuration, the favicon.ico is not always
|
||||
rendered, even if it is in one of the above locations,
|
||||
unless the web page explicitly declares its presence. To
|
||||
declare that your web page has an icon, you add the fol
|
||||
lowing 2 lines into the <head> section of your page:
|
||||
|
||||
<link rel="icon" href="favicon.ico"
|
||||
type="image/x-icon">
|
||||
|
||||
<link rel="shortcut icon" href="favicon.ico"
|
||||
type="image/x-icon">
|
||||
|
||||
|
||||
EXAMPLES
|
||||
To create a favicon.ico from 2 logo files (the 1st in
|
||||
16x16 resolution and the 2nd in 32x32 resolution) you
|
||||
could use the following command:
|
||||
|
||||
png2ico favicon.ico logo16x16.png logo32x32.png
|
||||
|
||||
|
||||
BUGS
|
||||
The color reduction algorithm used by png2ico is very
|
||||
slow. If you have an input file with several thousand col
|
||||
ors (very unlikely), it may take several seconds to create
|
||||
the icon. If possible, reduce the number of colors in your
|
||||
.PNG files before passing them to png2ico.
|
||||
|
||||
The handling of the transparency mask is very inconsistent
|
||||
in programs. The same program will sometimes interpret it
|
||||
differently depending on context. png2ico takes precau
|
||||
tions to make sure that the icon will always look the
|
||||
same. For doing this, png2ico uses one palette entry for
|
||||
black (0,0,0) and one palette entry for white
|
||||
(255,255,255), even if the icon does not have a single
|
||||
black or white pixel. This means that 2-color icons will
|
||||
always be black and white. In 16/256-color icons, only
|
||||
14/254 colors can be chosen freely.
|
||||
|
||||
|
||||
AUTHOR
|
||||
Matthias S. Benkmann <matthias@winterdrache.de>.
|
||||
|
||||
png2ico lives at http://www.winterdrache.de/freeware
|
||||
|
||||
|
||||
SEE ALSO
|
||||
convert(1), gimp(1)
|
||||
|
||||
|
||||
|
||||
1 June 2002 png2ico(1)
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
pngopt.exe ..\..\data\fonts\*.png
|
||||
pngopt.exe ..\..\data\sprites\*.png
|
||||
pngopt.exe ..\..\data\tilesets\*.png
|
||||
Binary file not shown.
Reference in New Issue
Block a user