The Editor

This forum is for discussing anything related to The Quest editor.

The Editor

Postby Elendil / Redshift » Sun May 14, 2017 8:55 am

The editor is available on Windows. You can create new custom worlds with it which you can then upload to the Steam Workshop for others to play.

The editor is now also available with the GOG version of the game. It's not accessible from the game but can easily be started from the Galaxy client (Use the "More" button next to the "Play" button, then "Other" / "World Editor".) Everything is the same as in the Steam version (so the tutorial is applicable), except of course there is no Steam integration / Workshop, so that part can be disregarded.

If you haven't already, please read the tutorial! It contains information on how to start and use the editor.

The best way to learn the editor is to use it (after you've read the tutorial :)). Apart from the tutorial world, you can also get and study the main world on how things are done!

If you still have questions, ask them here, that's why the forum is in place. (I'm always busy, but I'll try to answer questions too, of course. ;))
User avatar
Elendil / Redshift
Site Admin
 
Posts: 940
Joined: Sun Oct 09, 2011 11:35 am

Re: The Editor

Postby Catacomber » Wed May 17, 2017 1:46 am

I made a pdf of your wonderful guide.

https://drive.google.com/file/d/0B6L6mu ... sp=sharing
User avatar
Catacomber
 
Posts: 1658
Joined: Tue Oct 25, 2011 5:20 am

Re: The Editor help

Postby Zachg1993 » Sat May 20, 2017 10:52 pm

let me say ive checked all the tutorials and i cant seem to get monster's(enemies) to show up. in the editor there placed and i created there id set them to visible and aggressive but when i go into the dungeon there not there. Ive re read all the pdf's even the tutorial you just put up i have no idea what im doing wrong.
Zachg1993
 
Posts: 3
Joined: Tue Sep 04, 2012 9:58 pm

Re: The Editor

Postby Elendil / Redshift » Sun May 21, 2017 8:27 am

You don't need an id for a regular monster.

Just select a monster from the "[Monster] monster (all)" submenu, place it (with space) and it'll be there. Anything more complicated builds upon that.
User avatar
Elendil / Redshift
Site Admin
 
Posts: 940
Joined: Sun Oct 09, 2011 11:35 am

Re: The Editor

Postby Zachg1993 » Mon May 22, 2017 7:35 am

I did as you said and still the monster shows up in the editor but when i load my game its not there il try making a whole new dungeon and see if that works.
(edit)
I created a blank dungeon an behold i slain the amazon lol but il just rebuild the world and try it again maybe the monster too close to the arrival area of the player?
Zachg1993
 
Posts: 3
Joined: Tue Sep 04, 2012 9:58 pm

Re: The Editor

Postby Elendil / Redshift » Mon May 22, 2017 10:25 am

Do you try to load a save? If you do, it won't work with a lot of things, including monsters.

As explained in the tutorial, the monster and item information saved into the save file has preference over the information in the world file. If you change things on a map and load a save which has saved information on that map, things will not really work. You must either wait a week in game somewhere else (so that monsters/items reset and it will not work with quest items) or enter the world with a character which hasn't been to it yet (maybe keep a save at the captain).
User avatar
Elendil / Redshift
Site Admin
 
Posts: 940
Joined: Sun Oct 09, 2011 11:35 am

Re: The Editor

Postby Schicko » Mon Jun 10, 2019 11:03 am

Hi again. I've finally bought a legitimate copy of the game and as such have been using the editor again lately. I have some more questions regarding the creation of expansions:

  1. Is it possible to run a script that exists in an expansion (say "Expansion A") in the base game or in another expansion (say "Expansion B") without editing the latter two?
  2. Is it possible to define and run functions in the scripting language used by the game? If yes, how?
  3. Is it possible to run scripts within scripts? If yes, how?
  4. Is it possible to run scripts in the background? If yes, how?
  5. Is it possible to use jump statements in scripts? I tried to write a dialog that should conditionally jump to an earlier part (using `setstate()`, `gonext()` and `ObjectThisState`), but it doesn't seem to work properly. This would be useful to make loops.
  6. Aside from the `gonext()` function, are there any other undocumented in-built functions in the scripting language? If so, what are they and what do they do?

I'd appreciate any answers or insight on these. For what it's worth, I asked those questions because, aside from being curious about the scripting language, I want to make an item for my expansion that will act sort of like Aladin's magic lamp, or maybe a like a phone, that can be used in the base game or any expansion and that when used will allow the player to talk to an NPC, but I haven't been able to this with my current knowledge of the game engine and the scripting language. The uncompleted sections of the http://redshift.hu/TheQuestSystem.pdf manual seems to hint that there were plans for the script API to be available for items and even spells (e.g., the `evtwear()` function, et al.), but there haven't been any updates regarding these as far as I know.

On a related note, it would be awesome if the features I asked about were possible to do in the current game but I know Elendil is probably busy with programming the upcoming game, so if it isn't already planned to be included in the game engine used for the upcoming game, it might be worth considering them. It'd definitely allow the new game and future expansions to be more flexible than they are currently and would allow for more possibilities in terms of interactivity.
User avatar
Schicko
 
Posts: 40
Joined: Sat Nov 12, 2011 11:02 am
Location: In your inventory

Re: The Editor

Postby Elendil / Redshift » Tue Jun 11, 2019 10:52 am

1. If I remember correctly an expansion is only loaded when you go to it. So no, you can't use expansion scripts in the base game.
2. I don't understand the question.
3. No.
4. No.
5. No.
6. There aren't any.

The Quest's script is very limited. Scripts are run at certain events, they run once and that's it.

The Quest 2 will use Lua. So it'll be more flexible. Anything more specific will have to wait until after we release the game. ;)
User avatar
Elendil / Redshift
Site Admin
 
Posts: 940
Joined: Sun Oct 09, 2011 11:35 am

Re: The Editor

Postby Schicko » Tue Jun 11, 2019 2:08 pm

Thanks for answering my questions Elendil. The fact that scripting in the new game will use Lua sounds very exciting! That will definitely make the creation of expansions in the new game way more interesting I think.

Just to clear it up, what I meant by "function definition" in question 2 is the same as function definition as outlined in https://www.lua.org/pil/5.html, whereby a new function can be made by giving it a name and body of things it should do. In the Lua example, the function `add`is defined and it takes parameter `a`, adds its contents then returns the result. Can I also do the same in The Quest and use the newly defined function in other parts of the script?

I've also got other issues. First, I tried make a script that contains the line:
Code: Select all
createmonsterdir("base_mugger3", dir north, 1);

which can't be compiled. The resulting error is:
Code: Select all
Invalid number of arguments.
createmonsterdir(monstertypeid, dir (north | west |
south | east), distance)

Since that doesn't seem to be the proper way to use `createmonsterdir()`, what is?

Second, when I use the `talknpc()` function, then use the "Buy/Sell" option in the dialogue screen that appears, the game crashes. To see an example of it, load the questworld file https://www.dropbox.com/s/d7sargpt4p3hz ... world?dl=0 or the pak file https://www.dropbox.com/s/01k3ufhwooqzl ... d.pak?dl=0 then go to The Void (accessible from the captain in Matras), after arriving, go through the door behind you, choose the "Other shops" dialogue option, select "Ok" which would change the NPC, and then choose the "Buy/Sell" option which would cause the crash. Another way to reproduce this issue is if you choose to go the The Arena, then hit a teleporter using the "Cheap Summoner Staff", the choose the "Buy/Sell" option. Is there any way I can make this work, or will I have to have separate doors for different NPCs?

Third, I can't seem to get the `questionyesno()` function to work properly. I use it in the same expansion above, in the scripts that have names starting with `void_script_mapobj_arena_teleporter_` which are used on the teleporters in the map `void_map_arena`. The "Yes" option works fine and moves the player to the appropriate place, but the "No" option does not cause the dialogue box to disappear as expected. Am I using it improperly? If so, what is the proper way to use it?

Fourth, in the same expansion, I made a shared dialogue topic "The Arena" with the id `void_topic_arena_options`. On one of the scripts, the one with the cond1 "ObjectListResult == 0", there is a section at the bottom that is not functioning as expected:
Code: Select all
if (choice_0 == "view_distance_change") {
  current = getglobal("void_global_arena_view_distance");

  message("The current visibility in The Arena is " + (current) + "%.");
  message("Change hundreds value:");
  createobjectlist("");
  addobjecttolist(0, "0");
  addobjecttolist(1, "1");
  showobjectlist();
  setstate(2);
}

I thought that after it runs, the script with the cond1 "StateThis == 2" will run but instead it does not and I'm not sure why. Is there a way to fix it?

Fifth, in the same topic as the one in my fourth issue, the script with the cond1 "StateThis == 1" also doesn't seem to work as expected. When "Yes" is chosen after being asked if the player would like to go back to The Void, the player is not returned to `void_map_void` as expected.

Sixth, when I activate enemy spawning in the arena (by hitting a teleporter with the "Opponent Generator Staff") then move around, enemies spawn when in the editor, but they don't when in game. In the game, I have to sleep first before they appear.
User avatar
Schicko
 
Posts: 40
Joined: Sat Nov 12, 2011 11:02 am
Location: In your inventory

Re: The Editor

Postby Elendil / Redshift » Wed Jun 12, 2019 11:15 am

You can't define functions in The Quest's script.

Just use:
Code: Select all
createmonsterdir("base_mugger3", north, 1);
(No "dir", that's just the variable name/purpose ("direction").)

The NPCs dialogue system is a mess. I have no idea whether talking to different NPCs from the same script was ever supposed to work (most likely not). You'll have to use different initiations (doors) to talk to different NPCs.

When calling "questionyesno()", you don't seem to handle the other case.

In your "void_topic_arena_options" script you create an object list. That will overwrite the object list results and the next line, with the "As you wish..." text and "ObjectListResult==0" will run if in that last list the first option was chosen and then the state will be set to 0.

Your next problem is likely related. In a dialogue, the game goes through all lines, one by one, and runs the one which has all it's conditions met. If you change those conditions during the run through, your results may vary.

Lastly as stated in the editor tutorial, if you change your expansion world, you might have to start a new character (or sleep somewhere else) to let the area 'reset'. Otherwise all the existing variables saved in your save file might interfere.

Sorry I can't help more precisely, I really don't have the time. At this point you are basically on your own with The Quest/Editor. :P I really have to work on The Quest 2.
User avatar
Elendil / Redshift
Site Admin
 
Posts: 940
Joined: Sun Oct 09, 2011 11:35 am

Re: The Editor

Postby Schicko » Fri Jun 14, 2019 10:00 pm

Edit 1: Disregard my call for help in the original post. I tried all sorts of solutions including manually unpacking the questworld file and attempting to edit the pdb inside with a hex editor but I was finally able to edit the topic when I changed its place in the list of shared dialogue topics using the up and down buttons for another topic in the editor. I don't know why that worked but it did for some reason. Hopefully this will help other people who come across the same problem.

Original: Thanks for the reply and advice Elendil. Because of it I managed to update my expansion again and fix the "change visibility" and "exit the arena" dialogue issues (the download links are still the same in case people want to try it out). It turns out the problems were caused by the `talknpc()` function again (thanks for letting me know about it being problematic btw), so I just fixed it by teleporting the player to a room with a door that can be used to talk to the NPC. I also stopped trying to use the `questionyesno()` function since it wasn't too important anyways and I couldn't get it to work however much I tried so now the "Return to The Void" spell simply instantly teleports the player instead of asking.

This isn't important and I know there's little chance it'll be fixed, but I thought I'd let you know that I found out that the `removemonstertypes()` function e.g. used with:
Code: Select all
removemonstertypes("base_archer2");

crashes the game for me.

Also I tried using the `createmonsterdir()` function in the way that you recommended but I still couldn't get it to work. I'm also not using it though, so it's not important but I thought I'd let you know about it nonetheless.

I do have a somewhat serious issue though that I would really appreciate some help with: I can't edit the dialogue topic `void_topic_arena_options` anymore because the editor crashes when I try to. I hate to ask because I know you're busy with the new game, but if you have some time to spare, please could you give me advice on what I could do to be able to edit it again? I spent a lot of time scripting that particular dialogue topic (one of the scripts was around 11000 bytes in size already) and I'd be pretty gutted if I can't edit it anymore and if I have to return to an older version of the expansion and make all the edits from memory again. I need to edit it because the option to change new opponents to witches doesn't work properly and I'd like to try and fix it.

For what it's worth, I have a backup of the problematic part of the topic - https://bin.privacytools.io/?628ce75401 ... r51ldqo6Q=. And I'm pretty sure the issue is because of line 760 which should've been
Code: Select all
if (choice_enemy_type == 18) {

instead of
Code: Select all
if (choice_enemy_type == 15) {

It sucks that I can't edit it now though and I feel stupid for not making a backup of the whole thing before saving it.
User avatar
Schicko
 
Posts: 40
Joined: Sat Nov 12, 2011 11:02 am
Location: In your inventory

Re: The Editor

Postby Elendil / Redshift » Sun Jun 16, 2019 6:19 am

Yeah, I have no idea what was the idea behind "removemonstertypes". The crash is basically the expected result. :lol: (Btw. if I haven't mentioned yet, I was originally only the graphics programmer. Although I've updated the game for the improved graphics, ported it to various platforms, fixed countless bugs and even polished up the editor a lot of the inner workings of the game are just baffling. :) )

"createmonsterdir": I think you might need to use "north", "south", etc. (with the quotation marks).

I'd need the recent questworld to check it in the editor to see where it crashes. Or does the old one linked before in the topic crash too?
User avatar
Elendil / Redshift
Site Admin
 
Posts: 940
Joined: Sun Oct 09, 2011 11:35 am

Re: The Editor

Postby Schicko » Sun Jun 16, 2019 6:41 am

Yeah, I have no idea what was the idea behind "removemonstertypes". The crash is basically the expected result. :lol:

Lol it certainly seems like it.

Btw. if I haven't mentioned yet, I was originally only the graphics programmer. Although I've updated the game for the improved graphics, ported it to various platforms, fixed countless bugs and even polished up the editor a lot of the inner workings of the game are just baffling. :)

And I have to thank you for that. The game and editor seems much more stable and a lot of the features actually work properly now!

"createmonsterdir": I think you might need to use "north", "south", etc. (with the quotation marks).

Thanks I will have to try that way.

I'd need the recent questworld to check it in the editor to see where it crashes. Or does the old one linked before in the topic crash too?

Oops I forgot to share a link to a version that has the faulty topic. Sorry about that that. Here's one if you wanted to see what causes it (it's the shared dialogue topic "The Arena" which has the id `void_topic_arena_options`) - https://www.dropbox.com/s/rwxv1q80j5gtl ... world?dl=0. Like I said though, I've already managed to fix the topic in later versions of the file. Anyways, thanks again for all your help!
User avatar
Schicko
 
Posts: 40
Joined: Sat Nov 12, 2011 11:02 am
Location: In your inventory

Re: The Editor

Postby Catacomber » Wed Jun 19, 2019 4:33 am

I tried using Create Monster and Remove Monster scripts and they always crashed. The best way to handle monsters is to set them hidden and set them visible. I tried using Create Monster in Caerworn Castle every which way for random battles and it was just unstable. Not worth the headache. : ) Quest does very well what it does. It's best to stick to that. I have a betatester, Old Shaman, who's proficient in C++ and C and he's tried to implement standard C++ and C scripts in the Quest and usually adding scripting that isn't supported just doesn't work.
User avatar
Catacomber
 
Posts: 1658
Joined: Tue Oct 25, 2011 5:20 am

Re: The Editor

Postby Schicko » Wed Jun 19, 2019 9:28 pm

I tried using Create Monster and Remove Monster scripts and they always crashed.

`createmonsterpos` works fine when I used it in The Void, for me it's just `removemonstertypes` that causes crashes whenever it's used. I've not scripted enemies yet, so I'm not sure if this would work, but surely it should be possible to kill monsters you want by writing a script for them that checks for the status of a global variable, say, "test_enemies_dead" to see if it should activate or not and if it should, it will use the `sethp(0)`function to set their hp to 0, like so:
Code: Select all
if (getglobal("test_enemies_dead")) {
  sethp(0);
}

So you simply do a `setglobal("test_enemies_dead", 1)` somewhere to kill them.

It's not ideal if you can't add scripts into the monsters though, for instance when you want to use the monsters from the base game (unless you make copies of them, which would also be a hassle). And like I said, I've not tried it out, so I'm not even sure it would work.
The best way to handle monsters is to set them hidden and set them visible.

Nice, thanks for the tip.
tried to implement standard C++ and C scripts in the Quest and usually adding scripting that isn't supported just doesn't work.

Wait, is that possible? How does he do it? I think I've reached some kind of script size limit with the file format/editor (the latter crashes when I edit new scripts in and try to save) and would like to try new ways of scripting to see if I can fit more complicated scripts than I have currently. Loops and function definitions from those languages would be a welcome boon too if they were possible to use.
User avatar
Schicko
 
Posts: 40
Joined: Sat Nov 12, 2011 11:02 am
Location: In your inventory

Re: The Editor

Postby Catacomber » Thu Jun 20, 2019 3:48 am

He doesn't create anything new----he just uses the script functions that are hard-wired into the Quest.

There are certain functions you can use in the quest--trying to use regular C or C++ scripts that include anything not hard-wired into the Quest doesn't work.

So you can test if a condition is true by using if (check for condition)
and then have something happen if that condition is true and then have something else happen if it isn't but if you tried to set up your own function using void or anything, that wouldn't work.

Not sure if I'm clear. Everything the Quest supports is in the manual. You can't really go outside that in scripting. Or at least, I haven't been able to do that. You'd get a script error.

I'm trying to avoid using globals where I can because people have too many expansions enabled and the Quest sometimes gets confused checking so many globals. This is especially a problem in Steam where you can't disable an expansion unless you start over with a new save file.
User avatar
Catacomber
 
Posts: 1658
Joined: Tue Oct 25, 2011 5:20 am

Re: The Editor

Postby Schicko » Thu Jun 20, 2019 7:17 am

Ah I see, I understand what you mean now.
Everything the Quest supports is in the manual. You can't really go outside that in scripting. Or at least, I haven't been able to do that. You'd get a script error.

This isn't strictly speaking true, I've encountered some usable functions that aren't documented in the editor's manual. There's `gonext()` that causes a dialogue script to jump to the next script whose conditions are matched, and there's `movebyship()` that causes the player to be transported to other expansions. In addition to that, there's also some variables that the game engine expands to other values, for instance "exppack1" which somehow gets converted to a list of expansions accessible from Matras when used in the `addobjecttolist` function, and then to a chosen expansion when used with the `showobjectlist`, and then to the expansion's startgame id (eg "test_STARTGAME") when used with `getobbjectlistresult`. I wouldn't be surprised if there's more stuff and would be interested to know about them if anyone knows anything else.
I'm trying to avoid using globals where I can because people have too many expansions enabled and the Quest sometimes gets confused checking so many globals.

Oh I didn't know that could happen. I've never it encountered it myself, but then again, I only have the Islands of Ice and Fire so far. I'm somewhat surprised that it happens because I would've thought that the fact that global variables have to be prefixed with the expansion's id would prevent variable naming conflicts. I guess there's still a lot of quirks with the game engine that we don't know about.
User avatar
Schicko
 
Posts: 40
Joined: Sat Nov 12, 2011 11:02 am
Location: In your inventory

Re: The Editor

Postby Elendil / Redshift » Thu Jun 20, 2019 7:32 am

Quest sometimes gets confused checking so many globals

That's not really a thing, no. Sorry Cat.

I haven't encountered this ever. What is true is that the game saves a lot of things in the save file and if the expansion is changed things can go wrong when loading the save. If you start a completely new game, there are no problems. One workaround is to go to somewhere else (like Freymore, where things haven't changed), wait a week in game time to let the game reset the area and then go back. This won't help with globals, obviously. If you change the way how you act on globals in scripts you'd have to be prepared for encountering any earlier values.
User avatar
Elendil / Redshift
Site Admin
 
Posts: 940
Joined: Sun Oct 09, 2011 11:35 am

Re: The Editor

Postby Schicko » Thu Jun 20, 2019 8:27 pm

Do logic operators such as `AND` and `OR` exist in the game's scripting language? I've mostly been using `if` and `else` statements in combination with setting variables to 1 or 0 to do logical operation which is inconvenient. I've tried using `AND` and `OR` as well as `&&` and `||` a couple of times but none of them seem to work and I couldn't see anything in the editor's manual about it (if it's there and I missed it, I apologise) so I thought I'd ask.
User avatar
Schicko
 
Posts: 40
Joined: Sat Nov 12, 2011 11:02 am
Location: In your inventory

Re: The Editor

Postby Catacomber » Fri Jun 21, 2019 2:15 am

Yes, they do.

if(evtuse() && (getstate()==0) && (player.hasitem("game_necklace",1) || (player.hasitem("game_ring",1)))
{
message("You opened a door.");
game_door.open();
setstate(1);
}
else
if(evtuse() && (getstate()==0) && !(player.hasitem("game_necklace",1) || ! (player.hasitem("game_ring",1)))
message("You can't open the door unless you have certain items.")
User avatar
Catacomber
 
Posts: 1658
Joined: Tue Oct 25, 2011 5:20 am

Re: The Editor

Postby Catacomber » Fri Jun 21, 2019 4:21 am

Elendil / Redshift wrote:
Quest sometimes gets confused checking so many globals

That's not really a thing, no. Sorry Cat.

I haven't encountered this ever. What is true is that the game saves a lot of things in the save file and if the expansion is changed things can go wrong when loading the save. If you start a completely new game, there are no problems. One workaround is to go to somewhere else (like Freymore, where things haven't changed), wait a week in game time to let the game reset the area and then go back. This won't help with globals, obviously. If you change the way how you act on globals in scripts you'd have to be prepared for encountering any earlier values.


That makes sense. Will pass the info on. It seems to be quite a problem sometimes.
User avatar
Catacomber
 
Posts: 1658
Joined: Tue Oct 25, 2011 5:20 am

Re: The Editor

Postby Elendil / Redshift » Fri Jun 21, 2019 6:20 am

Regarding the logical operators &&, || and ! (and, or and not), you should be aware that there is no operator precedence. Everything is evaluated from left to right. This is why it might be a good idea to put parens around some stuff in expressions.

(I've written about it in the tutorial. ;) )
User avatar
Elendil / Redshift
Site Admin
 
Posts: 940
Joined: Sun Oct 09, 2011 11:35 am

Re: The Editor

Postby Schicko » Fri Jun 21, 2019 7:55 am

Ah thanks Cat and Elendil for the examples and information. I think I wasn't using parentheses which is why they weren't working as I expected.
User avatar
Schicko
 
Posts: 40
Joined: Sat Nov 12, 2011 11:02 am
Location: In your inventory

Re: The Editor

Postby Schicko » Fri Jun 21, 2019 1:03 pm

Is there another way to do the following that doesn't use repeated calls to the same functions?
Code: Select all
createobjectlist("");
if (player.hasitem("base_spbookburninghand", 1)) {
  if (player.knowsspell("base_spellburninghand")) {
    addobjecttolist("base_spbookburninghand", "Burning hand (owned, known)");
  } else {
    addobjecttolist("base_spbookburninghand", "Burning hand (owned, unknown)");
  }
} else {
  if (player.knowsspell("base_spellburninghand")) {
    addobjecttolist("base_spbookburninghand", "Burning hand (not owned, known)");
  } else {
    addobjecttolist("base_spbookburninghand", "Burning hand (not owned, unknown)");
  }
}
showobjectlist();
setstate(1);

I tried to do the following which is shorter and uses each function only once but it doesn't work:
Code: Select all
createobjectlist("");
addobjecttolist("base_spbookburninghand", "Burning hand (" +
if (player.hasitem("base_spbookburninghand", 1)) {
  "owned"
} else {
  "not owned"
}
+ ", " +
if (player.knowsspell("base_spellburninghand")) {
  "known"
} else {
  "unknown"
}
+ ")");
showobjectlist();
setstate(1);
User avatar
Schicko
 
Posts: 40
Joined: Sat Nov 12, 2011 11:02 am
Location: In your inventory

Re: The Editor

Postby Elendil / Redshift » Sat Jun 22, 2019 7:04 am

"if" is a statement, not an expression. The two parts of an "if/else" statements will not get the value of the last expression (as would happen in some languages where if is an expression).

Try this:

Code: Select all
createobjectlist("");
if (player.hasitem("base_spbookburninghand", 1)) {
  owned = "owned";
}
else {
  owned = "not owned";
}
if (player.knowsspell("base_spellburninghand")) {
  known = "known";
}
else  {
  known = "unknown";
}
addobjecttolist("base_spbookburninghand", "Burning hand (" + owned + ", " + known +")");
showobjectlist();
setstate(1);
User avatar
Elendil / Redshift
Site Admin
 
Posts: 940
Joined: Sun Oct 09, 2011 11:35 am

Next

Return to Editor

Who is online

Users browsing this forum: No registered users and 9 guests

cron