GambleBot!

Ah, thanks Theraze.

So could I have something like this inside the main chatbotScript function?:

Code:
if (sender='jick')  {
 chat_private(sender , "How may I serve you, master?");
}

Would that work at all?
 
Should be roughly right. I'd probably use a match on sender instead... something more like sender.equals("Jick") instead.
 
Out of curiosity, what is the difference between
PHP:
if ( sender == "Jick" )
and
PHP:
if ( sender.equals("Jick") )
?
 
It would not work unless jick is in your clan.
Chat Private will only chat to clannies now.

I would recommend that you build your chat bot script to do very little, don't even hit the server.
Then you can use a clanbot script to parse in messages at a specified time interval.

This is my favorite chatbot script:
Code:
## Use this script by placing it in your scripts directory and typing "set chatbotScript=PMlogger.ash" into the gCLI.
void main( string sender , string message )
{
	print("Incoming message from " +sender+ " saying:  "+message,"olive");	
	record note
	{
		string sender;
		string message;
	}[int] PMlog;
	
	File_to_Map("PMlog.txt",PMlog);
	int newPM= count(PMlog);
	PMlog[newPM].sender= sender;
	PMlog[newPM].message= message;
	Map_to_File(PMlog,"PMlog.txt");	
}

It puts in all PM that are received into a map. My clan bot script will then execute them when it feels like it, not when they are immediately received.
This way you will prevent a crash due to two scripts running concurrently and hitting the server at the same time.
 
Last edited:
Out of curiosity, what is the difference between
PHP:
if ( sender == "Jick" )
and
PHP:
if ( sender.equals("Jick") )
?

But the first isn't what was given... we were given sender = 'Jick' not sender == 'Jick'. Explaining the difference and making sure that someone does it right in 300 lines of unindented code (if you're unlucky enough to be their validator when things go wrong on an overly complicated hodgepodge) generally isn't worth the effort of giving options. ;)
 
Ok, let me see if I can break this apart:

void main( string sender , string message ) #Main Function
{ #Start Main Function
print("Incoming message from " +sender+ " saying: "+message,"olive"); #Prints to the CLI "Incoming message from [sender's character name] saying [sender's message] olive". olive??? What's that for?
record note #Saves a copy of the information below (sender and their message)... where does it save it?
{
string sender;
string message;
}[int] PMlog; #Is this where it's saving that above info to?

File_to_Map("PMlog.txt",PMlog); #Selecting the file that you'll be changing?
int newPM= count(PMlog); #Creates an integer: newPM which is initialized to the lines in the PMlog
PMlog[newPM].sender= sender; #Adds the sender's name to sender part of the PMlog
PMlog[newPM].message= message; #Adds the message text to the message part of the PMlog
Map_to_File(PMlog,"PMlog.txt"); #Ending the changing of that file?
} #End main function

EDIT, EDIT: Oh, and I forgot, so I can put in something like this in the function then?:

Code:
if (sender.equals("Jick")  {
     chat_private(sender , "How may I serve you, master?");
}
if (sender.equals("Rick")  {
     chat_private(sender , "You may now serve me, your master?");
}
chat_private("rahmuss", +sender+, " sent your clan chatbot a message saying: ", +message);
 
Last edited:
Olive: The colour of the text that appears in the CLI-window
file_to_map takes a file in the /data folder and makes it into a ash-record/map.
map_to_file reverses the above to save the map to a file again, also in the /data folder

The record note{} part is actually defining how it is going to save the data and initiates the map structure.
 
Winterbay - Thanks. That makes sense. I'll have to check out the data folder after I try this then.

Theraze - Doh! You caught me. Actually I'm glad you caught that because I'll probably just cut / paste this into my script for testing purposes. :D

Thank you all for the great help. Now I just have to figure out how to randomize a comment back to whoever sends a message.
 
Well, the random(int) function will return a random number... could throw that into a switch...

Here's a little snippet that should send one of 3 random messages to the sender...
Code:
switch(random(3))
{
case 1: chat_private(sender , "You got message number one!"); break;
case 2: chat_private(sender , "You got the second message!"); break;
default: chat_private(sender , "You got the leftovers!"); break;
}
 
Theraze - Hey, that works for me. That's a great idea. I keep thinking of things to make this chatbot better. And that random function will help with my next project of making it so that he can roll dice. Then again, he can only send personal message right? Or, was it that the chatbot could also talk publicly in clan? Either way, this should be fun.
 
Hmm... well, since chat_clan works, I'm assuming it would work to send clan messages. And you could easily have it roll dice with just something like:
Code:
chat_clan(sender + " just rolled a " + random(6) + ". Is that a winner?!");

Gets more difficult if you care to have it keep/compare between people, but for just shooting back an immediate roll, should be easy. Note also that you could have that in a multiple bit if you have the matcher set to detect "roll dice <number>" or something like that... In that case, you'd want to do a string and append on dice rolls as you go through the for loop. Doing proper commas and that are fairly easily possible as well, if you care to do the work. :)
 
Theraze - Great! I thought I there was a way to chat to the clan chat; but I couldn't remember where I had seen that.

Not sure I understood that last part of your post though. The "matcher" you're talking about, I've seen it a few other times; but I don't really understand it. Sounds like it's trying to match a particular part of the message and that it requires regexes (regular expressions) to make it work. I saw a link earlier, I think from Alhifar, maybe I'll have to check that out.

EDIT: I guess I could also do a switch where it would find 1d2 or 1d3, or 1d4.... 1d20, something like that. Could I find that by having something like:

Code:
if (message.equals(*+"1d6"))  {
chat_clan(sender + " just rolled a " + (random(6)+1) + ".;
}

Or, if there isn't a way to use a wildcard, then I guess I could make people write it specifically as "roll 1d6" and then if it found that exact message then it could roll a 1d6.
 
Last edited:
Something sort of like:
Code:
int dice = 1; 
matcher m = create_matcher( "roll [URL="file://\\d"]\\d[/URL]+ di([c]?)e", message.to_lower_case());
if( m.find() ) dice = m.group( 1 ).to_int();
else
{
m = create_matcher( "roll di([c]?)e \\d+", message.to_lower_case());
if( m.find() ) dice = m.group( 2 ).to_int();
}

That will detect either "roll <number> dice" or "roll dice <number" in the message, pull the number of dice, and set it as the amount to display...

Generally, you wouldn't do it both ways... but you might want to do "dice" and "die" (the proper singular for one dice) depending on how likely you think your gamblers will be aware of proper grammar. ;)

Edit: Since it amuses me, here's a bit of the workings to generate the proper syntax for sending punctuated dice results:
Code:
int rolled = 0;
buffer sending.append(sender + " just rolled a ");
while (rolled < dice)
{
if (rolled == 1 && dice == 2)
sending.append(" and ");
else if (rolled > 0 && dice == rolled + 1)
sending.append(", and ");
else if (rolled > 0)
sending.append(", ");
sending.append((random(6) + 1);
rolled += 1;
}
sending.append(" on " + dice);
if (dice == 1) sending.append("die.");
else sending.append("dice.");

I also varied the matching code above... this should check for 0 or 1 'c' in the word dice/die. You'll notice that having added a new variable, it now matches on the second group on the lower item. If it's easier for you to read, instead doing "di([c]?)e" you should also be able to do "(dice|die)" to match either dice or die. I just prefer the first for some somewhat bizarre reason. :D

Edit2: In the case of complicated dice, you could do a matcher like:
Code:
int dice = 1; 
int sides = 6;
matcher m = create_matcher( "roll [URL="file://\\d+d\\d"]\\d+d\\d[/URL]+ di([c]?)e", message.to_lower_case());
if( m.find() ){
dice = m.group( 1 ).to_int();
sides = m.group( 2 ).to_int();
}
else
{
m = create_matcher( "roll di([c]?)e \\d+d\\d+", message.to_lower_case());
if( m.find() )
{
dice = m.group( 2 ).to_int();
sides = m.group( 3 ).to_int();
}
}

With that, you'd want to run random(sides) instead of random(6) when rolling your dice... And when giving the message about how many dice they rolled, I'd change this line:
sending.append(" on " + dice);
to this:
Code:
sending.append(" on " + dice + " " + sides + "-sided ");

If it works properly, it should return a clan chat of:
Theraze just rolled a 2, 5, and 1 on 3 6-sided dice.

Edit3: Fixed singular/pluralization. Don't grammar tired, it's bad. Also, I'd probably throw a check aborting the rolls if sides < 2 (possibly with a mocking comment on throwing balls, as that would be a 1 sided object)... and possibly calling 2 sided dice coins. If sides > 50 or something else rather large, because it ceases to be useful in dice calculations... though it may be useful for your own random number considerations. Just depends on how useful you want to keep it. Same on the number of dice thrown... if they aren't throwing at least 1 die, abort. If they're throwing over 20 or so, they can do it in multiple throws. Just don't want it to overwhelm the single message length capacity...
 
Last edited:
EDIT: I guess I could also do a switch where it would find 1d2 or 1d3, or 1d4.... 1d20, something like that. Could I find that by having something like:

Code:
if (message.equals(*+"1d6")) {
chat_clan(sender + " just rolled a " + (random(6)+1) + ".;
}

Or, if there isn't a way to use a wildcard, then I guess I could make people write it specifically as "roll 1d6" and then if it found that exact message then it could roll a 1d6.

Regarding doing something like that, if you changed it from message.equals(*+"1d6") to contains_text(message, "1d6"), that would actually let you do it that way... but you would have to do individual setups for each amount of dice and each side count. I'd suggest doing something with matchers, more like my post 34 instead.
 
Last edited:
Gah... sorry. Yeah, I've been staring at code too long. Yeah, it's not .contains("Something") for that then, it's contains_text(<text to check>, "Something"). Just make sure you have both equal signs in, not just the first... one equal sign means change the definition of something, two means you're checking. Updated post 35 to actually use contains_text instead of contains...
 
Well, I have my chatbot up and working just doing random comments back to people.
The regular expressions are really neat... however, they are also a bit complicated and I don't have many large blockss of time (10 or more minutes) to try and figure them out. But I'm working on it.

Next task will be to get my bot to roll dice of any number. I think I'll stick with chatbot's format. So it will be a message like:
/msg clanchatbot roll 1d__
(where the __ is obviously any number up to maybe 100)
And then the matcher will find what number is in there and roll it in clan chat... that's the goal at least.
 
Here is an example of a matcher that looks for something that looks like "XXdYY" or "XXDYY" where XX and YY are two numbers:
PHP:
string text = "roll 22d7";
matcher dice_matcher = create_matcher( "\\b(\\d+)[dD](\\d+)\\b", text);

if ( text.contains_text( "roll" ) && dice_matcher.find() )
{
	int num = dice_matcher.group( 1 ).to_int();
	int faces = dice_matcher.group( 2 ).to_int();
	int result = 0;
	
	if ( faces == 0 ) abort( "0-faced die do not exist in an Euclidian paradigm." );
	if ( num == 0 ) abort( "Not throwing any die will NOT give a random result, you know." );
	print( "Rolling " + num + " d" + faces + " ..." );
	for i from 1 to num result += random( faces ) + 1 ;
	print( "Result: "+ result );
}
else
{
	print( "Usage: 'roll <xxx>d<yyy>' where xxx is the number of yyy-faced die to roll." );
}

I can explain the RegEx in "\\b(\\d+)[dD](\\d+)\\b"
  • \\b matches a word boundary position such as whitespace or the beginning or end of the string (this means "a1d3test" won't match).
  • (\\d+) means one of more digits. Since it is enclosed in parenthesis, the number matched will be saved in a group.
  • [dD] simply meand "d" or "D" (so 2D56 and 2d56 will work).

EDIT: added checks to make sure faces and num are greater than 0.
 
Last edited:
I actually gave an example of how to do the whole thing, including the rolls of various sizes, above... though I didn't do the dD. Never seen someone do 2D10 instead of 2d10, but I suppose it may happen if someone gets all caps-happy.
 
Back
Top