Post your modding questions here

Locked
User avatar
false_chicken
Member
Posts: 53
Joined: Wed Feb 04, 2015 23:41
GitHub: falsechicken
In-game: false_chicken
Location: Florida, USA

Re: Post your modding questions here

by false_chicken » Post

Anonymous_moose wrote:how to make a function happen on punching a node
I am making a mod where when you punch a node, it spawns a monster on it with

Code: Select all

add_entity(pos, "monster")
, changes the time to midnight through

Code: Select all

set_timeofday(0000)
and becomes a different node using

Code: Select all

set_node(pos, "traps:used_monster_portal")
Use callbacks. Idk how to define it for the fists. I suppose you should override them. Something like:

Code: Select all

minetest.override_item(":", { -- I think that is the name fists have. That is the name in the source.
        on_punch = function(pos, node, puncher, pointed_thing)
            -- Do stuff here.
            add_entity(pos, "monster")
            set_timeofday(0000)
            set_node(pos, "traps:used_monster_portal")
        end,	
})
http://dev.minetest.net/minetest.register_node#on_punch

http://dev.minetest.net/minetest.override_item
DISCLAIMER: I am probably wrong.

User avatar
rubenwardy
Moderator
Posts: 6978
Joined: Tue Jun 12, 2012 18:11
GitHub: rubenwardy
IRC: rubenwardy
In-game: rubenwardy
Location: Bristol, United Kingdom
Contact:

Re: Punch node, spawn monster

by rubenwardy » Post

Anonymous_moose wrote:how to make a function happen on punching a node
I am making a mod where when you punch a node, it spawns a monster on it with

Code: Select all

add_entity(pos, "monster")
, changes the time to midnight through

Code: Select all

set_timeofday(0000)
and becomes a different node using

Code: Select all

set_node(pos, "traps:used_monster_portal")

If you're adding a tool, you will want to use the on_use callback of the tool.

Code: Select all

minetest.register_craftitem("asasas:asasas", {
    on_use = function(itemstack, user, pointed_thing)
        if pointed_thing.type == "node" then
            local pos = pointed_thing.above
            -- spawn the monster at 'pos'
        end
    end
})
untested.
Renewed Tab (my browser add-on) | Donate | Mods | Minetest Modding Book

Hello profile reader

User avatar
false_chicken
Member
Posts: 53
Joined: Wed Feb 04, 2015 23:41
GitHub: falsechicken
In-game: false_chicken
Location: Florida, USA

Re: Punch node, spawn monster

by false_chicken » Post

rubenwardy wrote: If you're adding a tool, you will want to use the on_use callback of the tool.

Code: Select all

minetest.register_craftitem("asasas:asasas", {
    on_use = function(itemstack, user, pointed_thing)
        if pointed_thing.type == "node" then
            local pos = pointed_thing.above
            -- spawn the monster at 'pos'
        end
    end
})
untested.
Are the hands considered a tool? I noticed that in the source for minetest_game they are identified by ":". That doesnt seem to follow the normal convention. Why?
DISCLAIMER: I am probably wrong.

User avatar
rubenwardy
Moderator
Posts: 6978
Joined: Tue Jun 12, 2012 18:11
GitHub: rubenwardy
IRC: rubenwardy
In-game: rubenwardy
Location: Bristol, United Kingdom
Contact:

Re: Post your modding questions here

by rubenwardy » Post

If you aren't registering a custom tool/craftitem to spawn it, use minetest.register_on_punch_node instead.
Renewed Tab (my browser add-on) | Donate | Mods | Minetest Modding Book

Hello profile reader

User avatar
Kilarin
Member
Posts: 896
Joined: Mon Mar 10, 2014 00:36
GitHub: Kilarin

Re: Post your modding questions here

by Kilarin » Post

Hello folks! I've got an ore generation question.
So a normal register_ore looks something like this:

Code: Select all

minetest.register_ore({
	ore_type       = "scatter",
	ore            = "default:stone_with_iron",
	wherein        = "default:stone",
	clust_scarcity = 11 * 11 * 11,
	clust_num_ores = 3,
	clust_size     = 2,
	height_min     = -15,
	height_max     = 2,
})
cluster_scarcity indicates how likely the ore is to generate, the smaller the number, the better odds. If I'm understanding correctly, it is generally coded as a cube because the odds are that the ore will show up once in that size of cube?

But, now for the serious question. I would like to make ore generation vary according to your location on the map. By height is obvious, since I can set height min and max and can just register the ore with different scarcity numbers at different heights. BUT, I would like to make ore scarcity vary depending on X and Z coords. For example, I might like to make iron ore more likely to generate the further you get from spawn. The math for this would not be at all difficult, I might use

clust_scarcity = 11 * 11 * 11*(1/(abs(x)+abs(z)+1)) (not necessarily a good formula, but gets the idea across)

But this would depend on two factors:
1: Is the value of clust_scarity calculated once at runtime and never again, in which case this approach wouldn't work at all.

2: IF this approach is valid at all, how would I specify the values of the x and z coords?

Thank you very much for any help in correcting my vast oceans of ignorance about minetest mapgen. :)

User avatar
ExeterDad
Member
Posts: 1717
Joined: Sun Jun 01, 2014 20:00
In-game: ExeterDad
Location: New Hampshire U.S.A

Re: Post your modding questions here

by ExeterDad » Post

Can a entity have multiple sized collision boxes? Like we could do with nodeboxes?
I'm asking because once again I'm wanting to continue with my dinosaur mobs mod. And what is holding me back is the size and shape of the models. I accept that collision boxes can't rotate with the model, but would like if I could make more appropriately sized stacks of boxes rather then a huge cube that covers the whole model.
I've played around with trying to use a list of boxes but have failed. Not sure if I'm doing it wrong or if it's not possible.
If someone could post a example of a collision box list to work with (or confirm it's not possible), it would be greatly appreciated.

User avatar
HeroOfTheWinds
Member
Posts: 470
Joined: Wed Apr 23, 2014 23:16
GitHub: HeroOfTheWinds
IRC: WindHero
Location: Hawaii

Re: Post your modding questions here

by HeroOfTheWinds » Post

Kilarin wrote:*snip*

But, now for the serious question. I would like to make ore generation vary according to your location on the map. By height is obvious, since I can set height min and max and can just register the ore with different scarcity numbers at different heights. BUT, I would like to make ore scarcity vary depending on X and Z coords. For example, I might like to make iron ore more likely to generate the further you get from spawn. The math for this would not be at all difficult, I might use

clust_scarcity = 11 * 11 * 11*(1/(abs(x)+abs(z)+1)) (not necessarily a good formula, but gets the idea across)

But this would depend on two factors:
1: Is the value of clust_scarity calculated once at runtime and never again, in which case this approach wouldn't work at all.

2: IF this approach is valid at all, how would I specify the values of the x and z coords?

Thank you very much for any help in correcting my vast oceans of ignorance about minetest mapgen. :)
Your understanding of how register_ores works is correct.

Sadly, register_ores is calculated only once, when the ores are placed in a global table that the mapgen references... Which means the proposed method would not work.

However, you can make a call to the mapgen Lua Voxel Manipulator (register_on_generated()), and search through every spawned node. Since the LVM is called after the regular mapgen finishes, the ores will already be generated, and all you would need to do is probably call math.random() with a parameter derived from your distance from center. If the random falls in a certain threshold, delete the ore node in question. Just do that for every ore. Sorry if my explanation isn't perfectly clear, I can provide an example if you like.
Nam ex spatio, omnes res venire possunt.
Why let the ground limit you when you can reach for the sky?
Back to college now, yay for sophomore year schedules. :P

User avatar
Kilarin
Member
Posts: 896
Joined: Mon Mar 10, 2014 00:36
GitHub: Kilarin

Re: Post your modding questions here

by Kilarin » Post

HeroOfTheWinds wrote:Sadly, register_ores is calculated only once,
Thats what it looked like. :(
HeroOfTheWinds wrote:Sorry if my explanation isn't perfectly clear, I can provide an example if you like
It was clear, but my ignorance if vast. :)
HeroOfTheWinds wrote:Lua Voxel Manipulator (register_on_generated()), and search through every spawned node. Since the LVM is called after the regular mapgen finishes, the ores will already be generated, and all you would need to do is probably call math.random() with a parameter derived from your distance from center. If the random falls in a certain threshold, delete the ore node in question. Just do that for every ore. .
So, and function set up through register_on_generated runs after each and every node in the world is generated. I would then do my register_ore to set the maximum density I wished. I would need to write my on_generated function so that it checked to see if the current node was an ore that I wanted to vary according to distance from spawn, and if it was, possibly remove it (turn into normal stone) based on a random function, thereby creating increasing scarcity as nodes get closer to spawn. Am I following correctly?

I assume that letting minetest generate the ore and lua remove it would be more efficient then trying to write my own ore generation logic in lua? More efficent and MUCH easier.

What kind of impact would this have on map generation speed, probably not a whole lot?

Am I close to on track? and yes, an example (simple!) would be appreciated. I learn best by looking at examples.

Thank you VERY much for the help!

<edit>
P.S. Oh, and one more question. could the deprecated default.generate_ore do what I want? I suppose it would be a very bad idea to use it in any case. :)

User avatar
HeroOfTheWinds
Member
Posts: 470
Joined: Wed Apr 23, 2014 23:16
GitHub: HeroOfTheWinds
IRC: WindHero
Location: Hawaii

Re: Post your modding questions here

by HeroOfTheWinds » Post

So, and function set up through register_on_generated runs after each and every node in the world is generated. I would then do my register_ore to set the maximum density I wished. I would need to write my on_generated function so that it checked to see if the current node was an ore that I wanted to vary according to distance from spawn, and if it was, possibly remove it (turn into normal stone) based on a random function, thereby creating increasing scarcity as nodes get closer to spawn. Am I following correctly?
Pretty close. Except you don't do any register_ore calls inside the LVM. Do that outside, and just handle the variation from spawn within the generated function. Otherwise, great!
I assume that letting minetest generate the ore and lua remove it would be more efficient then trying to write my own ore generation logic in lua? More efficent and MUCH easier.

What kind of impact would this have on map generation speed, probably not a whole lot?
Yeah, you will have a much easier time placing ore with the default ore mechanism and cleaning it up yourself compared to writing your own generation logic. More efficient? Still a moot point. The default ore generation takes next to no time, compared to any action with LVM. But overall, it should take very little time. You're not calling any perlin noise, you're just visiting every node once. I'd say well under 100 ms per chunk, and that's being strict.
Oh, and one more question. could the deprecated default.generate_ore do what I want? I suppose it would be a very bad idea to use it in any case. :)
...Yeah, that could be bad. Plus, it doesn't override default ore gen. So you'd have to clean up the default ores as well.
and yes, an example (simple!) would be appreciated. I learn best by looking at examples.
Here you go!

Code: Select all

minetest.register_on_generated(function(minp, maxp, seed)
        --if out of range of ore_gen limits
	if minp.y > 0 then
		return --quit; otherwise, you'd have wasted resources
	end

	--easy reference to commonly used values
	local t1 = os.clock()
	local x1 = maxp.x
	local y1 = maxp.y
	local z1 = maxp.z
	local x0 = minp.x
	local y0 = minp.y
	local z0 = minp.z
	
	print ("[ore_gen] chunk minp ("..x0.." "..y0.." "..z0..")") --tell people you are generating a chunk
	
        --This actually initializes the LVM
	local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
	local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
	local data = vm:get_data()
	
	--grab content IDs -- You need these to efficiently access and set node data.  get_node() works, but is far slower
	local c_air = minetest.get_content_id("air")
	local c_stone = minetest.get_content_id("default:stone")
	local c_water = minetest.get_content_id("default:water_source")
	local c_lava = minetest.get_content_id("default:lava_source")
	local c_iron = minetest.get_content_id("default:stone_with_iron")
	local c_diamond = minetest.get_content_id("default:stone_with_diamond")

	for z = z0, z1 do -- for each xy plane progressing northwards
		for y = y0, y1 do -- for each x row progressing upwards
			local vi = area:index(x0, y, z) -- This accesses the node at a given position
			for x = x0, x1 do -- for each node do
				-- Now test the node if it's an ore that needs to be potentially thinned out
				if data[vi] == c_iron or data[vi] == c_diamond then
					-- it is, so now thin it based on distance from center
					local dist = abs(x) + abs(y) + abs(z) + 1  -- This also accounts for vertical distance, so that you don't need new functions for deeper depths
					-- Now threshold it and delete unwanted nodes
					if math.random() > (1/dist) then  -- 1/dist becomes exceeding small as dist increases. random is between 0 and 1.
						data[vi] = c_stone  -- remove the ore
					end
				end -- end ore existence check
			end -- end 'x' loop
		end -- end 'y' loop
	end -- end 'z' loop

	-- Wrap things up and write back to map
	--send data back to voxelmanip
	vm:set_data(data)
	--calc lighting
	vm:set_lighting({day=0, night=0})
	vm:calc_lighting()
	--write it to world
	vm:write_to_map(data)

	local chugent = math.ceil((os.clock() - t1) * 1000) --grab how long it took
	print ("[ore_gen] "..chugent.." ms") --tell people how long
end)
Nam ex spatio, omnes res venire possunt.
Why let the ground limit you when you can reach for the sky?
Back to college now, yay for sophomore year schedules. :P

User avatar
Kilarin
Member
Posts: 896
Joined: Mon Mar 10, 2014 00:36
GitHub: Kilarin

Re: Post your modding questions here

by Kilarin » Post

Thank you VERY much!

I think I will suggest to the developers though that minetest add a clust_scarcity_func option to register_ore. Then you could easily write your own function to determine the scarcity however you wished.

Now, off to play. :)

User avatar
Kilarin
Member
Posts: 896
Joined: Mon Mar 10, 2014 00:36
GitHub: Kilarin

Re: Post your modding questions here

by Kilarin » Post

I thank you SO much for that example. the process was a lot more involved than I imagined. :) I'm learning a lot from going through this!

Right now, I'm having a problem though. register_on_generated is running, and from the debug output, I can tell that its hitting the remove ore logic. I switched it to replacing with a gold block instead of natural stone, just so I could see it. And I even put in a print to prove that data[vi] is changing. But no ore is actually being removed from the map. So I'm guessing that somehow the data is not being saved back to the map? Which makes no sense, because we are obviously hitting vm:write_to_map(data).

My very slight variations of your code, just in case it matters:

Code: Select all

    minetest.register_on_generated(function(minp, maxp, seed)
            --if out of range of ore_gen limits
       if minp.y > 0 then
          return --quit; otherwise, you'd have wasted resources
       end

       --easy reference to commonly used values
       local t1 = os.clock()
       local x1 = maxp.x
       local y1 = maxp.y
       local z1 = maxp.z
       local x0 = minp.x
       local y0 = minp.y
       local z0 = minp.z
       
       print ("[ore_gen] chunk minp ("..x0.." "..y0.." "..z0..")") --tell people you are generating a chunk
       
            --This actually initializes the LVM
       local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
       local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}
       local data = vm:get_data()
       
       --grab content IDs -- You need these to efficiently access and set node data.  get_node() works, but is far slower
       local c_air = minetest.get_content_id("air")
       local c_stone = minetest.get_content_id("default:stone")
       local c_water = minetest.get_content_id("default:water_source")
       local c_lava = minetest.get_content_id("default:lava_source")
       local c_iron = minetest.get_content_id("default:stone_with_iron")
       local c_coal = minetest.get_content_id("default:stone_with_coal")
       local c_copper = minetest.get_content_id("default:stone_with_copper")
       local c_mese = minetest.get_content_id("default:stone_with_mese")
       local c_diamond = minetest.get_content_id("default:stone_with_diamond")
       local c_goldblock = minetest.get_content_id("default:goldblock")

       for z = z0, z1 do -- for each xy plane progressing northwards
          for y = y0, y1 do -- for each x row progressing upwards
             local vi = area:index(x0, y, z) -- This accesses the node at a given position
             for x = x0, x1 do -- for each node do
                -- Now test the node if it's an ore that needs to be potentially thinned out
                if data[vi] == c_iron or data[vi] == c_copper or data[vi] == c_mese or data[vi] == c_diamond then
                   -- it is, so now thin it based on distance from center
                   local dist = math.abs(x) + math.abs(y) + math.abs(z) + 1  -- This also accounts for vertical distance, so that you don't need new functions for deeper depths
                   -- Now threshold it and delete unwanted nodes
                   --if math.random() > (1/dist) then  -- 1/dist becomes exceeding small as dist increases. random is between 0 and 1.
                   if 1 == 1 then  -- remove all for test just to prove it is removing the ore
                      print("[ore_gen] removing ore old="..dump(data[vi]))
                      --data[vi] = c_stone  -- remove the ore                      
                      data[vi] = c_goldblock
                      print("                       new="..dump(data[vi]))
                   end
                end -- end ore existence check
             end -- end 'x' loop
          end -- end 'y' loop
       end -- end 'z' loop

       -- Wrap things up and write back to map
       --send data back to voxelmanip
       vm:set_data(data)
       --calc lighting
       vm:set_lighting({day=0, night=0})
       vm:calc_lighting()
       --write it to world
       vm:write_to_map(data)

       local chugent = math.ceil((os.clock() - t1) * 1000) --grab how long it took
       print ("[ore_gen] "..chugent.." ms") --tell people how long
    end)

end
and a sampling of my debug output, just in case that proves useful

Code: Select all

[ore_gen] chunk minp (-32 -112 -192)
[ore_gen] removing ore old=38
                       new=46
[ore_gen] removing ore old=38
                       new=46
[ore_gen] removing ore old=38
                       new=46
... lots and lots more of the same kind of thing :)
[ore_gen] removing ore old=40
                       new=46
[ore_gen] removing ore old=38
                       new=46
[ore_gen] removing ore old=38
                       new=46
[ore_gen] 220 ms

Again, thank you so VERY much for your assistance. This mapgen stuff is fascinating!

TeTpaAka
Member
Posts: 141
Joined: Sat Dec 28, 2013 21:54

Re: Post your modding questions here

by TeTpaAka » Post

This code checks only slices of the map. The line

Code: Select all

             local vi = area:index(x0, y, z) -- This accesses the node at a given position
should be like

Code: Select all

             local vi = area:index(x, y, z) -- This accesses the node at a given position
and inside the x loop.

User avatar
Kilarin
Member
Posts: 896
Joined: Mon Mar 10, 2014 00:36
GitHub: Kilarin

Re: Post your modding questions here

by Kilarin » Post

I see your point TeTpaAka, but then wouldn't setting vi need to be inside the x loop as well?
In the current configuration, vi never changes as we loop through the x values. Hmmm....

<edit>
DUH! yes, fixed!
simple typo in the example which I should have detected right off if I hadn't been intimidated by not understanding so much of mapgen.

Code: Select all

             --local vi = area:index(x0, y, z) -- This accesses the node at a given position
             for x = x0, x1 do -- for each node do
                local vi = area:index(x, y, z) -- This accesses the node at a given position
Now works!!! thank you Hero and TeTpaAka!

User avatar
Krock
Developer
Posts: 4650
Joined: Thu Oct 03, 2013 07:48
GitHub: SmallJoker
Location: Switzerland
Contact:

Re: Post your modding questions here

by Krock » Post

Kilarin wrote:

Code: Select all

             --local vi = area:index(x0, y, z) -- This accesses the node at a given position
             for x = x0, x1 do -- for each node do
                local vi = area:index(x, y, z) -- This accesses the node at a given position
Now works!!! thank you Hero and TeTpaAka!
It's supposed to be used as an array.

Code: Select all

	local vi = area:index(x0, y, z) -- This accesses the node at a given position
	for x = x0, x1 do -- for each node do
		-- Codes..
		vi = vi + 1
	end
Look, I programmed a bug for you. >> Mod Search Engine << - Mods by Krock - DuckDuckGo mod search bang: !mtmod <keyword here>

User avatar
Kilarin
Member
Posts: 896
Joined: Mon Mar 10, 2014 00:36
GitHub: Kilarin

Re: Post your modding questions here

by Kilarin » Post

Krock wrote:It's supposed to be used as an array.
Please excuse my ignorance. I still have difficulties figuring out variable types in lua, and of course, the Minetest api is not my best friend yet. :)

area is a VoxelArea returned by VoxelArea:new
so doesn't area:index return a specific element from the VoxelArea array?

User avatar
HeroOfTheWinds
Member
Posts: 470
Joined: Wed Apr 23, 2014 23:16
GitHub: HeroOfTheWinds
IRC: WindHero
Location: Hawaii

Re: Post your modding questions here

by HeroOfTheWinds » Post

It doesn't return an element, per se, but rather the index of an element. Hence, incrementing the returned index virtually is the same as choosing the next index of the VoxelArea array. Just be careful of array bounds.
Nam ex spatio, omnes res venire possunt.
Why let the ground limit you when you can reach for the sky?
Back to college now, yay for sophomore year schedules. :P

User avatar
Kilarin
Member
Posts: 896
Joined: Mon Mar 10, 2014 00:36
GitHub: Kilarin

Re: Post your modding questions here

by Kilarin » Post

HeroOfTheWinds wrote:It doesn't return an element, per se, but rather the index of an element.
yes! sorry, I've got to watch my language. vi is obviously the index of data. :)

drkwv
Member
Posts: 102
Joined: Thu Jun 28, 2012 13:48
GitHub: aa6

onkeydown? onkeyup?

by drkwv » Post

Maybe a stupid question but why don't minetest have a reaction on a key press? Instead, one should check for get_player_controls() every X ms. Why? Server even could tell a client what combinations it interested in to have a reaction on a custom combinations.

User avatar
lag01
Member
Posts: 321
Joined: Sun Mar 16, 2014 03:41
GitHub: AndrejIT
IRC: lag01
In-game: lag
Contact:

Re: onkeydown? onkeyup?

by lag01 » Post

drkwv wrote:Maybe a stupid question but why don't minetest have a reaction on a key press? Instead, one should check for get_player_controls() every X ms. Why? Server even could tell a client what combinations it interested in to have a reaction on a custom combinations.
Hm...
Maybe it is possible in lua to code something like register_on_key_press( function(player, keyname), check_delay_ms )...
But people may click buttons tens of times per second, so bad idea to respond to all that clicks...

TeTpaAka
Member
Posts: 141
Joined: Sat Dec 28, 2013 21:54

Re: Post your modding questions here

by TeTpaAka » Post

Is there a way to change the brightness for specific players? This would allow mods that add tools for players to see at night.
If this is not possible, could this be considered when dynamic lighting is added?

drkwv
Member
Posts: 102
Joined: Thu Jun 28, 2012 13:48
GitHub: aa6

Re: onkeydown? onkeyup?

by drkwv » Post

lag01 wrote:But people may click buttons tens of times per second, so bad idea to respond to all that clicks...
You can group these clicks inside check_delay_ms interval to transform 10 clicks into one event to react to:

Code: Select all

register_on_key_press( function(player, keyname, times_pressed), check_delay_ms )
Also, player could click his mouse 10 times/sec or press W button 10 times/sec but everyone seems to be ok with that, why bother about keyboard clicks then?

User avatar
yyt16384
Member
Posts: 46
Joined: Mon Nov 03, 2014 12:16
GitHub: yyt16384
IRC: yyt16384
In-game: yyt16384
Location: China

Re: Post your modding questions here

by yyt16384 » Post

Can I create some type of tool/sword that gets random attributes? For example, a sword may have random damage group within a range defined by its type. With current API I think the only way is to create many types for different attributes and generate a random type, but there will be too many possible combination of attributes.

User avatar
12Me21
Member
Posts: 873
Joined: Tue Mar 05, 2013 00:36
GitHub: 12Me21
Location: (Ignore all of my posts before 2018)

Re: Post your modding questions here

by 12Me21 » Post

does anyone know of a tutorial for making tools in mods? I've seen some before but now I can't find them anymore!

User avatar
Don
Member
Posts: 1643
Joined: Sat May 17, 2014 18:40
GitHub: DonBatman
IRC: Batman
In-game: Batman

Re: Post your modding questions here

by Don » Post

12Me21 wrote:does anyone know of a tutorial for making tools in mods? I've seen some before but now I can't find them anymore!
Check this
viewtopic.php?f=14&t=10729
Many of my mods are now a part of Minetest-mods. A place where you know they are maintained!

A list of my mods can be found here

User avatar
12Me21
Member
Posts: 873
Joined: Tue Mar 05, 2013 00:36
GitHub: 12Me21
Location: (Ignore all of my posts before 2018)

Re: Post your modding questions here

by 12Me21 » Post

Don wrote:
12Me21 wrote:does anyone know of a tutorial for making tools in mods? I've seen some before but now I can't find them anymore!
Check this
viewtopic.php?f=14&t=10729
I can't find the tools section, I've used it before, but it must have been moved or something.

Locked

Who is online

Users browsing this forum: No registered users and 7 guests