Modifications to BullCows

I made one quality-of-life adjustment increasing the size of the sign, as well as the column and line count & decreased the font size to have more guesses logged.

I also tried to implement difficulty, but I can’t get it to work yet.

I wrote the function

void UBullCowCartridge::DifficultyPrompt(FString Choice)//asking for difficulty setting

{

    PrintLine(TEXT("Select Difficulty:\n[E]asy\n[F]air\n[C]hallenging\n[N]ightmare\n[U]ltra Nightmare"));

}

to prompt the player to pick a difficulty, and then

void UBullCowCartridge::DifficultySelection()

{

    DifficultyPrompt(Choice);//choice registered

    {

        Isograms = GetValidWords(Words);

        HiddenWord = Isograms[FMath::RandRange(0, Isograms.Num() - 1)];

        if (Choice = DiffArray[0])

        {

            Lives = HiddenWord.Len() * 3;

            return;

        }

        if (Choice = DiffArray[1])

            return;

        {

            Lives = HiddenWord.Len() * 2;

            return;

        }

        if (Choice = DiffArray[2])

        {

            Lives = HiddenWord.Len();

            return;

        }

        if (Choice = DiffArray[3])

        {

            Lives = HiddenWord.Len() / 2;

            return;

        }

        if (Choice = DiffArray[4])

        {

            Lives = HiddenWord.Len() / 3;

            return;

        }

        else

        {

            PrintLine(TEXT("Please make a valid selection."));

            return;

        } 

    }

    return Isograms;

    return Lives;

    return HiddenWord;

}

to adjust the lives count based on the choice. I pulled Isograms and HiddenWord insto the second function and then have it return Isograms, HiddenWords and Lives to use in the later functions.

I made the array to evaluate the choice of difficulty a separate list modeled on the HiddenWordList.h

But I can’t get it to run. I have been futzing around with it for the last 6ish hours, and I am just chasing my tail on whether the functions should be constant, be made structs, anything else I can think of to make it work. I think I have the nesting right, I tried to model it on the hierarchy we used for taking in and processing the guess.

This is how I modified SetupGame()

void UBullCowCartridge::SetupGame()//asking for guess

{

    

    DifficultySelection(Choice);

        

    //ProcessDifficulty(Choice);********************

    //Lives = HiddenWord.Len() * 2;

    bGameOver = false;

    PrintLine(TEXT("Welcome to Bulls and Cows!\nGuess the %i letter isogram."), HiddenWord.Len());

    PrintLine(TEXT("Bull: Letter in the correct position.\nCow: Correct letter in the wrong position.Letters don't repeat."));

    PrintLine(TEXT("You have %i tries."), Lives);

    PrintLine(TEXT("\nMake your first guess and press [ENTER]."));

}

calling the function that should return Lives, HiddenWord and Isograms.

This is the state of my BullCowCartridge.h:

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"

#include "Console/Cartridge.h"

#include "BullCowCartridge.generated.h"

struct FBullCowCount

{

    int32 Bulls = 0;

    int32 Cows = 0;

};

UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))

class BULLCOWGAME_API UBullCowCartridge : public UCartridge

{

    GENERATED_BODY()

    public:

    virtual void BeginPlay() override;

    virtual void OnInput(const FString& Input) override;

    void SetupGame();

    void EndGame();

    void WinGame();

    void ProcessGuess(const FString& Guess);

    bool IsIsogram(const FString& Word) const;

    TArray<FString> GetValidWords(const TArray<FString>& WordList) const;

    FBullCowCount GetBullCows(const FString& Guess) const;

    void DifficultyPrompt(FString Choice);

    void DifficultySelection();

    

    // Your declarations go below!

    private:

    FString HiddenWord;

    int32 Lives;

    bool bGameOver;

    TArray<FString> Isograms;

};

I welcome any ideas/observations/help to send me on my way

1 Like

I think a function that does a single function call has no value. The parameter is also unused.

This is an assignment not a comparison. Also what’s DiffArray?

That’s not how that works.

  1. void functions can’t return any value. Doing so would result in a compilation error.
  2. You can’t return multiple values and of differing types like that. It would need to be a encapsulated in a type that can hold multiple values like FBullCowCount was.
  3. As these are member variables they don’t need to be returned to the calling code.

To give you an idea of the basic structure of a solution and assuming DiffArray would be different word lists.

Using standard C++

// These being declared somewhere.
// std::vector = TArray, std::string = FString.

// Word lists based on difficulty
// std::vector<std::vector<std::string>> WordLists;
// std::vector<std::string> SelectedWordList;


// Get input
std::cout << "Choose your difficulty\n";
int Difficulty;
std::cin >> Difficulty;

//Reject Invalid
while (Difficulty < 0 || Difficulty >= WordLists.size())
{
    std::cout << "Invalid input, try again\n";
    std::cin >> Difficulty;
}

WordLists = WordLists[Difficulty];
1 Like

My DiffArray looks like this:

#pragma once

#include "CoreMinimal.h"

const TArray<FString> DiffArray = 

{

    TEXT("E"),

    TEXT("F"),

    TEXT("C"),

    TEXT("N"),

    TEXT("U")

};

I am trying to run this:

void UBullCowCartridge::DifficultyPrompt()//asking for difficulty setting

{

    PrintLine(TEXT("Select Difficulty:\n[E]asy\n[F]air\n[C]hallenging\n[N]ightmare\n[U]ltra Nightmare"));

}

to get an input from the player and then use it here


void UBullCowCartridge::ProcessDifficultySelection(const FString& Input)

{

    //DifficultyPrompt();//choice registered

    {

        Isograms = GetValidWords(Words);

        HiddenWord = Isograms[FMath::RandRange(0, Isograms.Num() - 1)];

        if (Choice == DiffArray[0])

        {

            Lives = HiddenWord.Len() * 3;

            return;

        }

        if (Choice == DiffArray[1])

            return;

        {

            Lives = HiddenWord.Len() * 2;

            return;

        }

        if (Choice == DiffArray[2])

        {

            Lives = HiddenWord.Len();

            return;

        }

        if (Choice == DiffArray[3])

        {

            Lives = HiddenWord.Len() / 2;

            return;

        }

        if (Choice == DiffArray[4])

        {

            Lives = HiddenWord.Len() / 3;

            return;

        }

        else

        {

            PrintLine(TEXT("Please make a valid selection."));

            return;

        } 

    }

}

to determine how many lives they are playing with.

So the player types either E, F, C, N, or U, and then I use one of those choices to adjust the lives-count, then play the game as usual.

I can’t figure how how to place the functions so that the difficulty selection happens before the prompt to guess the hidden word. Is what I am thinking of really an entire new game with a different structure to it, and not something I can simply add on/splice into the vanilla class game?

Thank you

So a couple things

  1. Isograms = GetValidWords(Words). Should remain in BeginPlay, you don’t need to generate the word list on each game.

  2. What is Choice and where is it being assigned? Where is it getting that information from what is input?

  3. You don’t need DiffArray.

    Choice == TEXT('C') || Choice == TEXT('c');
    

    Or

    FChar::ToUpper(Choice) == TEXT('C')
    
  4. Remember that OnInput is called whenever the user presses Enter. As you now can’t use SetupGame without getting the selected difficulty it doesn’t make sense to call it in BeginPlay as it’ll have to redo that pretty much straight away.

    So if you give bGameOver the default value of true in the header then all you would need to do is create another function that takes the input and does the check for the difficulty and if it was valid call SetupGame with that value (you would need to modify SetupGame for that) otherwise do nothing (or be helpful and give a nice error message).

    With that your OnInput function should be something like

    if (bGameOver)
    {
        ClearScreen();
        NewSetupGame(Input); // or rename SetupGame(int32) to something else
    }
    

    So NewSetupGame would call the old one only if what was entered was a valid difficulty.

Thank you Dan.

create another function that takes the input and does the check for the difficulty and if it was valid call SetupGame with that value

How do I do that? I am getting hung up on how to accept and then process another player input to decide difficulty. I can’t quite wrap my head around what it is that I am doing wrong.

I figured if I make bGameOver == true the default, I would want to use bGameOver == false to tell whether a difficulty was chosen? But I couldn’t figure out the part where I wait for an input. Or how to call on an input.

This is what I have tried, unsuccessfully:

#include "BullCowCartridge.h"
#include "HiddenWordList.h"
#include "Math/UnrealMathUtility.h"
//#include "DifficultyList.h"

void UBullCowCartridge::BeginPlay() // When the game starts
{
    Isograms = GetValidWords(Words);
    Super::BeginPlay();
    
    //int32 Number;
    //SetupGame();
    NewSetupGame();
}

void UBullCowCartridge::OnInput(const FString& Input) // When the player hits enter, taking guess
{
    if (bGameOver)
    {
        ClearScreen();
        NewSetupGame();
    }
    else // check player guess
    {
        ProcessGuess(Input);//using guess 
    }  
}

void UBullCowCartridge::ProcessDifficultySelection(const FString& Input)
{
    PrintLine(TEXT("Select Difficulty:\n[E]asy\n[F]air\n[C]hallenging\n[N]ightmare\n[U]ltra Nightmare"));
}

void UBullCowCartridge::NewSetupGame(FString Input)
{
    ProcessDifficultySelection();
    {
        {
            if (Input == TEXT('e')||Input == TEXT('E'))
            {
                Lives = HiddenWord.Len() * 3;
                bGameOver = false;
                // return;
            }
            if (Input == TEXT('f')||Input == TEXT('F'))
                bGameOver = false;
                // return;
            {
                Lives = HiddenWord.Len() * 2;
                bGameOver = false;
                // return;
            }
            if (Input == TEXT('c')||Input == TEXT('C'))
            {
                Lives = HiddenWord.Len();
                bGameOver = false;
                // return;
            }
            if (Input == TEXT('n')|| Input == TEXT('N'))
            {
            Lives = HiddenWord.Len() / 2;
                bGameOver = false;
                // return;
            }
            if (Input == TEXT('u')||Input == TEXT('U'))
            {
                Lives = HiddenWord.Len() / 3;
                bGameOver = false;
                // return;
            }
        if (bGameOver == false);
        {
            SetupGame();
        }
        else
        {
            PrintLine(TEXT("Please make a valid selection."));
        }
        
    }
}

void UBullCowCartridge::SetupGame()//asking for guess
{
    HiddenWord = Isograms[FMath::RandRange(0, Isograms.Num() - 1)];
    
    
    //DifficultySelection();
    
    //Lives = HiddenWord.Len() * 2;
    bGameOver = false;

    PrintLine(TEXT("Welcome to Bulls and Cows!\nGuess the %i letter isogram."), HiddenWord.Len());
    PrintLine(TEXT("Bull: Letter in the correct position.\nCow: Correct letter in the wrong position.Letters don't repeat."));
    PrintLine(TEXT("You have %i tries."), Lives);
    PrintLine(TEXT("\nMake your first guess and press [ENTER]."));
}

void UBullCowCartridge::WinGame()
{
    bGameOver = true;
    ClearScreen();
    PrintLine(TEXT("Congratulations!\nYou Win!"));
    PrintLine(TEXT("\n\nPress [ENTER] to play again."));
}

void UBullCowCartridge::EndGame()
{
    bGameOver = true;
    ClearScreen();
    PrintLine(TEXT("No more tries. \n\nThe word was %s."), *HiddenWord);
    PrintLine(TEXT("\n\nPress [ENTER] to play again."));
}

void UBullCowCartridge::ProcessGuess(const FString& Guess)
{
    if (Guess == HiddenWord)
    {
        WinGame();
        return;
    }
    if (Guess.Len() != HiddenWord.Len())
    {
        PrintLine(TEXT("The isogram is %i characters long.\nYou entered %i characters."), HiddenWord.Len(), Guess.Len());
        //SetupGame(); //changed from EndGame();  -- I don't want a reset
        return;
    }

    if (!IsIsogram(Guess))  //keep commented
    {
        PrintLine(TEXT("Isograms don't have repeat letters,\ntry again!"));
        return;
    } 
    
    else
    {
        --Lives; //this also works: Lives = Lives-1;
        //PrintLine(TEXT("That was not the right isogram."));
        //Show Bulls and Cows
   
    FBullCowCount Score = GetBullCows(Guess);

    PrintLine(TEXT("Incorrect: %i bull/s, %i cow/s, tries: %i"), Score.Bulls, Score.Cows, Lives);
        if (Lives == 0)
        {
            EndGame();
        }    
        return;
    }
    
}

bool UBullCowCartridge::IsIsogram(const FString& Word) const
{
    for (int32 Index = 0; Index < Word.Len(); Index++)
    {
        for (int32 Comparison = Index + 1; Comparison < Word.Len(); Comparison++)
        {
            if (Word[Index] == Word[Comparison])
            {
                return false;
            }
        }
    }
    return true;
}

TArray<FString> UBullCowCartridge::GetValidWords(const TArray<FString>& WordList) const
{
    TArray<FString> ValidWords;

    for (FString TempVar : WordList)
    {
        if (TempVar.Len() >= 4 && TempVar.Len() <= 6 && (IsIsogram(TempVar)))
        {
            ValidWords.Emplace(TempVar);
        }
    }
    return ValidWords;    
}

FBullCowCount UBullCowCartridge::GetBullCows(const FString& Guess) const
{
    FBullCowCount Count;
    for (int32 GuessIndex = 0; GuessIndex < Guess.Len(); GuessIndex++)
    {
        if (Guess[GuessIndex] == HiddenWord[GuessIndex])
        {
            Count.Bulls++;
            continue;
        }
        
        for (int32 HiddenIndex = 0; HiddenIndex < HiddenWord.Len(); HiddenIndex++)
        {
            if (Guess[GuessIndex] == HiddenWord[HiddenIndex])
            {
                Count.Cows++;
                break;
            }
        }
    }
    return Count;
}

This is my header file:

#pragma once

#include "CoreMinimal.h"
#include "Console/Cartridge.h"
#include "BullCowCartridge.generated.h"

struct FBullCowCount
{
	int32 Bulls = 0;
	int32 Cows = 0;
};

UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class BULLCOWGAME_API UBullCowCartridge : public UCartridge
{
	GENERATED_BODY()

	public:
	virtual void BeginPlay() override;
	virtual void OnInput(const FString& Input) override;
	void SetupGame();
	void NewSetupGame();
	void EndGame();
	void WinGame();
	void ProcessGuess(const FString& Guess);
	bool IsIsogram(const FString& Word) const;
	TArray<FString> GetValidWords(const TArray<FString>& WordList) const;
	FBullCowCount GetBullCows(const FString& Guess) const;
	void ProcessDifficultySelection();
	
	// Your declarations go below!
	private:
	FString HiddenWord;
	int32 Lives;
	bool bGameOver = true;
	TArray<FString> Isograms;
};

I’m getting lost in the woods somewhere around how to call and then process an input. I tried mimicking the OnInput function in earlier attempts, but it didn’t work as intended. How do I call for an input I can use? I am trying to implement what you are suggesting, but can’t quite get it to work.

The way this project is set up you can only react to the player pressing enter so you have to work around that.

if it was valid call SetupGame with that value (you would need to modify SetupGame for that) otherwise do nothing (or be helpful and give a nice error message).

By this I mean you would have two functions like this

void DifficultySetup(const FString& Input);
void SetupGame(int32 Dificulty);

DifficultySetup would be used in OnInput and SetupGame would be called in DifficultySetup if and only if it was a valid selection.

void UBullCowCartridge::OnInput(const FString& PlayerInput)
{
	if (bGameOver)
	{
		ClearScreen();
		DifficultySetup(PlayerInput);
	}
	else
	{
		ProcessGuess(PlayerInput);
	}
}

void UBullCowCartridge::DifficultySetup(const FString& Input)
{
	FString LowerInput = Input.ToLower();
	if (LowerInput == TEXT("hello"))
	{
		SetupGame(1);
        return;
	}
	if (LowerInput == TEXT("world"))
	{
		SetupGame(2);
        return;
	}
	PrintLine(TEXT("Not a valid selection."));
}

That way bGameOver remains true and you continue this control flow until they enter a valid selection.

This is trying to compare a string to a char. This is sort of what I was getting at by my second bullet point.
What you do here is dependant on what you want, do you only want to check if the first character matches or they type exactly that?

If you just care about the first letter check if the word is not empty and if it’s not check [0].
Otherwise you’d need to use double quotes TEXT("E")

Thank you Dan,

I almost have it working properly. Except that on choosing e for difficulty I was returned 0 lives and after a wrong answer got -1. Shouldn’t Lives carry over to SetupGame() since it is declared in the header?

Here again my code:

#include "BullCowCartridge.h"

#include "HiddenWordList.h"

#include "Math/UnrealMathUtility.h"

//#include "DifficultyList.h"

void UBullCowCartridge::BeginPlay() // When the game starts

{

    Isograms = GetValidWords(Words);

    Super::BeginPlay();

    PrintLine(TEXT("Select Difficulty:\n[E]asy\n[F]air\n[C]hallenging\n[N]ightmare\n[U]ltra Nightmare"));

    //int32 Number;

    //SetupGame();

    //NewSetupGame(Input);

}

void UBullCowCartridge::OnInput(const FString& Input) // When the player hits enter, taking guess

{

    if (bGameOver)

    {

        ClearScreen();

        PrintLine(TEXT("Select Difficulty:\n[E]asy\n[F]air\n[C]hallenging\n[N]ightmare\n[U]ltra Nightmare"));

        NewSetupGame(Input);

    }

    else // check player guess

    {

        ProcessGuess(Input);//using guess 

    }  

}

void UBullCowCartridge::NewSetupGame(FString Input)

{

    {

        {

            if (Input == TEXT("e")||Input == TEXT("E"))

            {

                Lives = HiddenWord.Len() * 3;

                SetupGame();

                // return;

            }

            if (Input == TEXT("f")||Input == TEXT("F"))

            {

                Lives = HiddenWord.Len() * 2;

                SetupGame();

                // return;

            }

            if (Input == TEXT("c")||Input == TEXT("C"))

            {

                Lives = HiddenWord.Len();

                SetupGame();

                // return;

            }

            if (Input == TEXT("n")|| Input == TEXT("N"))

            {

                Lives = HiddenWord.Len() / 2;

                SetupGame();

                // return;

            }

            if (Input == TEXT("u")||Input == TEXT("U"))

            {

                Lives = HiddenWord.Len() / 3;

                SetupGame();

                // return;

            }

            else

            {

                PrintLine(TEXT("Please make a valid selection."));

            } 

        }

        // if (bGameOver == false);

        // {

        //     SetupGame();

        // }   

    }

}

void UBullCowCartridge::SetupGame()//asking for guess

{

    HiddenWord = Isograms[FMath::RandRange(0, Isograms.Num() - 1)];

        

    //DifficultySelection();

    

    //Lives = HiddenWord.Len() * 2;

    bGameOver = false;

    PrintLine(TEXT("Welcome to Bulls and Cows!\nGuess the %i letter isogram."), HiddenWord.Len());

    PrintLine(TEXT("Bull: Letter in the correct position.\nCow: Correct letter in the wrong position.Letters don't repeat."));

    PrintLine(TEXT("You have %i tries."), Lives);

    PrintLine(TEXT("\nMake your first guess and press [ENTER]."));

}

void UBullCowCartridge::WinGame()

{

    bGameOver = true;

    ClearScreen();

    PrintLine(TEXT("Congratulations!\nYou Win!"));

    PrintLine(TEXT("\n\nPress [ENTER] to play again."));

}

void UBullCowCartridge::EndGame()

{

    bGameOver = true;

    ClearScreen();

    PrintLine(TEXT("No more tries. \n\nThe word was %s."), *HiddenWord);

    PrintLine(TEXT("\n\nPress [ENTER] to play again."));

}

void UBullCowCartridge::ProcessGuess(const FString& Guess)

{

    if (Guess == HiddenWord)

    {

        WinGame();

        return;

    }

    if (Guess.Len() != HiddenWord.Len())

    {

        PrintLine(TEXT("The isogram is %i characters long.\nYou entered %i characters."), HiddenWord.Len(), Guess.Len());

        //SetupGame(); //changed from EndGame();  -- I don't want a reset

        return;

    }

    if (!IsIsogram(Guess))  //keep commented

    {

        PrintLine(TEXT("Isograms don't have repeat letters,\ntry again!"));

        return;

    } 

    

    else

    {

        --Lives; //this also works: Lives = Lives-1;

        //PrintLine(TEXT("That was not the right isogram."));

        //Show Bulls and Cows

   

    FBullCowCount Score = GetBullCows(Guess);

    PrintLine(TEXT("Incorrect: %i bull/s, %i cow/s, tries: %i"), Score.Bulls, Score.Cows, Lives);

        if (Lives == 0)

        {

            EndGame();

        }    

        return;

    }

    

}

bool UBullCowCartridge::IsIsogram(const FString& Word) const

{

    for (int32 Index = 0; Index < Word.Len(); Index++)

    {

        for (int32 Comparison = Index + 1; Comparison < Word.Len(); Comparison++)

        {

            if (Word[Index] == Word[Comparison])

            {

                return false;

            }

        }

    }

    return true;

}

TArray<FString> UBullCowCartridge::GetValidWords(const TArray<FString>& WordList) const

{

    TArray<FString> ValidWords;

    for (FString TempVar : WordList)

    {

        if (TempVar.Len() >= 4 && TempVar.Len() <= 6 && (IsIsogram(TempVar)))

        {

            ValidWords.Emplace(TempVar);

        }

    }

    return ValidWords;    

}

FBullCowCount UBullCowCartridge::GetBullCows(const FString& Guess) const

{

    FBullCowCount Count;

    for (int32 GuessIndex = 0; GuessIndex < Guess.Len(); GuessIndex++)

    {

        if (Guess[GuessIndex] == HiddenWord[GuessIndex])

        {

            Count.Bulls++;

            continue;

        }

        

        for (int32 HiddenIndex = 0; HiddenIndex < HiddenWord.Len(); HiddenIndex++)

        {

            if (Guess[GuessIndex] == HiddenWord[HiddenIndex])

            {

                Count.Cows++;

                break;

            }

        }

    }

    return Count;

}

and the header:

#pragma once

#include "CoreMinimal.h"

#include "Console/Cartridge.h"

#include "BullCowCartridge.generated.h"

struct FBullCowCount

{

    int32 Bulls = 0;

    int32 Cows = 0;

};

UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))

class BULLCOWGAME_API UBullCowCartridge : public UCartridge

{

    GENERATED_BODY()

    public:

    virtual void BeginPlay() override;

    virtual void OnInput(const FString& Input) override;

    void SetupGame();

    void NewSetupGame(FString Difficulty);

    void EndGame();

    void WinGame();

    void ProcessGuess(const FString& Guess);

    bool IsIsogram(const FString& Word) const;

    TArray<FString> GetValidWords(const TArray<FString>& WordList) const;

    FBullCowCount GetBullCows(const FString& Guess) const;

    void ProcessDifficultySelection(const FString& Input);

    

    // Your declarations go below!

    private:

    FString HiddenWord;

    int32 Lives;

    bool bGameOver = true;

    TArray<FString> Isograms;

};

Thank you again so much for your help and patience sorting things out for me!

  1. Think of the control flow. When is HiddenWord being assigned a value and when are you calculating Lives?

  2. The chain of ifs you have in NewSetupGame isn’t working how you perhaps think it is. That last else only applies to this statement if (Input == TEXT("u")||Input == TEXT("U"))

  3. You have quite a few redundant {}'s in that function.

  4. It’s likely you don’t quite understand return statements. They return from the function i.e. exit them.

    void UBullCowCartridge::ProcessGuess(const FString& Guess)
    {
       if (Guess == HiddenWord)
       {
           // ...
           return;
       }
       if (Guess.Len() != HiddenWord.Len())
       {
           // code ...
           return;
       }
       if (!IsIsogram(Guess))  //keep commented
       {
           PrintLine(TEXT("Isograms don't have repeat letters,\ntry again!"));
           return;
       } 
       // redundant else
       else
       {
           // code ...
    
           // this is redundant.
           return;
       }   
    }
    

    The else is redundant because there’s no logical way for it to reach that point if any of the if statements are true since they all return if they are.

    The return at the end of the function is redundant because that was what it was going to do anyway at the end of it.

Of course! I moved HiddenWord back into BeginPlay() and it is working how I was hoping.

Thank you for helping me muddle through this :slight_smile:

Doing that would mean subsequent plays are using the previous word’s length. This is why I suggested adding a parameter to SetupGame where you would pass the difficulty selected to it e.g.

if (Input == TEXT('e')||Input == TEXT('E'))
{
    SetupGame(0);
    return;
}

Oh, OK, I will have to look into that. I will report back with how I make do.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.