Jump to content

how to structure this type of project


Fiddlesticks

Recommended Posts

Hey guys, I tried asking this question elsewhere and didn't really get an answer

 

I'm looking to code this entire book in PHP: (and from the looks of things its entirely possible)

 

http://www.scribd.com/doc/26519770/Central-Casting-Heroes-of-Legend-by-Paul-Jaquays

 

I'm already at 2000 lines of code, and it seemingly works quite well. However, I'd rather ask the questions now before I run into a block and find out the code I'm writing isn't capable to delivering such changes that this book asks for, specifically modifying social status with the roll of a dice... and a whole bunch of other different types of things.

 

i'm quite the novice in php, but have a somewhat good understanding of how everything flows..

 

I really want some insight... REALLY! this OP will continue posting if you need any more info

 

here's what most of my functions look like so far: (very, very small tidbit of info)

	
class char
{
public function d100() { $RNG = mt_rand(1,100); return $RNG; }
public function d20() { $RNG = mt_rand(1,20); return $RNG; }
public function d16() { $RNG = mt_rand(1,16); return $RNG; }
public function d12() { $RNG = mt_rand(1,12); return $RNG; }
public function d10() { $RNG = mt_rand(1,10); return $RNG; }
        // etc
        private $character = array();
public function create() {
            $this->character['race'] = $this->rollRace($this->d20());
            $this->rollCultureStatus($this->d100());
            return $this->character;
        }
        public function rollRace($dice) { // ** COMPLETE
	switch($dice) {
		case ($dice <= 12): $race = "Human"; break;
		case ($dice == 13 || $dice == 14): $race = "Elf"; break;
		case ($dice == 15 || $dice == 16): $race = "Dwarf"; break;
		case ($dice == 17 || $dice == 18): $race = "Halfling"; break;
		case 19: // CROSSBREED
			for($i = 1; $i <= 2; $i++) {
				switch($cb = $this->d20()) {
					case ($cb <= 6): $derp[$i] = "Human"; break;
					case ($cb == 7 || $cb == : $derp[$i] = "Elf"; break;
					case ($cb == 9 || $cb == 10): $derp[$i] = "Dwarf"; break;
					case ($cb == 11 || $cb == 12): $derp[$i] = "Halfling"; break;
					case ($cb == 13 || $cb == 14): $derp[$i] = "Beastman"; break;
					case ($cb == 15 || $cb == 16): $derp[$i] = "Reptileman"; break;
					case ($cb == 17 || $cb == 18): $derp[$i] = "Orc"; break;
					case ($cb == 19 || $cb == 20): $derp[$i] = "Halforc"; break;
				}
				if($i == 2) {
					$breed1 = $derp[1]; $breed2 = $derp[2];
					if(strcmp($breed1, $breed2) == 0) {$i = 1;} // Equal races, re-roll
					// Humans & Halflings, re-roll
					if($breed1 == "Human" && $breed2 == "Halfling") {$i = 1;}
					if($breed1 == "Halfling" && $breed2 == "Human") {$i = 1;}
					// Orcs & Halforcs, re-roll
					if($breed1 == "Orc" && $breed2 == "Halforc") {$i = 1;}
					if($breed1 == "Halforc" && $breed2 == "Orc") {$i = 1;}
					// Exempt Humans rolling in second race
					if($breed2 == "Human") {$i = 1;}
				}
			}
			$race = $breed1 ."/". $breed2;
			return $race;
		break;
		case 20: // Other races
			switch($this->d10()) {
				case 1:
				case 2:
				case 3: $race = "Beastman"; break;
				case 4:
				case 5: $race = "Reptileman"; break;
				case 6: $race = "Orc"; break;
				case 7:
				case 8:
				case 9:
				case 10: $race = "Halforc"; break;
			}
		break;
		default: $race = "Error in Race generation"; break;
	}
	return $race;
}
/******************************************************************
/* SOCIAL STATUS
/*****************************************************************/
public function rollSocialStatus($dice, $CuMod, $TiMod = 0) {
	if($TiMod >= 1) {
		if($this->d100() >= 95) {
			$dice = ($dice + $CuMod);
			if($dice >= 100) {
				$dice = 99;
			}
		} else {
			$dice = ($dice + $CuMod + $TiMod);
			if($dice >= 100) {
				$dice = 99;
			}
		}
	} else {
		$dice = ($dice + $CuMod);
	}
	switch($dice) {
		case ($dice <= 15): 				// SOCIAL STATUS: DESTITUDE
			$this->character['social'] = $this->destitude;
			// 50% chance for an underworld event
			// BENEFITS
			$this->character['social']['benefits'][] = "- Rank 3 in <i>Dagger & Brawling</i>";
		break;
		case ($dice >= 16 && $dice <= 40): // SOCIAL STATUS: POOR
			$this->character['social'] = $this->poor;
			// BENEFITS
			if($this->d100() <= 50) $this->character['social']['benefits'][] = "- Rank 3 in <i>Dagger & Brawling</i>";
		break;
		case ($dice >= 41 && $dice <= 84): // SOCIAL STATUS: COMFORTABLE
			$this->character['social'] = $this->comfortable;
			// BENEFITS
			$this->character['social']['benefits'][] = "- CHOOSE: A heirloom weapon</i>";
		break;
										   // SOCIAL STATUS: RE-ROLL without CUMOD
		case 85: 
		case 86: $this->rollSocialStatus($this->d100(), 0, $TiMod); break;
		case ($dice >= 87 && $dice <= 95): // SOCIAL STATUS: WELL-TO-DO
			$this->character['social'] = $this->welltodo;
			// BENEFITS
			$this->character['social']['benefits'][] = "- CHOOSE: Two weapons of any type";
			$this->character['social']['benefits'][] = "- CHOOSE: A riding animal";
		break;
		case ($dice >= 96 && $dice <= 99): // SOCIAL STATUS: EXTREMELY WEALTHY
			if($this->d100() <= (1 + $TiMod)) {
				$this->character['social'] = $this->ewealthy;

				if($this->d100() <= 30) $this->character['social']['benefits'][] = "CHOOSE: ". $this->d4() ." other language(s) to speak.";

				$this->character['social']['benefits'][] = "- CHOOSE: Material posessions desired. Unlimited.";
				$this->character['social']['benefits'][] = "- CHOOSE: Minor magical item.";
			} else {						// SOCIAL STATUS: WEALTHY
				$this->character['social'] = $this->wealthy;

				$this->character['social']['benefits'][] = "- Finely furnished home";
				$this->character['social']['benefits'][] = "- Fine clothing";
				$this->character['social']['benefits'][] = "- ". $this->d3() ." Jewelry worth 10x starting money";
				$this->character['social']['benefits'][] = "- CHOOSE: A fine culture-related hand weapon";
				$this->character['social']['benefits'][] = "- CHOOSE: A riding animal";
			}
		break;
		case ($dice >= 100 && $dice <= 110):
			$this->character['culture']['points'] = ($this->character['culture']['points'] - 1);
			$this->character['nobility']['nobile'] = 1;
			$this->character['nobility']['benefits'][] = "+". $this->d4() ." to CHR (where title is known)";
			if($this->d100() >= 50) {
				$quirk = $this->rollPersonalityTrait($this->d20());
				$this->character['nobility']['benefits'][] = "Personality Trait: ". $quirk[0]; // Personality traits
			}
			// d4 HOBBIES if civilized
			if($this->character['culture']['civilized'] == 1) {
				for ($i = 1; $i <= $this->d4(); $i++) {
					$hobbies[$i] = "HOBBY: ". $this->rollHobby($this->d20());
				}
				$results = $this->recursiveArrayShrink($hobbies);
				$this->character['nobility']['hobbies'] = $results;
			} else { // TO-DO: OCCUPATION passed down from parents at rank 4

			}
			$this->character['nobility']['benefits'][] = "CHOOSE: Full set of non-magical weapons & a suit of armor.";
			$this->rollNobility($this->d100());
		break;
		default: return; break;
	}
	// 1d4+2 ranks in occupation handed down 313. TO-DO
	// CALCULATE STAGNANT CULTURE OCCUPATION
	if($this->character['culture']['abbr'] == "sc") {
		if(!isset($this->character['culture']['occupation'])) {
			$this->character['culture']['occupation'] = $this->rollCivilizedOccupation($this->d10(), $this->character['social']['mod']);
		}
	}
	// CALCULATE SKILLPOINTS
	$this->character['culture']['points'] = ($this->character['social']['points'] + $this->character['culture']['points']);
	// CALCULATE LITERACY
	if($this->character['social']['abbr'] == "d") {
		$this->character['social']['literate'] = ($this->d100() <= 5) ? 'Literate in native language.' : 'No';
	} else {
		$chanceofLiteracy = ($this->character['culture']['litmod'] + $this->character['social']['litmod']);
		$this->character['social']['literate'] = ($this->d100() <= $chanceofLiteracy) ? 'Literate in native language.' : 'No';
	}
	// CALCULATE SOCIAL MOD (IF NOBILITY)
	if(isset($this->character['nobility']['title']) && $this->character['nobility']['nobile'] == 1) {
		$this->character['social']['mod'] = ($this->character['social']['mod'] + 5);
	}
}
/******************************************************************
/* GIFTS & LEGACIES
/*****************************************************************/
public function rollGiftsandLegacies($dice) {
	switch($dice) {
		case 1: // WEAPONS
			switch($this->d10()) {
				case 1: $gifts[] = "Ornate dagger."; break;
				case 2: $gifts[] = "Ornate sword."; break;
				case 3: $gifts[] = "Plain sword."; break;
				case 4: $gifts[] = "A mace."; break;
				case 5: $gifts[] = "Ornate spear."; break;
				case 6: $gifts[] = "Well-made short or long bow."; break;
				case 7: $gifts[] = "Ornate battle-axe."; break;
				case 8: $gifts[] = "Any type of crossbow."; break;
				case 9: $gifts[] = "Exotic weapon. (GM Only)"; break;
				case 10: $gifts[] = "An anachronistic weapon."; break;
			}
		break;
		case 2: $gifts[] = "Young companion."; break;
		case 3: // UNUSUAL PETS
			$gifts[] = $this->rollUnusualPet($this->d20(), 0);
		break;
		case 4: // JEWELRY
			$worth = $this->d10();
			if($worth == 10) {
				$worth = $this->d10();
				switch($worth) {
					case 1: $gifts[] = "An extremely valuable Amulet."; break;
					case 2: $gifts[] = "An extremely valuable Necklace."; break;
					case 3: $gifts[] = "Extremely valuable Earrings."; break;
					case 4: $gifts[] = "An extremely valuable Tiara."; break;
					case 5: $gifts[] = "An extremely valuable Torc."; break;
					case 6: $gifts[] = "An extremely valuable Armband."; break;
					case 7: $gifts[] = "An extremely valuable Ring."; break;
					case 8: $gifts[] = "An extremely valuable Broach."; break;
					case 9: $gifts[] = "An extremely valuable Pin."; break;
					case 10: $gifts[] = "An extremely valuable Bracelet."; break;
				}
			} else {
				switch($worth) {
					case 1: $gifts[] = "An amulet."; break;
					case 2: $gifts[] = "A necklace."; break;
					case 3: $gifts[] = "Earrings."; break;
					case 4: $gifts[] = "A tiara."; break;
					case 5: $gifts[] = "A torc."; break;
					case 6: $gifts[] = "An armband."; break;
					case 7: $gifts[] = "A ring."; break;
					case 8: $gifts[] = "A broach."; break;
					case 9: $gifts[] = "A pin."; break;
					case 10: $gifts[] = "A bracelet."; break;
				}
			}
		break;
		case 5: $gifts[] = "A tapestry."; break;
		case 6: $gifts[] = "An anachronistic device."; break;
		case 7: $gifts[] = "A key."; break;
		case 8: $gifts[] = "A sealed book."; break;
		case 9: $gifts[] = "A shield."; break;
		case 10: $gifts[] = "A sealed bottle (determine contents)."; break;
		case 11: $gifts[] = "A tarnished old helm."; break;
		case 12: $gifts[] = "A bound wooden staff."; break;
		case 13: // Roll for horse or something else 25% chance
			if($this->d100() <= 25) {
				$mount = "An unusual riding animal. (DM chooses)";
			} else {
				$mount = "A riding horse."; 
			}
			$gifts[] = $mount;
		break;
		case 14: // LAND DEEDS
			switch($this->d20()) {
				case 1: $gifts[] = "A deed to an apartment building."; break;
				case 2: $gifts[] = "A deed to an ancient fortress."; break;
				case 3: $gifts[] = "A deed to a country manor."; break;
				case 4: $gifts[] = "A deed to a track of jungle."; break;
				case 5: $gifts[] = "A deed to a tavern."; break;
				case 6: $gifts[] = "A deed to a mill."; break;
				case 7: $gifts[] = "A deed to a theatre."; break;
				case 8: $gifts[] = "A deed to ancient ruins."; break;
				case 9: $gifts[] = "A deed to an island."; break;
				case 10: $gifts[] = "A deed to a mine."; break;
				case 11: 
					$item = "A deed to an ancient house. (";
					if($this->d100() <= 50) { $item .= "haunted"; }
					else { $item .= "not haunted"; }
					$item .= ")";
					$gifts[] = $item;
				break;
				case 12: $gifts[] = "A deed to a swampland."; break;
				case 13: $gifts[] = "A deed to a farm."; break;
				case 14: $gifts[] = "A deed to a small keep."; break;
				case 15: $gifts[] = "A deed to a mountain."; break;
				case 16: $gifts[] = "A deed to a mysterious forest."; break;
				case 17: $gifts[] = "A deed to an old temple."; break;
				case 18: $gifts[] = "A deed to an inn."; break;
				case 19:
				case 20: // Re-roll (property on other side of world.)
					$item = $this->rollGiftsandLegacies($dice = 14);
					$item[0] .= " located on other side of the world.";
					$gifts[] = $item;
				break;
			}
		break;
		case 15: $gifts[] = "A musical instrument."; break;
		case 16: // CLOTHING
			switch($this->d20()) {
				case 1: $gifts[] = "A hat."; break;
				case 2: $gifts[] = "A pair of shoes."; break;
				case 3: $gifts[] = "A belt."; break;
				case 4: $gifts[] = "A cape."; break;
				case 5: $gifts[] = "A tunic."; break;
				case 6: $gifts[] = "Pants."; break;
				case 7: $gifts[] = "A pair of stockings."; break;
				case 8: $gifts[] = "A robe."; break;
				case 9: $gifts[] = "A pair of boots."; break;
				case 10: $gifts[] = "A wig."; break;
				case 11: $gifts[] = "An unusual coat."; break;
				case 12: $gifts[] = "A military uniform."; break;
				case 13: $gifts[] = "A dress."; break;
				case 14: $gifts[] = "Priestly garments."; break;
				case 15: $gifts[] = "A toga."; break;
				case 16: $gifts[] = "Gloves."; break;
				case 17: case 18: case 19: case 20: // Roll d4 times on this subtable.
					for($i = 1; $i <= $this->d4(); $i++) {
						$gifts[] = $this->rollGiftsandLegacies($dice = 16);
					}
				break;
			}
		break;
		case 17: // POUCH OF PAPERS
			switch($this->d10()) {
				case 1: $gifts[] = "An ancient ancestor's letter to his descendants."; break;
				case 2: $gifts[] = "A map."; break;
				case 3: $gifts[] = "An undelivered letter."; break;
				case 4: $gifts[] = "Diagrams and plans for a mysterious invention."; break;
				case 5: $gifts[] = "A scroll of magic spells."; break;
				case 6: $gifts[] = "A wild story of adventure."; break;
				case 7: $gifts[] = "A last will and testament. The character is an heir."; break;
				case 8: $gifts[] = "A treasure map."; break;
				case 9: $gifts[] = "The character's true (and colorful) family history."; break;
				case 10: // d3 more items on this table, ignore 2nd result of 10
					for($i = 1; $i <= $this->d3(); $i++) {
						$item = $this->rollGiftsandLegacies($dice = 17);
						$gifts[] = $item[0];
					}
				break;
			}
		break;
		case 18: // SEALED TRUNK: 60% chance that it contains d3+1 additional items on this table.
			if($this->d100() <= 60) {
				$gifts[] = "A sealed trunk with contents:";
				$this->amountGiftsSealedTrunk = $this->d3() + 1;
				$i = 1;
				while($i <= $this->amountGiftsSealedTrunk) {
					$item = $this->recursiveArrayShrink($this->rollGiftsandLegacies($this->d20()));
					$item[0] = "   <i>". $item[0];
					$item[0] .= "</i>";
					$gifts[] = $item;
					$i++;
				}
				$this->amountGiftsSealedTrunk = 0;
			} else {
				$gifts[] = "A sealed trunk that is empty.";
			}
		break;
		case 19: $gifts[] = "Chain mail."; break;
		case 20: // EXTREMELY MAGICAL: Re-Roll, resulting item definately has magic properites and is a destiny deciding item.
			$item = $this->recursiveArrayShrink($this->rollGiftsandLegacies($this->d20()));
			$item[0] .= " Extremely magical.";
			$gifts[] = $item;
		break;
		default: $gifts[] = "Error in Gifts & Legacies generation"; break;
	}
	return $gifts;
}

 

I do own the original book (the pdf is different), and the reason im making this is well, instead of rolling manually and taking forever it'll all be done in one click.

Link to comment
Share on other sites

However, I'd rather ask the questions now

 

What is your question? Please tell me your question isn't to read this (large) snippet of code and make overall suggestions on your entire project without any sort of further information.

 

yeah, no way.

 

My question was in the thread title. The link I put in the thread is what the project is-- a book that makes character backgrounds based on a roll of the dice on multiple tables, subtables within those tables (like re-rolling on a 20, add 1d3+1 more items on this subtable) type of things. Curses, blessings, body locations for serious injuries, e.t.c.

 

There are sections in the book that throw you into the military based on a roll on the adult events table, and within the military tables there's 8 other tables (to determine ranks, combat, skills you've learned, e.t.c), sometimes you might roll something that may change your social status later on, or culture.

 

The first thing the book determines is your culture, then your social status... social status may determine if you are a noble, or a poor character. Then you have where you were born, and your birth events that trail into around 10-15 different subtables alone. Then adolescence, 20-25 different tables. Adulthood is anywhere in the book.. which could go from 1 table, to another table, to another table and if I need to edit certain data that's already been processed (like social status), would I put all that in a global array and just say $this->character['social'] = new socialstatus?

 

An idea of size and scope is all. My first attempt at making something this somewhat complicated... im not asking to write code for me, just give me a hint on what  the best method would be is to structure the data... i've already got most of the culture, social status, birth place and birth events done and all the data is generated into one huge array $this->character

 

is throwing everything into an array and returning it the best possible option for each individual function?

how would I exempt a re-roll on a subtable that only wants to roll a 12 or a 13 once. (roll a 12 or 13 on a table, table says can't re-roll a 12 or 13)

 

Link to comment
Share on other sites

With something as complicated and dynamic as you are describing, my suggestion is to sort things in the user's member table row, broken up categorically and stored in a condensed array called a serialized array.  You could then use those values to relationally check against the properties of the associated table.  Storing the values serialized gives you flexibility without having to worry about gigantic tables.

 

To explain my opinion:

You're going to have a cobweb of related tables with related values that will establish your hierarchal data flow - much akin to how forums operate.  Military, per your example, has many different children that belong only to it, which may in turn have children which belong on to that parent.  In turn, one user's Military may look like:

Military: Rank (rookie) // SKills (x, y, z, 1, 2, 3) // Combat (10 str).

 

The users_table could be broken down categorically like so:

user_name | salt | password | email | ... | military | culture | ...

 

You can store all of the user's military data in one array (like you correctly assumed) into their user row via serialize() - and likewise with their subsequent categorical skillsets / information.

 

how would I exempt a re-roll on a subtable that only wants to roll a 12 or a 13 once. (roll a 12 or 13 on a table, table says can't re-roll a 12 or 13)

I think a master rule reference table would suffice the situation. You can use this table to cross-reference and set limits upon the actions of certain categories/subcats depending on the flags they carry dependent on how they are referenced in the master table.

Link to comment
Share on other sites

Don't have much time to go over your code at the moment, but I couldn't help but notice all of your base dice roll methods.  Why not consolidate them like so:

 

public function rollDice($sides) {
    return mt_rand(1, $sides);
}

 

You could then use it like:

 

return $this->rollDice(6); // d6
return $this->rollDice(20); // d20

 

Remember - the whole point of functions/object methods is to create as abstract, reusable code as you possibly can.

Link to comment
Share on other sites

keep posting, want to see how far you get...

 

to answer your subject:

 

You need a DB.  Which leads me to a ?  Once you load all this data into a BFA(big friggin array), how do you make changes to that data? Like when one levels up?  What if you need to add a new amulet, or fist 'of goodness'?

Link to comment
Share on other sites

Don't have much time to go over your code at the moment, but I couldn't help but notice all of your base dice roll methods.  Why not consolidate them like so:

 

public function rollDice($sides) {
    return mt_rand(1, $sides);
}

 

You could then use it like:

 

return $this->rollDice(6); // d6
return $this->rollDice(20); // d20

 

Remember - the whole point of functions/object methods is to create as abstract, reusable code as you possibly can.

 

Thanks Kevin! that looks a lot better, I also added these:

 

	private function rollDiceHalved($sides) { return ceil(mt_rand(1, $sides)/2); } // For the sake of rolling a d6 and dividing by 2, or a d4. LEGITIMACY!
private function rollDiceExempt($sides, $doNotRoll = array()) { 
	$dice = mt_rand(1, $sides);
	if(isset($doNotRoll)) {
		if(in_array($dice, $doNotRoll)) {
			$dice = $this->rollDiceExempt($sides, $doNotRoll);
			return $dice;
		} else {
			return $dice;
		}
	}
}

 

now with that function I can actually filter out dice rolls :), also another somewhat hacky fix for re-rolling on subtables.

 

				if(isset($this->donotreroll) && $this->donotreroll == 1) { $subDice = $this->rollDiceExempt(10, array(10)); }
			else { $subDice = $this->rollDice(10); }
			switch($subDice) {
				case 1: $gifts[] = "An amulet."; break;
				case 2: $gifts[] = "A necklace."; break;
				case 3: $gifts[] = "Earrings."; break;
				case 4: $gifts[] = "A tiara."; break;
				case 5: $gifts[] = "A torc."; break;
				case 6: $gifts[] = "An armband."; break;
				case 7: $gifts[] = "A ring."; break;
				case 8: $gifts[] = "A broach."; break;
				case 9: $gifts[] = "A pin."; break;
				case 10: // re-roll, ignore 2nd result of 10. Resulting item is extremely valuable.
					$this->donotreroll = 1;
					$item = $this->rollGiftsandLegacies($dice = 4);
					$item[0] .= " Extremely valuable.";
					$gifts[] = $item;
					$this->donotreroll = 0;
				break;
			}

 

I rigged the dice rolls and it seems to hold up quite well after a plethora of refreshes. It doesn't give me $item. Extremely valuable. Extremely valuable. etc... so hooray!

 

@Mahngiel, it's all generated within a few seconds without using any database whatsoever... I'll think about that though thank you :)

Link to comment
Share on other sites

private function rollDiceExempt($sides, $doNotRoll = array()) { 
	$dice = mt_rand(1, $sides);
	if(isset($doNotRoll)) {

 

Just wanted to point out that the isset() in the above code is always true. Remove the if(isset($doNotRoll)) line and update the lines below to:

 

if(is_array($doNotRoll) && in_array($dice, $doNotRoll)) {
			$dice = $this->rollDiceExempt($sides, $doNotRoll);
			return $dice;
		} else {
			return $dice;
		}

Link to comment
Share on other sites

some simple stuff.  rollDice() is rolling a die, or rolling more than one?  looks like rollDice originally was a random number from how many sides the dice(die) had.  semantically this is moot(singular vs. multi), logically, it's not.  The number of dice, and their potential values are the important things.  So make a truly, useful, generic rollDice fn:

 

public function rollDice(xvars){...};

 

xvar = the parameters we pass, and they can of type...

 

This has been done before, google 'PHP dice'....

 

anyway:

 

public function rollDice($value, $inc, $exc, $off){};

 

$value replaces $sides, coz, it is an array that holds the sides value??  array size is num sides.

 

As you have boolean for do not reroll, then reroll is possible, and the above function can recurse, for when that happens.

 

we need to know what the expected value of the fn is, even before the params, but, we'll assume

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.