Help with chatbot buffing.

HasteBro

Member
I'm trying to make my Buffbot buff people when receiving a PM, like several buffbots out there do, using a chatbot script.

I'm was trying to use switch so that the script chooses the correct buff to use, but I simply couldn't figure out how to use it with strings. So I decided to go the messy way, by making loads of ifs and elses everywhere. It's working, but the code looks horrible. I know there's an easier way to do this, but I can't figure it out.

Basically, the way it's working now is by having a message look like this: "buff [buffname] [number of casts]". The word buff is needed since the script also handles dice rolls and a few other things my clan requested.


And while I'm on the subject, how would I go about making sure people can get only 1 buff per day? Adding sender to a map and calling it to check the names? I don't fully understand how maps work, even after reading veracity's tutorial, so I would be happy if someone explained how to use one in this particular case.

Here's the part of the code containing the buffing things:

Code:
void main(string sender, string message)
{
	if(contains_text(message, "buff"))
	{
		int numcasts = to_int(message);
		
		if(contains_text(message, "madrigal"))
		{
			if(have_skill($skill[The Moxious Madrigal]))
			{
				if(my_mp() >= mp_cost($skill[The Moxious Madrigal]))
				{
					chat_private(sender, "Casting The Moxious Madrigal"+ numcasts +" times.");
					use_skill(numcasts, $skill[The Moxious Madrigal], sender);
				}
				else
				{
					cli_execute("recover mp");
					chat_private(sender, "Casting The Moxious Madrigal"+ numcasts +" times.");
					use_skill(numcasts, $skill[The Moxious Madrigal], sender);
				}
			}
			
			else
			{
				chat_private(sender, "I don't have that buff available, human.");
			}
		}
		
		if(contains_text(message, "mojomuscular"))
		{
			if(have_skill($skill[The Magical Mojomuscular Melody]))
			{
				if(my_mp() >= mp_cost($skill[The Magical Mojomuscular Melody]))
				{
					chat_private(sender, "Casting The Moxious Madrigal"+ numcasts +" times.");
					use_skill(numcasts, $skill[The Magical Mojomuscular Melody], sender);
				}
				else
				{
					cli_execute("recover mp");
					chat_private(sender, "Casting The Magical Mojomuscular Melody"+ numcasts +" times.");
					use_skill(numcasts, $skill[The Magical Mojomuscular Melody], sender);
				}
			}
			
			else
			{
				chat_private(sender, "I don't have that buff available, human.");
			}
		}
		else
		{
			chat_private(sender, "Excuse me, human, but I was not able to understand your request: "+ message +" is not an available buff or you made a mistake.");
		}
		
	}
	
}
 

slyz

Developer
It looks like you need a casting function:
PHP:
boolean buff( skill buff, int numcasts, string player )
{
	if ( !buff.have_skill() )
	{
		chat_private( player, "I don't have that buff available, human." );
		return false;
	}

	if ( my_mp() < buff.mp_cost() ) cli_execute("recover mp");

	chat_private(sender, "Casting " + buff + " "+ numcasts +" times.");
	return use_skill( numcasts, skill, player);
}
 
Last edited:

Grotfang

Developer
And while I'm on the subject, how would I go about making sure people can get only 1 buff per day? Adding sender to a map and calling it to check the names? I don't fully understand how maps work, even after reading veracity's tutorial, so I would be happy if someone explained how to use one in this particular case.

If you've read Veracity's Data Structures page, it might be worth looking at the discussion page too. It explains in a LOT less detail the basics of map manipulation for those who are complete beginners. My advice when you are starting is to do lots of tests. Try out different ways of representing your data.

For example, for buffs, one way of storing a map would be to have two keys. The first is their name, the second the skill they requested with a value of the number of casts used (if applicable).

Code:
int [string,skill] buffRecord;

That way, if people's names appear in the map at all, you know that they have requested something, but it also allows you to send more out if you can afford it (maybe restricting total casts to 10). There are lots of different ways you could express the data. Records allow multiple values too, so that may be worth a look in.
 

HasteBro

Member
Slyz, thanks a lot for the function, it's working perfectly!

The code looks like this now, for anyone interested:

Code:
void main(string sender, string message)
{
	if(contains_text(message, "buff"))
	{
		int numcasts = to_int(message);
		
		boolean buff( skill buff, int numcasts, string sender )
		{
			if (!buff.have_skill())
			{
				chat_private(sender, "I don't have that buff available, human.");
				return false;
			}

			if (my_mp() < buff.mp_cost()) 
				cli_execute("recover mp");

			print(sender +" asked for "+ numcasts +" turns of "+ buff +".");
			chat_private(sender, "Casting " + buff + " "+ numcasts +" times.");
			return use_skill( numcasts, buff, sender);
		}  
		
		if(numcasts > 15)
		{
			chat_private(sender, "You ask too much of me, human.");
			abort();
		}
		
		switch
		{
			case(contains_text(message, "madrigal") == true):
				buff($skill[The Moxious Madrigal], numcasts, sender);
				break;

			default:
				print(sender +" asked for "+ message +", but I was not able to comply.");
				chat_private(sender, "Excuse me, human, but I was not able to understand your request: "+ message +" is not an available buff or you made a mistake.");
				break;
		}
	}
}

Now about the recording, from what I gathered in the discussion page, I'd have to use something like this:
Code:
record buffed
{
	string sender;
	skill buff;
	int numcasts;
};
buffed [string,skill, int] buffRecord;

Am I correct? If so, how can I confirm it works? I ran the script with that, it worked and I have no idea if the recording did too.

EDIT: Nevermind how to check, forgot about map_to_file(). It didn't record, the question is why? XP
 
Last edited:

Grotfang

Developer
Code:
record buffed
{
	string sender;
	skill buff;
	int numcasts;
};
buffed [string,skill, int] buffRecord;

EDIT: Nevermind how to check, forgot about map_to_file(). It didn't record, the question is why? XP

It looks as though you are using both multiple values and multiple keys. Make sure you are clear in your mind what the difference is between them.

Eg.

Code:
int [string,skill] buffRecord;

Value: int (could be the number of casts given for the entry).
Keys: string (could be the persons name), skill (the skill/buff requested). An entry might look like this:

Code:
void main( string sender , string message ) {
  int casts = to_int( message );
  skill buff = contains_text( message , "madrigal" ) ? $skill[The Moxious Madrigal] : $skill[none];
  int [string,skill] buffRecord;
  file_to_map( "buffs.txt" , buffRecord );
  if( !( buffRecord[sender] contains buff ) ) {
    buffRecord[sender,buff] = casts;
  }
  map_to_file( buffRecord , "buffs.txt" );
}

Safety note: this is entirely untested.
 

HasteBro

Member
Code:
void main( string sender , string message ) {
  int casts = to_int( message );
  skill buff = contains_text( message , "madrigal" ) ? $skill[The Moxious Madrigal] : $skill[none];
  int [string,skill] buffRecord;
  file_to_map( "buffs.txt" , buffRecord );
  if( !( buffRecord[sender] contains buff ) ) {
    buffRecord[sender,buff] = casts;
  }
  map_to_file( buffRecord , "buffs.txt" );
}

Safety note: this is entirely untested.

Ok, I hadn't paid attention to one of the lines of that code, that's why it was overwriting, it works perfectly now. Only thing is, the number of casts stays equal to that of the last message. I want to issue a limit of 15 daily casts per buff, which means I need the map to record the total number of casts, instead of the number in the last message and I can't figure that out...

My question is how do I make the map reset daily? Would using something like the sample in game_day_to_int() work?

Code is looking like this now:
Code:
void main (string sender, string message)
{
	int numcasts = to_int(message);
	
	boolean buff( skill buff, int numcasts, string sender )
	{
		if (!buff.have_skill())
		{
			chat_private(sender, "I don't have that buff available, human.");
			return false;
		}

		if (my_mp() < buff.mp_cost()) 
			cli_execute("recover mp");

		print(sender +" asked for "+ numcasts +" turns of "+ buff +".");
		
		int casts = to_int( message );
		int [string,skill] buffRecord;
		file_to_map( "buffRecord.txt" , buffRecord );
		if( !( buffRecord[sender] contains buff ) ) 
		{
			buffRecord[sender,buff] = casts;
		}
		map_to_file( buffRecord , "buffRecord.txt" );		
		
		if( casts < 15 )
		{
			chat_private(sender, "Casting " + buff + " "+ numcasts +" times. You have used "+ casts +" out of 15 free daily casts.");
			use_skill(numcasts, buff, sender);
		}
		
		else
		{
			print(sender +" already used up the free daily casts for "+ buff +".");
			chat_private(sender, "Excuse me, human, but it seems you already used all your free daily casts for "+ buff +".");
		}
	}  
	
	if(numcasts > 15)
	{
		chat_private(sender, "You ask too much of me, human. You can only have up to 15 casts of each buff per day.");
		abort();
	}
	
	if(contains_text(message, "buff"))
	{
		
		Switch
		{
			case (contains_text(message, "tarrypin") == true):
				buff($skill[Curiosity of Br'er Tarrypin], numcasts, sender);
				break;
			
			case (contains_text(message, "elemsauce") == true):
				buff($skill[Elemental Saucesphere], numcasts, sender);
				break;
			
			case (contains_text(message, "jalasauce") == true):
				buff($skill[Jalapeno Saucesphere], numcasts, sender);
				break;
			
			default:
				print(sender +" asked for "+ message +", but I was not able to comply.");
				chat_private(sender, "Excuse me, human, but I was not able to understand your request: "+ message +" is not an available buff or you made a mistake.");
				break;
		}
	}
}

The final version will have all buffs.
 

Theraze

Active member
You're doing file_to_map and map_to_file, but you only update the cast amount if it isn't listed yet. You want an else after the buffRecord check that does += casts if it does contain... like this (and skipping the exclamation mark, since we're checking both ways anyways).
Code:
		if( buffRecord[sender] contains buff ) 
		{
			buffRecord[sender,buff] += casts;
		}
		else
		{
			buffRecord[sender,buff] = casts;
		}
 

Grotfang

Developer
Only thing is, the number of casts stays equal to that of the last message. I want to issue a limit of 15 daily casts per buff, which means I need the map to record the total number of casts, instead of the number in the last message and I can't figure that out...

Theraze shows you one way of doing that, but in the future my advice would be to think about these sorts of problems before posting on here. Adding two integers together (whether in a map or not) is pretty simple ASH coding. I think the fact that the integers are in a map is making you scared. It'll take a while, but it really is best to try to work it out yourself! :)

My question is how do I make the map reset daily? Would using something like the sample in game_day_to_int() work?

That could do it, but the value will need to be stored somewhere. You could create a preference (eg. lastBuffReset), but if you are going to create a preference then you may as well just set a daily preference (eg. _lastBuffReset). Daily preferences are reset by mafia daily, so if it is set, it has been used. That would simplify your checking function.
 

HasteBro

Member
Yeah, I'm still new to the whole coding thing, I still can't get my brain to think logically on some stuff XD

Anyway, about the daily pref. Would I have to change the internal default.txt for every update I get? Or is there a way to set the default through coding?

The code I have based on that gameday_to_int() sample works just fine though, I'll use that while I haven't figured out the simpler way XP

PHP:
		int last = get_property("_lastBuffReset").to_int();
		if((last + 1) % 96 == gameday_to_int())
		{
			print("Reseting the buffRecord map", "green");
			int [string,skill] buffRecord;
			map_to_file( buffRecord , "buffRecord.txt" );
		}
		set_property("_lastBuffReset", gameday_to_int());
 

Grotfang

Developer
Anyway, about the daily pref. Would I have to change the internal default.txt for every update I get? Or is there a way to set the default through coding?

The code I have based on that gameday_to_int() sample works just fine though, I'll use that while I haven't figured out the simpler way XP

PHP:
		int last = get_property("_lastBuffReset").to_int();
		if((last + 1) % 96 == gameday_to_int())
		{
			print("Reseting the buffRecord map", "green");
			int [string,skill] buffRecord;
			map_to_file( buffRecord , "buffRecord.txt" );
		}
		set_property("_lastBuffReset", gameday_to_int());

Creating a preference that begins with an underscore means that it will be reset daily. So, _lastBuffReset (the one you use in your code) is added to your preference file and handled like every other daily preference. No need to fiddle with any internals. Now, you currently set the preference to gameday_to_int(), and that will mostly work fine. If you add some debug logging though, you will probably find that the first time in a day you run that code, the integer "last" is equal to 0. This is because the preference has been reset. Your check will still work (except once in every 96 days), but it is redundant. You really only need to check whether it has been set at all. If it has been set, that means it has been set that day.

So, what I would do is to run that "Reseting the buffRecord map" code in a breakfast script instead of every time you receive a command. That means it will run every time you log in. Combined with using a check to see if you have done it already today, that should keep you covered.
 

HasteBro

Member
Ah, I get it now, I checked the pref file today and it had no value to it. What I thought is that it would have whatever value that was set last for it.

PHP:
if(get_property("_lastBuffReset") != true)
{
	print("Reseting the buffRecord map", "green");
	int [string,skill] buffRecord;
	map_to_file( buffRecord , "buffRecord.txt" );
	set_property("_lastBuffReset", true);
}
So I can just put this code to my breakfast script and everything will work, right?
 

Grotfang

Developer
What I thought is that it would have whatever value that was set last for it.

The whole point of an underscore prefix is this functionality (daily reset). In this case, it being a daily preference is exactly what you want. In another situation, a preference that doesn't reset daily is one that does not have an underscore.

Your code looks fine. Happy buffing!
 
Top