Welcome to TeX.SE. Problems in your macro:
You are adding unwanted spaces. Please refer to What is the use of percent signs (%) at the end of lines?
If you write \cast{Bob SquarePants}{A sponge}{bob}, when \cast is expanded, the whole will be replaced with:
\oldCast{Bob SquarePants}{A sponge}
\expandafter\newcommand\csname bob\endcsname{\chara #1}
You see, the parameter tokens have been replaced by their values, and the ## has been replaced by a single #. The problem is that after \expandafter is expanded, the last line will become:
\newcommand\bob{\chara #1}
In other words, it defines a macro that takes no argument but contains #1 in its replacement text. This explains the error you obtained: “Illegal parameter number in definition of \bob.” \bob takes 0 arguments, but it is trying to use its first argument, hence an illegal parameter number.
Your definition of the character-specific new command is done using \newcommand, therefore it is local and will be forgotten after \end{castpage} if you use \cast inside \begin{castpage} ... \end{castpage} (environments define a TeX group).
What you need to fix point 2 is to use a single # and add braces around the #1, so that after one expansion step of \cast{Bob SquarePants}{A sponge}{bob}, one obtains:
\oldCast{Bob SquarePants}{A sponge}%
\expandafter\newcommand\csname bob\endcsname{\chara{bob}}%
So, your definition could be:
\let\oldcast\cast
\renewcommand*{\cast}[3]{%
\oldCast{#1}{#2}%
\expandafter\newcommand\csname #3\endcsname{\chara{#1}}%
}
Note that in some cases (most notably commands defined with \newcommand and taking optional arguments, or commands defined with \DeclareRobustCommand), the \let\oldcast\cast won't work the way you want. In such cases, the letltxmacro package can be very useful.
Also, since you are changing the syntax and semantics of \cast, it may be wiser to name your function differently—say, \newcast:
\newcommand*{\newcast}[3]{%
\cast{#1}{#2}%
\expandafter\newcommand\csname #3\endcsname{\chara{#1}}%
}
Now to problem number 3. We need to do the dynamic command definition performed inside \newcast global. This can be done with \gdef. In order to be über-clean, we can additionally use \newcommand to make sure the command (such as \bob) doesn't already exist. Indeed, \gdef would overwrite an existing command without notice. Thus, we can do the following:
\newcommand*{\newcast}[3]{%
\cast{#1}{#2}%
% Print an error if the command named after #3 is already defined
\expandafter\newcommand\csname #3\endcsname{}%
\expandafter\gdef\csname #3\endcsname{\chara{#1}\ }% there is a control space
}
I added a control space after \chara{#1} because when you write for instance \bob do a flip., from TeX's point of view, there is no space token after \bob: the space character that follows in the input stream is eaten as soon as \bob is turned into a control sequence token (this is during the TeX processing stage known as tokenization).
Finally, the same thing can also be done using \csgdef from the etoolbox package (this is syntactic sugar and behaves the same):
\csgdef{#3}{\chara{#1}\ }
Full code:
\documentclass{sides}
\usepackage{etoolbox}
\newcommand*{\stage}{\stagedir}
\title{MWE}
\author{Foo}
\begin{document}
\maketitle
\newcommand*{\newcast}[3]{%
\cast{#1}{#2}%
% Print an error if the command named after #3 is already defined
\expandafter\newcommand\csname #3\endcsname{}%
\csgdef{#3}{\chara{#1}\ }% there is a control space before the brace
}
\begin{castpage}
\newcast{Bob SquarePants}{A sponge}{bob}
\newcast{Patrick Star}{A starfish}{pat}
\end{castpage}
\newact
\newscene
\show\bob
\stage{Opens on a black stage.}
\repl{Bob SquarePants} I will do a flip!
\stage{\bob do a flip.}
\repl{Patrick Star} Amazing!
\stage{\bob smiles and \chara{Patrick} applauds.}
\end{document}

\newcastinside a group. The dynamic definition has to be global, then; please see the updated answer. I removed\usepackage[T1]{fontenc}and\usepackage{libertine}from the MWE because they are not relevant to the question; feel free to readd them on your side. – frougon May 12 '20 at 15:27\newcommand*{\newcast}[4]{% \cast{#1\ #2}{#3}% \expandafter\newcommand\csname #4\endcsname{}% \csgdef{#4}{\chara{#1}\ } }– MisterJack49 May 12 '20 at 16:04{\chara{#1}\ }instead of{\chara{#1} }) is that a control space always adds an interword glue (space) to the horizontal list, whereas a space token can add a glue item of varying width depending on what precedes (for instance, in English, after a sentence-ending period, the space is larger than an interword space). Normally, this only matters in corner cases where punctuation precedes the space; now, you know the difference and can choose appropriately. – frougon May 12 '20 at 16:09{\chara{#1}\xspace}from the packagexspacebecause I noticed that\bob, foogave the resultBob , fooinstead ofBob, foo.xspaceis able to determine is he should put a space or not https://ctan.org/pkg/xspace – MisterJack49 May 12 '20 at 18:14xspace's original author. In short, maybe you should consider handling this manually, i.e. writing\bob\or\bob,in the script, depending on the particular sentence. – frougon May 12 '20 at 20:18