Graal Forums  

Go Back   Graal Forums > Development Forums > NPC Scripting
FAQ Members List Calendar Today's Posts

 
 
Thread Tools Search this Thread Display Modes
Prev Previous Post   Next Post Next
  #1  
Old 01-08-2010, 09:40 PM
DustyPorViva DustyPorViva is offline
Will work for food. Maybe
DustyPorViva's Avatar
Join Date: Sep 2003
Location: Maryland, USA
Posts: 9,589
DustyPorViva has a reputation beyond reputeDustyPorViva has a reputation beyond reputeDustyPorViva has a reputation beyond reputeDustyPorViva has a reputation beyond reputeDustyPorViva has a reputation beyond reputeDustyPorViva has a reputation beyond reputeDustyPorViva has a reputation beyond reputeDustyPorViva has a reputation beyond reputeDustyPorViva has a reputation beyond reputeDustyPorViva has a reputation beyond reputeDustyPorViva has a reputation beyond repute
Send a message via AIM to DustyPorViva Send a message via MSN to DustyPorViva
An experiment in customizing your own tile definitions

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!
Click image for larger version

Name:	tilesetkey.png
Views:	1394
Size:	2.7 KB
ID:	50196
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:
Click image for larger version

Name:	tilesettemplate.png
Views:	1377
Size:	42.3 KB
ID:	50195
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:
Name:  dusty_tiletemplate.png
Views: 1428
Size:  1.5 KB
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.getimgwidth(this.templateimage);
  
temp.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.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/16 0);
    
temp.ty = (cy+(int(i/w))) - (int(i/w)+== 1/16 0);
    
temp.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.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/16 0);
    
temp.ty = (cy+(int(i/w))) - (int(i/w)+== 1/16 0);
    
temp.tiles[tx,ty];
    if (
t in serverr.tiledefs[11]) {
      
foundtile true;
      break;
    }
  }
  return 
foundtile;
}

public function 
onTile(type,cx,cy) {
  
temp.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/16 0);
    
temp.ty = (cy+(int(i/w))) - (int(i/w)+== 1/16 0);
    
temp.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.vecx(k)*.65;
      
temp.newy player.vecy(k)*.65;
      
temp.hitwall Tiles.onBlocking2(newx+.5,newy+1,2,2);
      if (!
hitwall) {
        
player.+= vecx(k)*player.speed;
        
player.+= 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 == truesetAni("walk",null);
  else 
setAni("idle",null);


Last edited by DustyPorViva; 01-08-2010 at 09:52 PM..
Reply With Quote
 


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 04:23 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2025, vBulletin Solutions Inc.
Copyright (C) 1998-2019 Toonslab All Rights Reserved.