Log in or sign up


USER:
PASS:

 
 
Forums
Call of Duty World at War Zombies :: Forums :: Support :: Map Support
 
<< Previous thread | Next thread >>
Advanced Zombie Scripting
Moderators: smithster, dcslim
Author Post
bundabrg
Sat Dec 13 2008, 02:05PM
Registered Member #276
Joined: Sat Dec 06 2008, 04:12AM
Posts: 15
Hi All,

After messing around in Radiant for a while, I've decided I simply don't have the patience to sit down and tweak a 31x31 patch vertice by vertice. I'll create my map using nice boring boxes and we'll call it a city scape.
However, I am by profession as well as by hobby a coder, so I've been pulling apart the gsc code, and in particular the Zombie Code. I'd like to start a thread on the discussion of the code. I wonder just how many people have looked through the code yet?

So far, those who have managed to use the modtools to build a semi stable zombie map, you are probably starting to hit some of the limitations of the exiting code. Firstly, I do have to give props to the original authors. They did have to write this under extreme time constraints, and thus wrote it mainly for the nazi_zombie_prototype level (the standard one in the game). Also simple means that there are less bugs! I think there is plenty of room for improvement and I believe we as the community can add to the existing code.

I think IMHO that the zombie mode sold COD5. Ok, there are a bunch of things that have been improved in the engine (and we'll quietly ignore the whole fiasco of the modtools... wait a month, and a patch, and it'll all just be a distant memory) but the average user is not going to realise this and either bought the game based on their experience with COD4 (or older), or got sold on the zombie idea, which after the first 100 games in a 3 room map where you never buy anything but the random gun, gets boring. However I've seen some of your maps in progress and I tell you, playing TD in a FPS will make this game live on!

I therefore propose writing or editing the existing code in such a way that one can reasonaly easly drop in the 'advanced' zombie scripts in place of the existing ones, compile the map, and volia, have it all work, without really needing to modify maps. I'll be having a crack at this (in the time I don't have <g>), and will post back as I go through.

I havn't gone through all the code yet with a toothcomb, but some things I've noticed in the existing code (I'll flesh out later once I go through the code again) are (in easier to read english I hope than reading code): -

1 Zombies are quite dumb. Ok, in the prototype map, they only need to break through a barrier, then attack a player. It seems that a zombi's thinking goes as follows:
1.1 Spawn
1.2 Find the 3 nearest barriers and pick one of them. Head towards it (heaven forbid if there _are_ no barriers)
1.3 Look for a player

This means if you are building a complex level with window and door barriers and have multiple tiers, the zombies will either stand around shaking their heads stupidly when they spawn, or once they get through the first 'tier' of barriers, stand around shaking their heads stupidly. (Note, reading through again, they do change tactics when not finding a route/playe _sometimes_. Its mainly because they authors assume that the "playing area" is indoors and everywhere else is "outdoors". When the zombies are in the playing area, they just look for flesh. Heaven forbid another barrier system).

2 Zombies have failsafe code. If they fall off the map, they suicide. If they don't move for a while, they suicide. If they can't get to the closest player, they will ignore them and try someone else.

3 Lots of code for 'turning a player' into a zombie when they die instead of spectating them. Its disabled by default. I'm assuming it was not yet fully supported (and looking later at the code, theres lots of TODO's around this area). However, theres plently of code written to make use of it. As there are only a max of 4 players, I'm don't honestly think there would be too much incentive to get it working?

4 If you want to muck around with default values (IE, number of zombies, zombie health, and all the percentage increase values), edit the file _zombiemode.gsc and look for the function init_levelvars(). IE, if your map is HUGE you may want to scale the values differently. Be aware that hard coded in is an exponential leap in the multiple on the zombies from level 10 onwards (found in another file, can't quite remember).

5 Map builders will notice that you have prefabs for door blockers as well. Works pretty much same as a window blocker. One problem I can see is if a teammate gets stuck on the otherside (and in fact, you can _build_ it from the otherside as the trigger is close enough). Probably worth editing the code to allow a player to buy a removal of a barrier piece (when on the _other_ side of it). Just needs another trigger. Oh, and if you build a window blocker, make sure the player can't jump over it! Playerclip it!

6 Unblocking a window used to COST points before this got released (and many reviews mention this as well). Now of course you gain points. Good move IMHO. Recommend however editing so one can set whether its costs or gains optionally would be nice. Lots of stuff commented out for subtracting points that would need some if statements around.

7 Several types of blockers.
7.1 Exterior Goals - Looks for an entity with a targetname of "exterior_goal". Not sure yet what the difference between this and actually just linking a zombie to an entity is (unless you _have_ to link it to an exterior goal??)
7.2 Zombie Doors - Not sure. Someone experiment.
7.2.1 Create the Entity and set "targetname"="zombie_door"
7.2.2 You need to have one of the following keys as well: -
7.2.2.1 "script_angles" - Makes is a "rotating" door
7.2.2.2 "script_vector" - Makes it a "moving" door
7.2.2.3 "script_noteworthy" = "bust_apart" - Blows it apart (You need to create targets and link it to it, possibly like zombie blockers)
7.3 Zombie Debris - The "couch" in the prototype is a debris
7.3.1 Create the entity and set "targetname"="zombie_debris"
7.3.2 Create a struct where it will "go" and link it
7.3.3 (see regular tutorial for more details, can't be bothered repeating and its already very good.)
7.4 Zombie Blocker - The "boards" over the window is a zombie blocker
7.4.1 Create the entity and set "targetname"="zombie_blocker"
7.4.2 Create the "boards" and link them from the entity
7.4.3 Targets can optionally have "script_noteworthy" = "clip"
7.5 Flag Blocker (not sure yet. Probably not implemented)
7.5.1 Create the entity and set "targetname"="flag_blocker"
7.5.2 Requires a few other keys

8 Try shooting the radio in the regular map...

9 Zombie spawner has the following: -
9.1 Entity needs to have the key "targetname"="zombie_spawner"
9.2 Needs a key "script_noteworthy"="zombie_spawner"
9.2.1 Can have a key "script_start"="xx" where xx is a level that you want the spawner to start
9.3 Instead of "zombie_spawner", it can have "script_noteworthy"="later_round_spawners". Not quite sure yet of the difference. I suspect when designing it, the authors went for 'level based' spawning instead of 'blocker linked' spawning. So probably some legacy code.

10 Try timing a grenade throw over a group of zombies heads so it explodes in the air. They should all be head-gibbed. Extra care in the code to make sure of that

11 LOTS of code over that damn weapon cabinet.... I suspect it came before the Mario Kart box. I think you need to link it to the type of weapon you want in it.



Any other useful tips by others? Any useful things you _would like_ in the code? IE, being able to close doors, pull _down_ barriers, restore blockers, rescue dead team-mates ala Left-For-Dead style (in a locked room somewhere?), ... ...

- Bundabrg


[ Edited Sat Dec 13 2008, 02:26PM ]
Back to top
bundabrg
Tue Dec 16 2008, 05:23AM
Registered Member #276
Joined: Sat Dec 06 2008, 04:12AM
Posts: 15
Just a post to show you what I'm getting at. Here is a draft config file that I'll be using (and adding to as I think of stuff): -


/** 
 * ZombiePlus Extensions - Created 2008 - Bundabrg
 * --------------------------------------------------------------------------
 *
 * Zombie Mode Plus configuration file. 
 *
 **/
 

    /**
     * Initialise Configuration Variables
     *
     * Variables used by the rest of the code are all contained here. It means that there is a single location to
     * perform all the configuration you require. It is recommended that instead of editing this file and changing
     * values, that you instead override them in your own GSC OR create a ZP_Config.csv file with the values
     *
     **/ 
DoConfig() {

        //////////////////////////////////////////////////////////////////////////////////////////////
        //// Description
        //////////////////////////////////////////////////////////////////////////////////////////////
        //// Scaled Variables
        //// ----------------
        //// When a variable has "_scaled", it is generally a scaled variable. This means it uses the
        //// following formula: 
        //// <new>=(<current>*(C/100)) + A + (B*<current_level>)
        //// Where A,B,C are:
        //// zpSetConfig("variable_scaled", A, B, C)
        ////
        //// Overridable Variables
        //// ---------------------
        //// Variables can sometimes be overriden by other factors. Any variable that applies to an
        //// entity can generally be overriden by applying the same variable as an entity variable
        //// which will apply it for that specific entity
        ////
        //// Some variables also lookup values in a custom CSV file. 
        ////
        //// If a variable is able to be overridden, its description should indicate this.
        //////////////////////////////////////////////////////////////////////////////////////////////
        
        

        //////////////////////////////////////////////////////////////////////////////////////////////
        //// Score Settings
        //////////////////////////////////////////////////////////////////////////////////////////////
        
        // How much score does a player begin with
    zpSetConfig( "score_player_start", 500 );
    
        // Score killing a zombie
    zpSetConfig( "score_damage_killzombie_scaled", 50, 0, 100 );
    
        // Score Damaging a zombie
    zpSetConfig( "score_damage_damagezombie_scaled", 5, 0, 100 );
    
        // Score Bonus Melee
    zpSetConfig( "score_damage_bonus_melee_scaled", 80, 0, 100 );
    
        // Score Bonus Head
    zpSetConfig( "score_damage_bonus_head_scaled", 50, 0, 100 );
    
        // Score Bonus Neck
    zpSetConfig( "score_damage_bonus_neck_scaled", 20, 0, 100 );
    
        // Score Bonus Torso
    zpSetConfig( "score_damage_bonus_torso_scaled", 10, 0, 100 );
    
        // Score Bonus Burn
    zpSetConfig( "score_damage_bonus_burn_scaled", 10, 0, 100 );
    
        // Score when downed
    zpSetConfig( "score_player_downed_scaled", 0, 0, 95 );
    
        // Score when killed
    zpSetConfig( "score_player_killed_scaled", 0, 0, 100 );
    
        // How many points does it cost to rebuild a barrier. Negative means you gain points.
        // This is overridden by the barrier entity value "score_barrier_rebuild_cost_scaled"
    zpSetConfig( "score_barrier_rebuildcost_scaled", -10, 0, 100 );
    
        // How many points does it cost to tear down a barrier. Negative means you gain points. 
        // This is overridden by the barrier entity value "score_barrier_teardowncost_scaled"
    zpSetConfig( "score_barrier_teardowncost_scaled", 20, 0, 100 );
    
        // Maximum amount of points you are allowed to gain by rebuilding/tearing down windows
    zpSetConfig( "score_barrier_maxcost_scaled", 50, 10, 100 );
    
    
        //////////////////////////////////////////////////////////////////////////////////////////////
        //// Player Respawn Settings
        //////////////////////////////////////////////////////////////////////////////////////////////
        
        // Do we respawn dead players in between rounds?
    zpSetConfig( "player_respawn_betweenrounds", true );
    
        // Do we respawn players after a timeout when they die?
    zpSetConfig( "player_respawn_timeout", false );    
    zpSetConfig( "player_respawn_timeout_seconds_scaled", 0, 0, 100 );
    
        //////////////////////////////////////////////////////////////////////////////////////////////
        //// Zombie spawn Settings
        //////////////////////////////////////////////////////////////////////////////////////////////
        
        // Seconds to wait after round start until zombies are spawned
    zpSetConfig( "zombie_spawn_delay_scaled", 3, 0, 100 );
    
    
        //////////////////////////////////////////////////////////////////////////////////////////////
        //// Zombie Health Settings
        //////////////////////////////////////////////////////////////////////////////////////////////
        
        // Health that zombies start with
    zpSetConfig( "zombie_health_start", 150 );

        // Amount to increase health each level.
    zpSetConfig( "zombie_health_increase_scaled", 100, 0, 110 );
    
    
        //////////////////////////////////////////////////////////////////////////////////////////////
        //// Zombie Speed Settings
        //////////////////////////////////////////////////////////////////////////////////////////////
    
        // Percent chance a spawned zombie will run instead of walk
    zpSetConfig( "zombie_speed_chancerun_scaled", 1, 8, 100 );
    
        // Percent chance a spawned zombie will sprint instead of run or walk
    zpSetConfig( "zombie_speed_chancesprint_scaled", 1, 4, 100 );
    
     
        //////////////////////////////////////////////////////////////////////////////////////////////
        //// Round Settings
        //////////////////////////////////////////////////////////////////////////////////////////////
        
        // Seconds to wait between rounds 
    zpSetConfig( "round_beweenrounds_time_scaled", 0, 0, 100 );
    
    
        //////////////////////////////////////////////////////////////////////////////////////////////
        //// Misc Settings
        //////////////////////////////////////////////////////////////////////////////////////////////

        // Allow another player to take the weapon in the random box.
        // Overridden by the entity value "randombox_allowothergrab"
    zpSetConfig( "randombox_allowothergrab", false );
    
        // How many seconds after purchase till another player is allowed to take weapon
        // Overriden by the entity value "randombox_allowothergrab_delay_scaled"
    zpSetConfig( "randombox_allowothergrab_delay_scaled", 3, 0, 100 );
    
        // How long a weapon will hang around before going back into random box
        // Overriden by the entity value "randombox_timeout_scaled"
    zpSetConfig( "randombox_timeout_scaled", 12, 0, 100 );
    
    
    
        //////////////////////////////////////////////////////////////////////////////////////////////
        //// Misc Zombie Settings
        //////////////////////////////////////////////////////////////////////////////////////////////

        // Zombies drop guns on death?
    zpSetConfig( "zombie_dropweapons", false );
    
        // Percent chance of it occuring in a round
    zpSetConfig( "zombie_dropweapons_chance_scaled", 1, 0, 100 );
    
        // Maximum number of weapons dropped during a round allowed
    zpSetConfig( "zombie_dropweapons_maxdrops_scaled", 5, 0, 110 );
    
        // If a zombie does not move for this many seconds, kill it
    zpSetConfig( "zombie_stucktimeout", 30 );
    
        //////////////////////////////////////////////////////////////////////////////////////////////
        //// Powerup Settings
        //////////////////////////////////////////////////////////////////////////////////////////////
        
        // Zombies drop powerups?
    zpSetConfig( "zombie_droppowerups", true );
    
        // Percent chance of a powerup dropping randomly in a round
    zpSetConfig( "zombie_droppowerups_chance_scaled", 1, 0, 100 );
    
        // Drop one after this much score has been collected by players
    zpSetConfig( "zombie_droppowerups_scoredrop_scaled", 2000, 0, 100 );
    
        // Max powerups dropped in a round allowed
    zpSetConfig( "zombie_droppowerups_maxdrops_scaled", 4, 0, 100 );
    
        // Enable or Disable Powerups
    zpSetConfig( "powerup_instantkill", true );
    zpSetConfig( "powerup_pointdouble", true );
    zpSetConfig( "powerup_maxammo", true );
    zpSetConfig( "powerup_nuke", true );
    
        // Percent Chance of a powerup dropping compared to others
    zpSetConfig( "powerup_instantkill_chance_scaled", 100, 0, 100 );
    zpSetConfig( "powerup_pointdouble_chance_scaled", 100, 0, 100 );
    zpSetConfig( "powerup_maxammo_chance_scaled", 100, 0, 100 );
    zpSetConfig( "powerup_nuke_chance_scaled", 100, 0, 100 );
    
        // How long in seconds a dropped powerup will hang around before timing out
    zpSetConfig( "powerup_droptimeout_scaled", 45, 0, 100 );
    
        // How long does the pointdouble last
    zpSetConfig( "powerup_pointdouble_time_scaled", 30, 0, 100 );
    
        // How long does the instant kill last
    zpSetConfig( "powerup_instantkill_time_scaled", 30, 0, 100 );
Back to top
bundabrg
Tue Dec 16 2008, 05:26AM
Registered Member #276
Joined: Sat Dec 06 2008, 04:12AM
Posts: 15
Hmmm, not sure whats up with code blocks on this forum? Did I put it in wrong?

Back to top
HOGRampage
Tue Dec 16 2008, 05:34AM
Registered Member #508
Joined: Wed Dec 10 2008, 08:45PM
Posts: 72
I have looked through the scripts for zombies. In fact, I have changed difficulty, round times, how fast zombies move, how many come at you, etc.
Back to top
David_Draven
Wed Dec 17 2008, 12:10AM
Registered Member #234
Joined: Wed Dec 03 2008, 04:25AM
Posts: 5
bundabrg wrote ...

Any other useful tips by others? Any useful things you _would like_ in the code? IE, being able to close doors, pull _down_ barriers, restore blockers, rescue dead team-mates ala Left-For-Dead style (in a locked room somewhere?), ... ...


Probably just stating the obvious, but just to show that there is interest in what you are suggesting...

Useful things that I would like in the code (I don’t know what is possible, so I’m just throwing up what I’d like to see) -
* Zombies spawn and attack without requiring a barrier.
* Zombies continue moving through multiple barriers.
* Zombies find alternate routes if they spy a player but can’t reach them (at very least move to the closest node to a player).
* Zombies move through the map without having to spot a player or requiring a player to be within a certain distance.
* Being able to close a door would be cool. I don’t know if it would be possible to set up, but when it’s time to spawn, could a path check be made to determine if there is a reachable player? If not, the spawn point is not used. Otherwise, map makers would simply have to make it possible for the zombies to walk around to any area from any spawn point.
* It would be cool to see Zombies path aimlessly until they spy flesh. Perhaps a target node that they pick upon spawning and walk toward (navigating barriers and pulling down zombie blockers) until they spot a player.
* I would like to see perhaps one in every 10 zombies pick their player target when they spawn and ignore everyone else until their target is dead. Their random target may be the closest player anyway. In a co-op game, I think it would add creep factor to be fighting zombies and have one walk past you to attack a team mate somewhere behind you.

I don’t know what is possible, but this is some behaviour I’d like to see.
Back to top
bundabrg
Wed Dec 17 2008, 01:14AM
Registered Member #276
Joined: Sat Dec 06 2008, 04:12AM
Posts: 15
Currently zombies spawn, and unless targetted at something, they will look for 'exterior' goals to go to. I'm changing that so they start off looking for players, and will try go through any number of barriers to get to them.

Closing doors is easy. Perhaps it should be an entity flag that sets whether its closable or not.

The 'spawn check if player reachable and don't spawn if not' sounds like a good idea. There are some checks mande when they spawn, and they kill off if the checks fail (and don't count it to the number of spawned zombies).

You can already target zombies at something and they will go there, except they will do so to the exclusion of anything else. Perhaps a change so you can have a 'important' target or 'non-important' target such that 'non-important' means the zombie will go there, but if something more insteresting is found, it changes tactic. These percentage can be scaled depending on level as well.

I like the zombie picking on player option, as long as its tuneable.

I'm thinking I may change my script slightly and give zombies objectives. Objectives can be given a priority, such that 'picking on a certain player' can be given a percent, and 'walking to a node' another percentage. etc etc... A zombie can have lots of objectives and it will work out what to do based (with a bit of random chance) on the objective priorities.
Also it means you can add objectives to individual spawn spots and thus fine tune what each spot is likely to do...



[ Edited Wed Dec 17 2008, 01:22AM ]
Back to top
David_Draven
Wed Dec 17 2008, 05:01AM
Registered Member #234
Joined: Wed Dec 03 2008, 04:25AM
Posts: 5
Yes, I do like the idea of tuneable spawn spots that determine the behaviour of zombies spawned there. That would be awesome.

I was just thinking a moment ago of having a point with a name of ZombieDestination or something, so instead of giving up and dying when the zombie gets confused, the zombie attempts to move to a random ZombieDestination.
Of course, it should make limited attempts before it just goes ahead and suicides anyway.
I assume this is along the lines of your objective idea.

Example of spawn node information (obviously these are descriptions and not Key names) followed by possible values.
Move to ZombieDestination1 - 8
Move to ZombieDestination2 - 23
Move to ZombieDestination3 - 16
Move to ZombieDestination4 - 9
Pick random player, move to and attack - 10
Pick nearest player, move to and attack - 15
Go to DarkScaryCorner1 and wait until player within X distance before moving - 3
Go to DarkScaryCorner2 and wait until player within X distance before moving - 5
Go to DarkScaryCorner3 and wait until player within X distance before moving - 7
Go to DarkScaryCorner3 and wait until player within X distance before moving - 4

These two would override the above values
Attack visible player - 95 (hopefully reduced or disabled for Go to DarkScaryCorner1 and wait)
Attack damaging player - 60 (assuming zombie is not already engaged)

What does the zombie do once it has achieved a simple objective like move to ZombieDestination? Does it then randomly pick again from its spawn node list?

This example would require nodes with names of ZombieDestination1 to 4 and DarkScaryCorner1 to 4.

Perhaps instead of Go to DarkScaryCorner and wait until player within X distance before moving, simply have Go to DarkScaryCorner and wait. If DarkScaryCorner nodes are placed well, the zombie will activate when it sees the player and scare them anyway.

[ Edited Wed Dec 17 2008, 05:11AM ]
Back to top
bundabrg
Wed Dec 17 2008, 09:19AM
Registered Member #276
Joined: Sat Dec 06 2008, 04:12AM
Posts: 15
Sounds fantastic, and it opens up another type of zombie game... one where you are not necessarily fighting off endless rounds of zombies. If the code can allow for that as well then I'll be happy.

Currently I'm trying to get my head around clientscripts. Is there _any_ guide on them anywhere? They seem similar to GSCs, except vastly limited.
Back to top
bundabrg
Fri Dec 19 2008, 07:10AM
Registered Member #276
Joined: Sat Dec 06 2008, 04:12AM
Posts: 15
Update

I've started rewriting the Zombie code from scratch. I've called it ZombiePlus, not because its necessarily better than the original but because although I'm rewriting it, I'm basing it a lot on the original code but making it extremely customizable. Also wherever possible I'll be adding in the option to change how things work, but defaulting to how it looks with the standard code.

Some updates and thoughts: -
  • I've finished the Round Number hud, both the little one and the large one on the intro screen, and made it fully custmizable with placement, color, whether you want the intro done on every round or not. You can also choose whether to use the 'chalk' scores or not. Also a separate function to pulse the score so it can be done really anytime.
  • Almost finished the scoring. This includes the mini scores that fly off when you get a positive or negative change in score. Interestingly the actual bit that shows the score and the blood smear are provided by a UI change thats activated by enabling a couple of dvars and a variable on 'level'. Took a while to find that.


Some additional config entries are now: -

    zpSetConfig( "rn_roundhud_usecrosshatch", true );
    zpSetConfig( "rn_roundhud_color", ( 0.423, 0.004, 0 ) );
    zpSetConfig( "rn_roundhud_alignx", "left" );
    zpSetConfig( "rn_roundhud_aligny", "bottom" );
    zpSetConfig( "rn_roundhud_horzalign", "left" );
    zpSetConfig( "rn_roundhud_vertalign", "bottom" );
    zpSetConfig( "rn_roundhud_x", 0 );
    zpSetConfig( "rn_roundhud_y", 0 );
    zpSetConfig( "rn_roundhud_fontscale", 32 );
    
        // What colour to pulse the round hud to when we call rnPulseRoundNumber()
    zpSetConfig( "rn_roundhud_pulsecolor", (1,1,1) );
    
    
    zpSetConfig( "rn_introhud_color", ( 1, 1, 1 ) );
    zpSetConfig( "rn_introhud_largehud_alignx", "center" );
    zpSetConfig( "rn_introhud_aligny", "bottom" );
    zpSetConfig( "rn_introhud_horzalign", "center" );
    zpSetConfig( "rn_introhud_vertalign", "bottom" );
    zpSetConfig( "rn_introhud_x", 0 );
    zpSetConfig( "rn_introhud_y", -265 );
    zpSetConfig( "rn_introhud_fontscale", 16 );

        // Score Highlight font size
    zpSetConfig( "score_highlighthud_fontscale", 8 );
    
        // Score Highlight color for positive score
    zpSetConfig( "score_highlighthud_pluscolor", ( 0.9, 0.9, 0.0 ) );
    
        // Score Highlight color for negative score
    zpSetConfig( "score_highlighthud_minuscolor", ( 0.423, 0.004, 0 ) );

            // Display big round introduction ("firstround", "always", "never")
    zpSetConfig( "round_displayintro", "firstround" );
    
            // How many grenades to award survivors of a round
    zpSetConfig( "round_survivor_grenadeaward", 2 );


So at this stage, using it, the level starts, the rounds show correctly, and I can add/subtract score. My next goal are the window/door blockers and allowing them to be torn down as well.

- Bundabrg
Back to top
bundabrg
Fri Dec 19 2008, 03:46PM
Registered Member #276
Joined: Sat Dec 06 2008, 04:12AM
Posts: 15
Quick update. With due respect to the forum owner(s), I'll be posting future updates at: -
http://forums.raidersmerciless.com/showthread.php?t=7453

I'm finding the BB code here a little quirky to work with, and 'code' tags look as if the lines are overwriting each other.

- Bundabrg

[ Edited Fri Dec 19 2008, 03:49PM ]
Back to top
 

Jump:     Back to top

User Colour Key:
Head Administrator, Administrator, Forum Moderator, Member

Syndicate this thread: rss 0.92 Syndicate this thread: rss 2.0 Syndicate this thread: RDF
Powered by e107 Forum System