This is the new home of the egghelp.org community forum.
All data has been migrated (including user logins/passwords) to a new phpBB version.


For more information, see this announcement post. Click the X in the top right-corner of this box to dismiss this message.

Help with my old script Trivia 2000 please

Help for those learning Tcl or writing their own scripts.
I
Ian-Highlander
Op
Posts: 165
Joined: Mon Sep 24, 2001 8:00 pm
Location: Ely, Cambridgeshire

Post by Ian-Highlander »

Ok, I'm having another problem that no doubt is something really simple again. Whilst TCL is coming back to me bit by bit there are large gaps still in my basic knowledge which are causing me issues.

I'm working on the new major rebuild of this script and one of the functions (which I've got working perfectly apart from this exception) is that instead of having to issue the command !start for each question you can now issue !start ** (where ** represents the number of questions you want in the round) up to a max number of questions preconfigured in the script and also configurable with a public command. Its one of the most commonly requested updates people email me about constantly. Anyway I've got it working for the most part, there is now a public command that picks up the number of questions requested, checks it against the maximum number configured and then starts a counter, the questions then start and off it goes. I've got it working for two out of three scenarios so far, if you get the answer right and its your first ever win and if you get it right and you've won before (different parts of a proc for each so the code to return to the counter proc was required in both places).

The issue I'm having is that when no one gets the answer right there is a utimer that kicks in and sends it to another proc which basically was designed to tell them they didnt get it right and reset all functions, stopping the game. As nobody got it right, it didnt need to know any of the normal variables (nick uhost hand chan) so they quite rightly aren't declared at the beginning of the proc. Here's the issue, because the other procs (the counter and the main game start code require those variables, the no_answer proc isnt passing all the information back to them and the script errors out. If I add the variables to the code it simply gives the usual, null value for x error and errors out again. I cant for the life of me (and no doubt its simple) get it to return to the counter proc with the right information for the counter to carry on the round and start asking questions again.

Here's the relevant pieces of code, can someone show this silly old fool what he's doing wrong please. :D

This is part of the new code that checks if this is a multiple question round or not and plays the game accordingly by running "start_game".

Code: Select all

#Are we playing more than one question at a time and is it within the maximum set in the config at the top?
proc start_game_check {nick uhost handle channel args} {
   global questtoask maxquesttoask
	set questtoask [lindex $args 0]
	if {$questtoask == ""} {
	start_game $nick $uhost $handle $channel
} else {
	if {$questtoask > $maxquesttoask} {
	putserv "PRIVMSG $channel :Sorry\002\ $nick\002 the maximum number of questions per round is set to\002\ $maxquesttoask\002, please retry."
return 0
}
	count_questions $nick $uhost $handle $channel
}
}

#Procedure to keep count of and track the number of questions asked in a round.
proc count_questions {nick uhost handle channel args} {
   global questtoask questannounce
	if {$questtoask == ""} {
return 0
} else {
	if {$questtoask == "0"} {
	putserv "PRIVMSG $channel :That is the end of the current round."
	set questtoask ""
return 0
} else {
	if {($questannounce == "1") && ($questtoask == "1")} {
	putserv "PRIVMSG $channel :This is the last question in this round"
	set questtoask [expr $questtoask-1]
} elseif {($questannounce == "1") && ($questtoask > "1")} {
	putserv "PRIVMSG $channel :There are $questtoask questions left in this round"
	set questtoask [expr $questtoask-1]
} else {
	set questtoask ""
	set gameplaying "0"
return 0
}
	start_game $nick $uhost $handle $channel
}
}
}
This is the part of the code that generates the question, waits for the answer and has the timer in it for the "no_answer" proc.

Code: Select all

	set ques_pair [lindex $quest $questionno]
	set puzzle [lindex [split $ques_pair :] 1]
	set answer [lindex [split $::ques_pair :] 0]

#DEBUG LINE - SHOWS ANSWER BEFORE QUESTION FOR TESTING PURPOSES ONLY
        putserv "PRIVMSG $chan :DEBUG - $answer"

	bind pubm -|- * answercheck
	putserv "PRIVMSG $chan :Question.......\00304$puzzle"
	incr questionno
	utimer 25 no_answer
	setuser $player XTRA wcount.$chan $questionno
The code that checks the answer and passes it to the "winner" proc if its right.

Code: Select all

proc answercheck {nick uhost handle channel arg} { 
   global answer
	if {[string equal -nocase $answer $arg]} { 
	winner $nick $uhost $handle $channel
}
return
}
The code that reacts if its the users first ever win (the user adding code has already run at this point) The important new line is the last one which sends it back to the counter and keeps the game playing. There is a similar addition to the code for if you have won before.

Code: Select all

	set chan $gamechan
	putserv "PRIVMSG $chan :$nick this is your first ever win!!!...\00304Now try and win again!"
	set score [lappend score $handle]
	set score [lappend score 1]
	set score [lappend score 1]
	set fd [open $scores w]
	foreach line $score {
	puts $fd $line
}
	close $fd
	set gameplaying 0
	set chan ""
	count_questions $nick $uhost $handle $channel
The proc that is invoked if the right answer isnt given in the time specified in the utimer above. Checks if it's supposed to tell the channel the answer or not (another new function in the new version of the script) and stops the game. As shown at the bottom I tried just sending it back to count_questions using the same line of code, however it fails because the variables arent declared in the proc. If I declare them it fails because they are null. There has to be another way of doing it but I cant for the life of me see what or where and have been staring at it solidly for three days now.

Code: Select all

#If no one gets it right within the alloted time, stop game and reset.
proc no_answer {} {
   global gameplaying answer chan gamechan questtoask giveanswer
	set chan $gamechan
	if {$giveanswer == "0"} {
	putserv "PRIVMSG $chan :No body got it right!!.....\00304Try Again!!"
}
	if {$giveanswer == "1"} {
	putserv "PRIVMSG $chan :No body got it right!!.....The answer was \00304$answer"
}
	kill_timers
	unbind pubm -|- * answercheck
	set gameplaying 0
	set chan ""
	count_questions $nick $uhost $handle $channel
return 0
}
Once again guys, any help is hugely appreciated, this is another niggly little thing that is driving me insane again. I'm having nightmares about this code now :D
"Insanity Takes Its Toll, Please Have Exact Change"
User avatar
demond
Revered One
Posts: 3073
Joined: Sat Jun 12, 2004 9:58 am
Location: San Francisco, CA
Contact:

Post by demond »

generally, you have 2 options: either use global variables to save what you will need in other procs (for example, the channel), or pass the necessary info as parameters, in which case for [utimer] you need to use:

Code: Select all

utimer 25 [list no_answer $nick $uhost $handle $channel]
I
Ian-Highlander
Op
Posts: 165
Joined: Mon Sep 24, 2001 8:00 pm
Location: Ely, Cambridgeshire

Post by Ian-Highlander »

demond wrote:generally, you have 2 options: either use global variables to save what you will need in other procs (for example, the channel), or pass the necessary info as parameters, in which case for [utimer] you need to use:

Code: Select all

utimer 25 [list no_answer $nick $uhost $handle $channel]

Ahhhhhhhhhhhhhhhhhhhhhhh, that could be exactly what I was looking for, I'd tried

Code: Select all

utimer 25 no_answer $nick $uhost $handle $channel
as a last ditch effort without the braces which quite rightly failed but if enclosing them in braces as a list works, that should hopefully solve my problem. I'll be back later :D
"Insanity Takes Its Toll, Please Have Exact Change"
User avatar
Sir_Fz
Revered One
Posts: 3793
Joined: Sun Apr 27, 2003 3:10 pm
Location: Lebanon
Contact:

Post by Sir_Fz »

Using braces instead of
  • will not return the values of the variables inside the braces, so use what demond suggested:

    Code: Select all

    utimer 25 [list no_answer $nick $uhost $handle $channel]
I
Ian-Highlander
Op
Posts: 165
Joined: Mon Sep 24, 2001 8:00 pm
Location: Ely, Cambridgeshire

Post by Ian-Highlander »

Ok, that's worked apart from one silly thing that for some reason I cant find. The kill_timers proc no longer works and as a result the game isnt being stopped correctly and causing all sorts of weird things to happen.

I've proved this after a lot of chasing my own tail round and round by a few additional debugs to list the timers that are running before and after and they're the same.

The code above solved my last problem but has caused this one an example of what the utimer is now listed as when the game is running is:

Code: Select all

12 {no_answer Ian-Highlander Highlander@highlander.HighlandFox.com Ian-H #Scotland} timer17
My normal code to kill "all" timers (there is only ever one) is:

Code: Select all

# Kill all  timers.
proc kill_timers {} {
   global chan
   foreach j [utimers] {
     if {[lindex $j 1] == "no_answer"} {
        killutimer [lindex $j 2]
     }
   }
   return 0
}
But because of the above, this no longer catches the timer. I've proved this by using:

Code: Select all

# Kill all  timers.
proc kill_timers {} {
   global chan
   foreach j [utimers] {
     if {[lindex $j 1] != ""} {
        killutimer [lindex $j 2]
     }
   }
   return 0
}
Which obviously catches every possible utimer and that works perfectly the script behaves exactly as it's supposed to, but of course I cant have my script killing every single utimer on someone's bot every time they run it, fun as that might be lol :roll:

I'm fairly sure it's back to my old favourites of splitting lists and indexes but I cant see where. God I'm rusty at this :oops:

Any help again? Sorry I hope this will be the last time (although not guaranteeing it), dunno where I'd be without this forum here :D
"Insanity Takes Its Toll, Please Have Exact Change"
User avatar
Sir_Fz
Revered One
Posts: 3793
Joined: Sun Apr 27, 2003 3:10 pm
Location: Lebanon
Contact:

Post by Sir_Fz »

I
Ian-Highlander
Op
Posts: 165
Joined: Mon Sep 24, 2001 8:00 pm
Location: Ely, Cambridgeshire

Post by Ian-Highlander »

Yup, already read through that many times and tried some of it to catch the timer but like I say, its silly things like this that I'm really really rusty on as evidenced by the silly requests I've made so far for help whilst being able to code some otherwise fairly complex stuff without issues.

I guess if thats your answer then once again I'll thankyou for your help it is appreciated (and I really really mean that) and continue to bang my head against my desk for a few more hours trying to work it the hell out :D (or you could be really really kind again and put me out of my misery :wink: )
"Insanity Takes Its Toll, Please Have Exact Change"
User avatar
Sir_Fz
Revered One
Posts: 3793
Joined: Sun Apr 27, 2003 3:10 pm
Location: Lebanon
Contact:

Post by Sir_Fz »

String match should do the job

Code: Select all

# Kill all  timers. 
proc kill_timers {} { 
 global chan 
 foreach j [utimers] { 
  if {[string match -nocase "no_answer *" [lindex $j 1]]} { 
   killutimer [lindex $j 2] 
  } 
 }  
}
I
Ian-Highlander
Op
Posts: 165
Joined: Mon Sep 24, 2001 8:00 pm
Location: Ely, Cambridgeshire

Post by Ian-Highlander »

See?? Thats exactly why I come here for help :D

You just fixed in two seconds flat what I've been working on for four hours trying to get working.

Thankyou once again, I definitely owe you a drink :D finally it all works as it should (so far).
"Insanity Takes Its Toll, Please Have Exact Change"
I
Ian-Highlander
Op
Posts: 165
Joined: Mon Sep 24, 2001 8:00 pm
Location: Ely, Cambridgeshire

Post by Ian-Highlander »

The old rust is cracking off slowly and various bits and bobs are coming back to me or I'm working them out the hard way. :D

BUT.... it's always the relatively simple things that keep foxing me and I need some help with one of the other small things on my current "bugfix" list for Trivia 2000.

I have Trivia 2000 (and a couple of my other scripts) running on some bots in a chat room where a lot of users use coloured text. The bots dont respond to the binds from users using colour, the second they switch to black text it works fine. I dont want to wildcard the binds, that could have other adverse effects.

How can I get the bot to strip off the colour codes from what is typed in and react to the correct commands or answers regardless of the colour they where typed in without wild carding the whole bind?

Can anyone help?
"Insanity Takes Its Toll, Please Have Exact Change"
User avatar
Sir_Fz
Revered One
Posts: 3793
Joined: Sun Apr 27, 2003 3:10 pm
Location: Lebanon
Contact:

Post by Sir_Fz »

You can't do that, you'll have to edit the eggdrop source in order to do that. What you can do is bind to * and call the other procs from there if the stripped-text matches. Example:

Code: Select all

bind pubm - * call:others

proc call:others {nick uhost hand chan arg} {
 set arg [stripcodes <switches> $arg]
 switch [string tolower [lindex [split $arg] 0]] {
  "!trivia" {
   trivia:proc $nick $uhost $hand $chan $arg
  }
  default {
   return 0
  }
 }
}
I
Ian-Highlander
Op
Posts: 165
Joined: Mon Sep 24, 2001 8:00 pm
Location: Ely, Cambridgeshire

Post by Ian-Highlander »

Thanks Sir_Fz, hopefully that will point me in the right direction.

:D
"Insanity Takes Its Toll, Please Have Exact Change"
I
Ian-Highlander
Op
Posts: 165
Joined: Mon Sep 24, 2001 8:00 pm
Location: Ely, Cambridgeshire

Post by Ian-Highlander »

Right, finally had enough time to do some work on this and with a great deal of swearing eventually got all the main commands to work using this code based on what Sir_Fz gave me above.

Code: Select all

bind pubm -|- * strip_colour_codes

proc strip_colour_codes {nick uhost handle channel args} {
     set args [string tolower [string trim [stripcodes c $args] "{}" ]]
        switch [string tolower [lindex [split $args] 0]] {
"!help" {give_help $nick $uhost $handle $channel $args}
"!trivia" {give_help $nick $uhost $handle $channel $args}
"!score" {give_score $nick $uhost $handle $channel $args}
"!choose" {give_choice $nick $uhost $handle $channel $args}
"!start" {start_game_check $nick $uhost $handle $channel $args}
"!hints" {hints_onoff $nick $uhost $handle $channel $args}
"!answers" {give_answers $nick $uhost $handle $channel $args}
"!announce" {quest_announce $nick $uhost $handle $channel $args}
"!game" {game_onoff $nick $uhost $handle $channel $args}
"!stop" {stop_game $nick $uhost $handle $channel $args}
   }
return 0
}
The stumbling block that took me a while to get working was the second part of some commands and passing that correctly to the relevant procs that needed it (i.e. the command "!game on") but resolved that using the code above and a few minor edits to the relevant procs and all appears to be working great.

However I now find myself stuck again with the same problem but for some of the other binds in the script. I'll try to explain and hopefully someone can help with this because I'm going round in circles here.

The above commands are the games main control commands but there are several other places in the script where the bot has to "listen" for specific words in almost all of these situations the bot has to stop listening for those words the second someone has said it. For example when offering a choice of category, it has six binds listening, one for each category. The moment someone enters one of these words, the category is set and all six words are then unbound immediately. The code below is a snippet of the proc that creates the binds.

Code: Select all

        putserv "PRIVMSG $chan :\002\003$copycol1\'Trivia 2000'\002 \003$copycol2\Version $triviaversion ©Ian-Highlander 2000-2006 started, please wait for a moment."
        putserv "PRIVMSG $chan :\002\003$copycol1\'Trivia 2000'\002 \003$copycol2\Inspired by ^norma ------------------- ('I can't play word games')"
        putserv "PRIVMSG $chan :\003$categcol1\Please select a category of questions to be answered"
        putserv "PRIVMSG $chan :Current categories available are: \003$categcol2\Geography, Entertainment, History, Art & Literature, Science & Nature, Sport & Leisure, Queen"
        putserv "PRIVMSG $chan :\003$choosecol\To choose a category simply type in the first word of that category."
        bind pub -|- geography set_geog
        bind pub -|- entertainment set_ent
        bind pub -|- history set_his
        bind pub -|- art set_art
        bind pub -|- science set_sci
        bind pub -|- sport set_sport
        bind pub -|- queen set_queen
}
There are then six seperate procs each of which are almost identical that look like this.

Code: Select all

#Geography's been set
proc set_geog {nick uhost handle channel args} {
   global questfile geography gamechan quessetcol1 quessetcol2 quessetcol3
        set chan $gamechan
        set questfile $geography
        putserv "PRIVMSG $chan :\003$quessetcol1\Questions set to \002\003$quessetcol2\ Geography\002 \003$quessetcol1\ by $nick enter\002\003$quessetcol3\ !start\002 \003$quessetcol1\ to play!"
        unbind pub -|- geography set_geog
        unbind pub -|- entertainment set_ent
        unbind pub -|- history set_his
        unbind pub -|- art set_art
        unbind pub -|- science set_sci
        unbind pub -|- sport set_sport
        unbind pub -|- queen set_queen
}
As you can see the minute the category is set, the bot sets the variable $questfile to $geography (specified in the user config at the top of the script) so that it knows which questions database to use, it then immediately unbinds all the words it was listening for to stop anyone else being able to choose too and stop any confusion.

My problem is this, if as Sir_Fz says, I cant strip the colour codes from the binds and the only way round it is to wildcard the binds then how can I achieve this? I tried re-writing the entire section with a wildcarded bind "switching" the correct trigger words to the right procs and I can get it working but as I did a wildcard bind, there is no way of unbinding the words. The same problem occurs when answers are given, as soon as a correct answer is given the bot reacts to it and unbinds it so that it wont react to anyone else giving that answer.

I'm tearing my hair out here guys, any help would be massively appreciated.

Ian
"Insanity Takes Its Toll, Please Have Exact Change"
User avatar
Sir_Fz
Revered One
Posts: 3793
Joined: Sun Apr 27, 2003 3:10 pm
Location: Lebanon
Contact:

Post by Sir_Fz »

I'm not sure if I understood you very well; but if you mean you don't want to unbind the '*' pubm bind since it will stop listening to any command, what you can do is create a variable which is set to 1 when the commands are bound and 0 when unbound (you figure the whole logic of this).
I
Ian-Highlander
Op
Posts: 165
Joined: Mon Sep 24, 2001 8:00 pm
Location: Ely, Cambridgeshire

Post by Ian-Highlander »

Yeah I cant unbind the pubm * because it would then stop every other command working. I just need to be able to unbind the category selections or answers after they have been given so that no repeats or user clashes happen.

I had an idea kind of on the lines of what you where suggesting so am hoping to get some time to work on that. If I get stuck I'll be back.

Thanks :D
"Insanity Takes Its Toll, Please Have Exact Change"
Post Reply