String concatenation is performed with the $+ identifier. (Example: $nick $+ !).
You could perform a loop and check if each $nick in the channel is in the text. But this will still get awkward responses.
Here is a cleaned up version of your code.
on *:text:*hi*:#: {
var %i 1
while (%i <= $0) {
if ($($+($,%i),2) ison $chan) { halt }
inc %i
}
msg # Hello, $nick $+ !
}
This replies if *hi* is anywhere in the text.