Right now you can't customize your own tile layout. You have to use either type 0(pics1), which is very unorganized(and harder to organize tiles in) and cluttered, or type 1('era'), which wastes so much space on tile types you might not even use. There's no way to balance out tiles the way YOU want. I thought I'd experiment a little and see what I could make.
Originally I want to do it all serverside -- it's much more secure and automatic that way. You upload the template to your server, and use an RC command like /npc update tiledefs. TADA. However, there's no functions on the serverside to interpret image pixels... so I had to do it all clientside. This means the functions would have to be called by designated staff to update the tile data, and the image has to be downloaded. This is not what I desired, but there's a reason this is called an experiment.
Anyways, here's the process:
1) Take this key and use it! It contains the color values that my script processes. Make sure you eyedropper these colors!

2) Now you can either take two roads: The fullscale road, which is taking a fullscale tileset template and working with it there, or the smallscale. Fullscale each tile represents its 16x16 scale in game. Make sure you stick to this grid or it will mess up! Color the tiles with the key above for each type you want it to represent. Here is a fullscale representation of pics1 with my color format:

3) If you did it fullscale, you'll need to shrink it so each tile ends up as one pixel(way smaller filesize, and easier to read data from). You can't do this successfully with MSPaint. You'll have to use another program that lets you input specific resize numbers, and where you can disable filtering(needs to be nearest neighbor!). The desired size is 128x32. Now, you can skip this whole process by editing it on the single pixel level instead of resizing the larger one. The large template is just there to make visualization easier. You should end up with something like this:

This is the good stuff. Upload this onto your server where it's downloadable(aka where most image files go). Alternatively, you can just place it in your Graal folder and delete FILENAMECACHE.txt. This will cache it in your Graal folder, making scripts able to read the data. This can be more secure if you're the only person who needs to generate the tile data.
Here is the core script. You can place this in a weapon like -TileData or something. Add it to yourself. On creation, or whenever it's updated/you log on, it will go through the tile data and upload it to a serverr.var. This is not good, but not much is how I desired and this is only for display purposes right now. Replace the this.templateimage var with the image of your template.
PHP Code:
function onActionServerside(cmd) {
if (cmd == "SendTileData") serverr.tiledefs = params[1];
}
//#CLIENTSIDE
function onCreated() {
this.templateimage = "dusty_tiletemplate.png";
Tiles = this;
onTimeout();
}
function onTimeout() {
if (getimgheight("dusty_tiletemplate.png") <= 0) {
showimg(200,"dusty_tiletemplate.png",-1,-1);
changeimgpart(200,0,0,1,1);
setTimer(.1);
} else GetTileDefs();
}
public function GetTileDefs() {
temp.w = getimgwidth(this.templateimage);
temp.h = getimgheight(this.templateimage);
temp.defvalues = {
1.19 , // Type 0, nonblocking
null ,
"2.00", // Type 2, hurting underground
1.29 , // Type 3, chair
2.48 , // Type 4, bed upper
2.74 , // Type 5, bed lower
0.86 , // Type 6, swamp
0.38 , // Type 7, lava swamp
1.64 , // Type 8, shallow water
"1.03", // Type 9, shallow lava
null ,
1.25 , // Type 11, water
"1.00", // Type 12, lava
null,null,null,null,null,null,null,
"0.90", // Type 20, fence(throw-through)
"1.80", // Type 21, platform(for jumping)
0.48 , // Type 22, blocking
};
temp.tiledefs = new[23];
for (temp.i;i<w*h;i++) {
temp.cx = i%w;
temp.cy = int(i/w);
temp.pix = getimgpixel(this.templateimage,cx,cy);
temp.pix = (pix[0]+pix[1]+pix[2]).substring(0,4);
temp.tiletype = defvalues.index(pix);
temp.tile = ((cx%16)+(int(cx/16)*512))+((cy*16)%512);
temp.tiledefs[tiletype].add(tile);
}
TriggerServer("gui",this.name,"SendTileData",tiledefs);
// Color values for tiles, cropped down to the x.xx
// 0 nonblocking : 1.192156862
// 2 hurting underground : 2
// 3 chair : 1.290196078
// 4 bed upper side : 2.482352941
// 5 bed lower side : 2.749019607
// 6 swamp : 0.866666666
// 7 lava swamp : 0.388235294
// 8 near water : 1.647058823
// 9 near lava : 1.035294117
// 11 water : 1.258823529
// 12 lava : 1
// 20 throw-through (fences) : 0.901960784
// 21 jumping stone : 1.803921568
// 22 blocking tile : 0.482352941
}
public function onBlocking(cx,cy) {
temp.t = tiles[cx,cy];
if (t in serverr.tiledefs[4] ||
t in serverr.tiledefs[20] ||
t in serverr.tiledefs[21] ||
t in serverr.tiledefs[22]) return true;
else return false;
}
public function onBlocking2(cx,cy,w,h) {
w++; h++;
temp.foundtile = false;
for (temp.i=0;i<w*h;i++) {
temp.tx = (cx+(i%w)) - ((i%w)+1 == w ? 1/16 : 0);
temp.ty = (cy+(int(i/w))) - (int(i/w)+1 == h ? 1/16 : 0);
temp.t = tiles[tx,ty];
if (t in serverr.tiledefs[4] ||
t in serverr.tiledefs[20] ||
t in serverr.tiledefs[21] ||
t in serverr.tiledefs[22]) {
foundtile = true;
break;
}
}
return foundtile;
}
public function inWater(cx,cy) {
temp.t = tiles[cx,cy];
if (t in serverr.tiledefs[11]) return true;
else return false;
}
public function inWater2(cx,cy,w,h) {
w++; h++;
temp.foundtile = false;
for (temp.i=0;i<w*h;i++) {
temp.tx = (cx+(i%w)) - ((i%w)+1 == w ? 1/16 : 0);
temp.ty = (cy+(int(i/w))) - (int(i/w)+1 == h ? 1/16 : 0);
temp.t = tiles[tx,ty];
if (t in serverr.tiledefs[11]) {
foundtile = true;
break;
}
}
return foundtile;
}
public function onTile(type,cx,cy) {
temp.t = tiles[cx,cy];
if (t in serverr.tiledefs[type]) return true;
else return false;
}
public function onTile2(type,cx,cy,w,h) {
w++; h++;
temp.foundtile = false;
for (temp.i=0;i<w*h;i++) {
temp.tx = (cx+(i%w)) - ((i%w)+1 == w ? 1/16 : 0);
temp.ty = (cy+(int(i/w))) - (int(i/w)+1 == h ? 1/16 : 0);
temp.t = tiles[tx,ty];
if (t in serverr.tiledefs[type]) {
foundtile = true;
break;
}
}
return foundtile;
}
Besides processing the data, it also comes with a few functions that replicate default functions like onwall. These are:
Tiles.onBlocking(x,y) -- returns if there is a blocking tile at the x and y
Tiles.onBlocking2(x,y,width,height) -- returns if there is a blocking tile in the size given at the x and y
Tiles.inWater(x,y) -- Just like the above functions, but with water
Tiles.inWater2(x,y,width,height) --
Tiles.onTile(type,x,y) -- Checks for a specific type of tile at the x and y, as per the default tile types:
0 nonblocking
2 hurting underground
3 chair
4 bed upper side
5 bed lower side
6 swamp
7 lava swamp
8 near water
9 near lava
11 water
12 lava
20 throw-through (fences)
21 jumping stone
22 blocking tile
onTile2(type,x,y,width,height) -- ...
There are pros and cons to this.
Pros:
1) DEFINE YOUR OWN STUFF, MAKE ROOM WHERE YOU WANT IT. Not much more than that, is there?
2) Functions like onTile make some checks more streamlined than default offers.
Cons:
1) Serverside functions did not offer me the tools I needed to make my initial idea; it was much more simplistic and secure in that stage, and felt more like a tool for a server.
2) It's all gscript. That means functions like onBlocking2 are going to be slower than their default counterparts, because they have to loop through the large checks.
3) I couldn't figure an efficient way to store the tile data in a way that's easily accessible to scripts clientside and serverside. It's a lot of data to store, however if it was possible to do it how I wanted from the start I probably would have put a lot more effort into this. Server flags will be more than suitable for my explanations, however.
4) Default tile effects will still happen... swamp tiles will always show swamp images and such. However, you can use type 1 tileset instead if you'd like, or use a custom sprites.png image with those images cropped out. Be careful with things like bush tiles, though this is for custom movement so that shouldn't be a problem(though they will still respawn!).
Here's a small script I threw together to show how it works. It's actually pretty shoddy as I couldn't be assed to put more effort into it:
PHP Code:
//#CLIENTSIDE
function onCreated() {
player.speed = .65;
disabledefmovement();
noplayerkilling();
onTimeout();
}
function onTimeout() {
Movement();
setTimer(0.05);
}
function Movement() {
temp.walking = false;
for (temp.k=0;k<4;k++) {
if (keydown(k)) {
walking = true;
player.dir = k;
temp.newx = player.x + vecx(k)*.65;
temp.newy = player.y + vecy(k)*.65;
temp.hitwall = Tiles.onBlocking2(newx+.5,newy+1,2,2);
if (!hitwall) {
player.x += vecx(k)*player.speed;
player.y += vecy(k)*player.speed;
}
}
}
if (Tiles.inWater(player.x+1.5,player.y+2)) setAni("swim",null);
else if (Tiles.onTile2(3,player.x+1.5,player.y+2,2,2)) setAni("sit",null);
else if (walking == true) setAni("walk",null);
else setAni("idle",null);
}