The method I prefer is using a hash table to track responses:
Code:
on *:text:!command:#: {
  var %unset = 60, %limit = 3

  ; add to a TABLE "flood" the ITEM "<$cid><$chan><$nick><randomnumber>" with DATA "<dummy-char>". the item unsets after %unset seconds
  ; you might as well add items to the table tracking the user's hostmask instead of nicknames ("$site" instead of "$nick"), to bypass nickchanges and increase protection vs. clones
  hadd $+(-mu,%unset) flood $+($cid,$chr(1),$chan,$chr(1),$nick,$chr(1),$rand(1,9999)) x

  ; response only if the number of items matching <$cid><$chan><$nick>* is below %limit
  if ($hfind( flood, $+($cid,$chr(1),$chan,$chr(1),$nick,$chr(1),*) ,0,w) < %limit) {

    ; your response here
    msg # my response
  }
}


You might alternatively group all your !commands (triggers) into one on text event and use it as some "global" protection, like:
Code:
on *:text:*:#: {
  ; text is one of your commands
  if ($istok(!command1 !command2 !commandN,$1-,32)) {
    var %unset = 60, %limit = 3

    hadd $+(-mu,%unset) commands $+($cid,$chr(1),$chan,$chr(1),$nick,$chr(1),$rand(1,9999)) x
    if ($hfind( commands, $+($cid,$chr(1),$chan,$chr(1),$nick,$chr(1),*) ,0,w) < %limit) {

      ; your responses
      if ($1 == !command1) { msg # response 1 }
      elseif ($1 == !command2) { msg # response 2 }
      elseif ($1 == !commandN) { msg # response N }
    }
  }
}

The above code should give you a basic idea. You can extend this kind of protection with other wildmasks for $hfind(w) - some examples are in this thread smile