PDA

View Full Version : Script for a Buff bot


Sylaei
08-31-2009, 12:13 AM
I copied the translocator script (http://www.eqemulator.net/forums/showpost.php?p=147203&postcount=1) from Trev and modified it to allow a player to request a buff, then pay/donate for the buff, then get the buff.

There are probably a lot of scripts in the forums that do this type of stuff, but I like this way, because you can change 3 lines and it will work for about any type of caster bot.

I use 3 arrays for the buffs, one is the name of the buff, one is the cost of the buff, and one is the spell id to cast. I also use a qglobal variable for the npc to remember the spell to cast.

The beauty of scripting like this is that once this is working for a few spells it will be easily modifiable for any other buff bot type npc.

My idea is to have an npc for each class that can provide buffs or ports. I then want them to randomly appear and after a while to leave. This is a step in the direction of imitating live with players that would buff for donations.

One final note: I am not really a perl programmer, like I said I just copied Trev's code and modified it some. If there is a way to make this better or a more proper way, please let me know.




#A buff bot script.
#Buffs a player for pp.

#SpellList is the array containing the names of the spells. SpellCost is the amount in pp for each spell. SpellID is the spell that is cast by the npc.
#Note these are 3 arrays. Each position in the array corosponds to the same position in the other arrays.
#So I have this set so that if you say 'Spirit of Wolf' and pay 2 pp, then the npc will cast spell 278 on you.
#I am setting the amounts to pp just because they can be any amount you wish, this requires changing the EVENT_ITEM function to handle the other money types.
@SpellList = ("Everlasting Breath", "Improved Superior Camouflage", "Levitation", "See Invisible", "Spirit of Wolf", "Storm Strength");
@SpellCost = ("2", "10", "2", "2", "2", "10");
@SpellID = ("2881", "1435", "2894", "80", "278", "430");

sub EVENT_SAY
{
my $all = quest::saylink("List", 1);
#Spacer between Text messages to make them easier to read
$client->Message(7, "-");
my $NPCName = $npc->GetCleanName();
if ($text =~/Hail/i)
{
$client->Message(315, "$NPCName whispers to you, 'If you need a buff or a Port just let me know, or I can [$all] them for you. You may also enter a partial name and I can find it.'");
}
#Counts each row for the While
my $count = 1;
#Counts each element in the Array for the While
my $n = 0;
if ($text !~ /Hail/i)
{
while ($SpellList[$n])
{
#This searches the list to find possible matches. The lc() command makes all text lowercase.
#It is easier to make all text lower case for comparison, if the user types uppercase it will still match.
if ((lc($SpellList[$n]) =~ lc($text) && lc($SpellList[$n]) ne lc($text)) || ($text =~ /^All$/i))
{
my $SpellList = quest::saylink($SpellList[$n]);
$client->Message(315, "$NPCName whispers to you, 'Possible match is: $SpellList");
}
#This is the command that is executed when a the user enters a spell.
if (lc($SpellList[$n]) eq lc($text) && $text !~ /^All$/i)
{
#Creates a global variable. You must set the qgolbal field in the npc_types table to 1 for each npc you wish to handle global variables.
#buff is the name, $text is what the varible should be eq too, 0 only this npc, char, and zone apply to the variable, M5 is 5 minutes.
quest::setglobal("buff", $text, 0, "M5");
#I'm not sure why I need the next line, the line above should set the $qglobals{buff}, but it wouldn't work for me.
$qglobals{buff} = $text;
$client->Message(315, "Please give me $SpellCost[$n]pp, and I'll cast $qglobals{buff} for you!");
}
$n++;
$count++;
}
}
}

sub EVENT_ITEM
{
my $correctmoney = 0;
#Counts each row for the While
my $count = 1;
#Counts each element in the Array for the While
my $n = 0;
#Cycles through each spell in the array until it matches the requested spell, and the amount pp required.
while ($SpellList[$n])
{
if(($SpellList[$n] eq $qglobals{buff}) && ($platinum == $SpellCost[$n]))
{
$client->Message(315, "Thank you for the $SpellCost[$n]pp, prepare for $qglobals{buff}!");
$npc->CastSpell($SpellID[$n], $userid);
#set this to 1 so that we don't return money we shouldn't.
$correctmoney = 1;
}
$n++;
$count++;
}
#Returns the money if it is not the correct amount.
if ($correctmoney == 0 )
{
if(($copper > 0) || ($silver > 0) || ($gold > 0) || ($platinum > 0))
{
$client->Message(315, "I don't need these coins, you may have them back.");
quest::givecash($copper,$silver,$gold,$platinum);
}
}
#deletes the $qglobals{buff} variable.
quest::delglobal("buff");
}

Sylaei
08-31-2009, 02:16 AM
I just realized there was an error, I changed the word All to List but I didn't change it everywhere. Danged ole bugs.



#A buff bot script.
#Buffs a player for pp.

#SpellList is the array containing the names of the spells. SpellCost is the amount in pp for each spell. SpellID is the spell that is cast by the npc.
#Note these are 3 arrays. Each position in the array corosponds to the same position in the other arrays.
#So I have this set so that if you say 'Spirit of Wolf' and pay 2 pp, then the npc will cast spell 278 on you.
#I am setting the amounts to pp just because they can be any amount you wish, this requires changing the EVENT_ITEM function to handle the other money types.
@SpellList = ("Everlasting Breath", "Improved Superior Camouflage", "Levitation", "See Invisible", "Spirit of Wolf", "Storm Strength");
@SpellCost = ("2", "10", "2", "2", "2", "10");
@SpellID = ("2881", "1435", "2894", "80", "278", "430");

sub EVENT_SAY
{
my $all = quest::saylink("List", 1);
#Spacer between Text messages to make them easier to read
$client->Message(7, "-");
my $NPCName = $npc->GetCleanName();
if ($text =~/Hail/i)
{
$client->Message(315, "$NPCName whispers to you, 'If you need a buff or a Port just let me know, or I can [$all] them for you. You may also enter a partial name and I can find it.'");
}
#Counts each row for the While
my $count = 1;
#Counts each element in the Array for the While
my $n = 0;
if ($text !~ /Hail/i)
{
while ($SpellList[$n])
{
#This searches the list to find possible matches. The lc() command makes all text lowercase.
#It is easier to make all text lower case for comparison, if the user types uppercase it will still match.
if ((lc($SpellList[$n]) =~ lc($text) && lc($SpellList[$n]) ne lc($text)) || ($text =~ /^List$/i))
{
my $SpellList = quest::saylink($SpellList[$n]);
$client->Message(315, "$NPCName whispers to you, 'Possible match is: $SpellList");
}
#This is the command that is executed when a the user enters a spell.
if (lc($SpellList[$n]) eq lc($text) && $text !~ /^List$/i)
{
#Creates a global variable. You must set the qgolbal field in the npc_types table to 1 for each npc you wish to handle global variables.
#buff is the name, $text is what the varible should be eq too, 0 only this npc, char, and zone apply to the variable, M5 is 5 minutes.
quest::setglobal("buff", $text, 0, "M5");
#I'm not sure why I need the next line, the line above should set the $qglobals{buff}, but it wouldn't work for me.
$qglobals{buff} = $text;
$client->Message(315, "Please give me $SpellCost[$n]pp, and I'll cast $qglobals{buff} for you!");
}
$n++;
$count++;
}
}
}

sub EVENT_ITEM
{
my $correctmoney = 0;
#Counts each row for the While
my $count = 1;
#Counts each element in the Array for the While
my $n = 0;
#Cycles through each spell in the array until it matches the requested spell, and the amount pp required.
while ($SpellList[$n])
{
if(($SpellList[$n] eq $qglobals{buff}) && ($platinum == $SpellCost[$n]))
{
$client->Message(315, "Thank you for the $SpellCost[$n]pp, prepare for $qglobals{buff}!");
$npc->CastSpell($SpellID[$n], $userid);
#set this to 1 so that we don't return money we shouldn't.
$correctmoney = 1;
}
$n++;
$count++;
}
#Returns the money if it is not the correct amount.
if ($correctmoney == 0 )
{
if(($copper > 0) || ($silver > 0) || ($gold > 0) || ($platinum > 0))
{
$client->Message(315, "I don't need these coins, you may have them back.");
quest::givecash($copper,$silver,$gold,$platinum);
}
}
#deletes the $qglobals{buff} variable.
quest::delglobal("buff");
}

Sylaei
09-05-2009, 01:58 AM
I thought I'd post the 'final' version. With this version all I have to do is change the SpellList, SpellCost, and SpellId Arrays and I'll have a seperate npc for casting buffs or ports. In this script they are up for 20 minutes then down for 20 minutes. The respawn time in the database is responsible for respawning after 20 minutes.

This will simulate the players in pok that would buff for donations.

One other change is that you can list all the spells, buffs only, or the ports only.


#A buff bot script.
#Buffs a player for pp.

#SpellList is the array containing the names of the spells. SpellCost is the amount in pp for each spell. SpellID is the spell that is cast by the npc.
#Note these are 3 arrays. Each position in the array corosponds to the same position in the other arrays.
#So I have this set so that if you say 'Spirit of Wolf' and pay 2 pp, then the npc will cast spell 278 on you.
#I am setting the amounts to pp just because they can be any amount you wish, this requires changing the EVENT_ITEM function to handle the other money types.
@SpellList = ("Bind Affinity","Chloroplast","Port to Arcstone","Port to Barindu","Port to Blightfire Moors","Port to Bloodfields","Port to Buried Sea","Port to Butcher","Port to Cobalt Scar","Port to Commons","Port to Dawnshroud","Port to Feerrott","Port to Great Divide","Port to Grimling","Port to Iceclad","Port to Karana","Port to Knowledge","Port to Lavastorm","Port to Misty","Port to Natimbi","Port to Ro","Port to Steamfont","Port to Stonebrunt","Port to Surefall Glade","Port to the Combines","Port to the Nexus","Port to The Steppes","Port to Toxxulia","Port to Twilight","Port to Undershore","Port to Wakening Lands","Port to Emerald Jungle","Everlasting Breath","Levitation","Natureskin","Protection of the Cabbage","Regrowth","Resist Cold","Resist Disease","Resist Fire","Resist Magic","Resist Poison","See Invisible","Shield of Blades","Shield of Thorns","Skin like Diamond","Skin like Nature","Port to Sky Fire Mountains","Spirit of Eagle","Spirit of the Shrew","Spirit of Wolf","Storm Strength");
@SpellCost = ("2", "10", "15", "15", "2", "15", "15", "5", "10", "5", "8", "8", "8", "5", "8", "5", "8", "8", "8", "15", "8", "8", "5", "5", "8", "5", "20", "5", "8", "15", "10", "8", "2", "2", "15", "15", "15", "8", "10", "5", "10", "10", "2", "15", "10", "8", "10", "8", "15", "8", "2", "10");
@SpellID = ("35", "145", "8965", "5731", "9957", "6184", "11981", "553", "1440", "551", "2429", "556", "1438", "2419", "1434", "550", "3184", "554", "558", "4966", "555", "557", "3792", "2020", "1517", "2432", "9954", "552", "2424", "8235", "1398", "1737", "2881", "2894", "1559", "2188", "1568", "61", "63", "60", "64", "62", "80", "1560", "356", "422", "423", "1736", "2517", "4054", "278", "430");

sub EVENT_SPAWN
{
quest::settimer("buffy", 96);
quest::shout("Get your buffs here! Come see Buffy by the tree by the big bank");
quest::settimer("despawnbuffy", 1200)
}

sub EVENT_TIMER
{
#$npc->SetAppearance(1);
if($timer eq "buffy")
{
my $random_number = int(rand(4));
if ($random_number == 0)
{
quest::shout("Get your buffs here! Come see Buffy by the tree by the big bank");
}
elsif ($random_number == 1)
{
quest::shout("Need a port? Come see Buffy by the tree by the big bank");
}
elsif ($random_number == 2)
{
quest::shout("Giving buffs for pp I'm by the tree by the big bank");
}
elsif ($random_number == 3)
{
quest::shout("Buffin and Portin by the tree by the big bank");
}
$npc->SetAppearance(int(rand(2)));
}
if($timer eq "despawnbuffy")
{
quest::say ("I am off to gather more experience. See you all soon!");
quest::depop();
}
}

sub EVENT_SAY
{
my $all = quest::saylink("List", 1);
my $ports = quest::saylink("Ports",1);
my $buffs = quest::saylink("Buffs",1);
#Spacer between Text messages to make them easier to read
$client->Message(7, "-");
my $NPCName = $npc->GetCleanName();
if ($text =~/Hail/i)
{
$npc->SetAppearance(0);
$client->Message(315, "$NPCName whispers to you, 'If you need a buff or a Port just let me know, or I can [$all] them for you. If you prefer to just see the [$buffs] or [$ports] I can do that too. You may also enter a partial name and I can find it.'");
}
#Counts each row for the While
my $count = 1;
#Counts each element in the Array for the While
my $n = 0;
if ($text !~ /Hail/i)
{
while ($SpellList[$n])
{
#This searches the list to find possible matches. The lc() command makes all text lowercase.
#It is easier to make all text lower case for comparison, if the user types uppercase it will still match.
if ((lc($SpellList[$n]) =~ lc($text) && lc($SpellList[$n]) ne lc($text)) || ($text =~ /^List$/i))
{
my $SpellList = quest::saylink($SpellList[$n]);
my $SpellCost = $SpellCost[$n];
$client->Message(315, "$NPCName whispers to you, 'Possible match is: $SpellList and it costs $SpellCost pp");
}
if ((lc($SpellList[$n]) =~ lc($text) && lc($SpellList[$n]) ne lc($text)) || (($text =~ /Buffs/i) && ($SpellList[$n] !~ /Port to/i)))
{
my $SpellList = quest::saylink($SpellList[$n]);
my $SpellCost = $SpellCost[$n];
$client->Message(315, "$NPCName whispers to you, 'Possible match is: $SpellList and it costs $SpellCost pp");
}
if ((lc($SpellList[$n]) =~ lc($text) && lc($SpellList[$n]) ne lc($text)) || (($text =~ /Ports/i) && ($SpellList[$n] =~ /Port to/i)) )
{
my $SpellList = quest::saylink($SpellList[$n]);
my $SpellCost = $SpellCost[$n];
$client->Message(315, "$NPCName whispers to you, 'Possible match is: $SpellList and it costs $SpellCost pp");
}

#This is the command that is executed when a the user enters a spell.
if (lc($SpellList[$n]) eq lc($text) && $text !~ /^List$/i)
{
#Creates a global variable. You must set the qgolbal field in the npc_types table to 1 for each npc you wish to handle global variables.
#buff is the name, $text is what the varible should be eq too, 0 only this npc, char, and zone apply to the variable, M5 is 5 minutes.
quest::setglobal("buff", $text, 0, "M5");
#I'm not sure why I need the next line, the line above should set the $qglobals{buff}, but it wouldn't work for me.
$qglobals{buff} = $text;
$client->Message(315, "Please give me $SpellCost[$n]pp, and I'll cast $qglobals{buff} for you!");
}
$n++;
$count++;
}
}
}

sub EVENT_ITEM
{
my $correctmoney = 0;
#Counts each row for the While
my $count = 1;
#Counts each element in the Array for the While
my $n = 0;
#Cycles through each spell in the array until it matches the requested spell, and the amount pp required.
while ($SpellList[$n])
{
if(($SpellList[$n] eq $qglobals{buff}) && ($platinum == $SpellCost[$n]))
{
$client->Message(315, "Thank you for the $SpellCost[$n]pp, prepare for $qglobals{buff}!");
if ($SpellList[$n] =~ /Port to/i)
{
quest::selfcast($SpellID[$n])
}
else
{
$npc->CastSpell($SpellID[$n], $userid);
}
#set this to 1 so that we don't return money we shouldn't.
$correctmoney = 1;
}
$n++;
$count++;
}
#Returns the money if it is not the correct amount.
if ($correctmoney == 0 )
{
if(($copper > 0) || ($silver > 0) || ($gold > 0) || ($platinum > 0))
{
$client->Message(315, "I don't need these coins, you may have them back.");
quest::givecash($copper,$silver,$gold,$platinum);
}
}
#deletes the $qglobals{buff} variable.
quest::delglobal("buff");
}

Gregk
10-27-2010, 12:41 PM
I copied the bot script and made some changes for other classes. The issue I'm having with the Enchanter bot is the KEI group buff. I know for the druid bot, the port spells are set to selfcast. If someone with coding skills could help me out, I'm hoping its possible to add a line that if spellid=2570 then selfcast 2570. Otherwise the npc just casts the group buff on itself. Once I see the added code, I can adjust the cleric bot too. Thank you much. And thanks for writing the quest in the first place. fits in my world perfectly.


Code:
#A buff bot script.
#Buffs a player for pp.

#SpellList Is the array containing the names of the spells. SpellCost Is the amount in pp for each spell. SpellID Is the spell that Is cast by the npc.
#Note these are 3 arrays. each position in the array corosponds to the same position in the other arrays.
#So I have this set so that if you say 'Spirit of Wolf' and pay 2 pp, then the npc will cast spell 278 on you.
#I am setting the amounts to pp just because they can be any amount you wish, this requires changing the EVENT_ITEM Function to handle the other money types.
@SpellList = ("Bind Affinity","”See Invisible","Serpent Sight","Intellectual Advancement","Rune I","Breeze","Quickness","Intellectual Superiority","Alacrity","Rune II","Clarity","Augmentation","Ward of Alendar","Radiant Visage","Clarity II","Rune III","Gift of Magic","Insight","Celerity","Rune IV","Brilliance","Guard of Alendar","Adorning Grace","Swift Like the wind","Improved Invisibility","Rune V","Aanya's Quickening","Gift of Insight","Protection of Alendar","Overwhelming Splendor","Augment","Wonderous Rapidity","Gift of Brilliance","KEI");
@SpellCost = ("2","2","1","2","3","3","2","3","5","6","5","7","4","5","7","9","5","5","5","12","7","6","8","8","10","15","10","8","10","10","10","12","12","25");
@SpellID = ("35","80","276","2561","481","697","39","2562","170","482","174","10","4073","646","1693","483","1408","175","171","184","33","4074","647","172","1406","1689","1708","1403","4075","1701","1729","1709","1410","2570");

sub EVENT_SPAWN
{
quest::settimer("buffy", 90);
quest::ooc("Mind buffs behind Main bank");
quest::settimer("despawnbuffy", 1300)
}

sub EVENT_TIMER
{
#$npc->SetAppearance(1);
if($timer eq "buffy")
{
my $random_number = int(rand(4));
if ($random_number == 0)
{
quest::shout("I have the buffs you're looking for...");
}
elsif ($random_number == 1)
{
quest::shout("Clarity, Clarity II, KEI, and Haste behind Main Bank");
}
elsif ($random_number == 2)
{
quest::shout("Buffing for Platinum! Proceedes go to Arcane Scholarship funds");
}
elsif ($random_number == 3)
{
quest::say("Terran, Please stop touching me.");
}
$npc->SetAppearance(int(rand(2)));
}
if($timer eq "despawnbuffy")
{
quest::say ("I'm off to shower. This place makes my skin crawl");
quest::depop();
}
}

sub EVENT_SAY
{
my $all = quest::saylink("List", 1);
my $buffs = quest::saylink("Buffs",1);
#Spacer between Text messages to make them easier to read
$client->Message(7, "-");
my $NPCName = $npc->GetCleanName();
if ($text =~/Hail/i)
{
$npc->SetAppearance(0);
$client->Message(315, "$NPCName whispers to you, 'Please let me know what [$buffs] you'd like, or I can list them [$all] for you. '");
}
#Counts each row for the while
my $count = 1;
#Counts each element in the Array for the while
my $n = 0;
if ($text !~ /Hail/i)
{
while ($SpellList[$n])
{
#This searches the list to find possible matches. The lc() command makes all text lowercase.
#It Is easier to make all text lower case for comparison, if the user types uppercase it will still match.
if ((lc($SpellList[$n]) =~ lc($text) && lc($SpellList[$n]) ne lc($text)) || ($text =~ /^List$/i))
{
my $SpellList = quest::saylink($SpellList[$n]);
my $SpellCost = $SpellCost[$n];
$client->Message(315, "$NPCName whispers to you, 'Possible match is: $SpellList and it costs $SpellCost pp");
}
if ((lc($SpellList[$n]) =~ lc($text) && lc($SpellList[$n]) ne lc($text)) || (($text =~ /Buffs/i) && ($SpellList[$n] !~ /Port to/i)))
{
my $SpellList = quest::saylink($SpellList[$n]);
my $SpellCost = $SpellCost[$n];
$client->Message(315, "$NPCName whispers to you, 'Possible match is: $SpellList and it costs $SpellCost pp");
}
if ((lc($SpellList[$n]) =~ lc($text) && lc($SpellList[$n]) ne lc($text)) || (($text =~ /Ports/i) && ($SpellList[$n] =~ /Port to/i)) )
{
my $SpellList = quest::saylink($SpellList[$n]);
my $SpellCost = $SpellCost[$n];
$client->Message(315, "$NPCName whispers to you, 'Possible match is: $SpellList and it costs $SpellCost pp");
}

#This Is the command that Is executed when a the user enters a spell.
if (lc($SpellList[$n]) eq lc($text) && $text !~ /^List$/i)
{
#Creates a global variable. You must set the qgolbal field in the npc_types table to 1 for each npc you wish to handle global variables.
#buff Is the name, $text Is what the varible should be eq too, 0 only this npc, char, And zone apply to the variable, M5 Is 5 minutes.
quest::setglobal("buff", $text, 0, "M5");
#I'm not sure why I need the next line, the line above should set the $qglobals{buff}, but it wouldn't work for me.
$qglobals{buff} = $text;
$client->Message(315, "Please give me $SpellCost[$n]pp, and I'll cast $qglobals{buff} for you!");
}
$n++;
$count++;
}
}
}

sub EVENT_ITEM
{
my $correctmoney = 0;
#Counts each row for the while
my $count = 1;
#Counts each element in the Array for the while
my $n = 0;
#Cycles through each spell in the array until it matches the requested spell, And the amount pp required.
while ($SpellList[$n])
{
if(($SpellList[$n] eq $qglobals{buff}) && ($platinum == $SpellCost[$n]))
{
$client->Message(315, "Thank you for the $SpellCost[$n]pp, prepare for $qglobals{buff}!");
if ($SpellList[$n] =~ /Port to/i)
{
quest::selfcast($SpellID[$n])
}
else
{
$npc->CastSpell($SpellID[$n], $userid);
}
#set this to 1 so that we don't return money we shouldn't.
$correctmoney = 1;
}
$n++;
$count++;
}
#Returns the money if it Is Not the correct amount.
if ($correctmoney == 0 )
{
if(($copper > 0) || ($silver > 0) || ($gold > 0) || ($platinum > 0))
{
$client->Message(315, "I don't need these coins, you may have them back.");
quest::givecash($copper,$silver,$gold,$platinum);
}
}
#deletes the $qglobals{buff} variable.
quest::delglobal("buff");
}

Gregk
10-27-2010, 03:27 PM
Nevermind. I changed the "/Port to/ part to KEI. Worked like a charm. Thanks again. Now I just need to slow down the shout spam. Wouldn't be so bad if the zone were populated... Awesome script!

lich2594
10-28-2010, 06:29 PM
Nevermind. I changed the "/Port to/ part to KEI. Worked like a charm. Thanks again. Now I just need to slow down the shout spam. Wouldn't be so bad if the zone were populated... Awesome script!

If you want to prevent a lot of spam, I would suggest using direct messages to the client, instead of chat spam, just like there is in parts of the script (but not all?). It is much more clean for everyone around.

IE:

sub EVENT_SAY {

$client->Message(7, " ");
my $NPCName = $npc->GetCleanName();

if ($text=~/hail/i) {
$client->Message(315, "$NPCName whispers to you '...nice and quite, $name.'");
}

}

Also, instead of shouting on a timer... why not put it on a proximity trigger when the player gets within X distance of the NPC?

Gregk
10-28-2010, 07:47 PM
I Like the suggestions. Maybe have one shout, which would be every 40 mins. That way new people to my PoK would find out they're there, do the rest with whispers and proximity. Nice....

Gregk
10-29-2010, 05:44 AM
Would it also be possible to Tweak the range the npc would have for casting? As it is now, you need to stand very close to the npc for the quest/spell to work. Doubling the range would make it Ideal...

Thank you.

lich2594
10-29-2010, 09:16 AM
Would it also be possible to Tweak the range the npc would have for casting? As it is now, you need to stand very close to the npc for the quest/spell to work. Doubling the range would make it Ideal...

Thank you.

The quest::cast uses a self-cast type script that triggers if you are within speaking range to the NPC. So you have to be within a certain distance to trigger the event. Just like if you are too far away, you can't speak to NPC's. I am sure it can be changed, if you wanted to modify the source code. ;)

Almost anything can be changed, if you had the knowledge to do so. (Except client side, of course.)

lich2594
10-29-2010, 09:20 AM
By the way, I wanted to point out that this script for the paid buff feature looks like it has the potential to be exploited. For example, it is storing data in memory that someone paid, but it does not store who. A simple fix for this would be to use quest globals, instead of storing it in a var. After they receive the buff, delete the quest global.

Right now, it seems to me that someone can pay - then someone else could steal the buffs that the other player paid for.

I guess it wouldn't matter if this was a private server, but it could cause issues on a public server. Just heads up!

(Also, I may have read it wrong since I haven't tested this exact script myself - it is just what it appeared to me.)

lich2594
10-29-2010, 09:26 AM
Actually, here is my exact script to charge money on the user level for buffs. I don't have a feature to automatically shout or anything (as I have the tag "buffs" under it's name). But this is how my script works:

sub EVENT_SAY{

$client->Message(7, " ");
my $NPCName = $npc->GetCleanName();

if($text=~/Hail/i) {
if ($ulevel <= 10) {
quest::selfcast(5415);
quest::selfcast(5312);
quest::selfcast(5405);
quest::selfcast(5409);
quest::selfcast(5521);
quest::selfcast(5365);
quest::selfcast(278);
quest::selfcast(939);
quest::selfcast(3391);
quest::selfcast(5390);
$client->Message(315, "$NPCName whispers to you, 'Since you are level 10 or lower you get free buffs, $name! Good luck to you.'");
}
if (($ulevel > 10) && ($ulevel < 25)) {
$client->Message(315, "$NPCName whispers to you, 'Hello $name, I will give you buffs for 100 platinum.'");
}
if (($ulevel >= 25) && ($ulevel < 80)) {
$client->Message(315, "$NPCName whispers to you, 'Hello $name, I will give you buffs for 500 platinum.'");
}
if ($ulevel >= 80) {
$client->Message(315, "$NPCName whispers to you, 'Hello $name, I will give you buffs for 1,000 platinum.'");
}
}
}


sub EVENT_ITEM {

$client->Message(7, " ");
my $NPCName = $npc->GetCleanName();

if ($platinum == 1000) {
if ($ulevel >= 80) {
quest::selfcast(5278);
quest::selfcast(5415);
quest::selfcast(5312);
quest::selfcast(5405);
quest::selfcast(5409);
quest::selfcast(5521);
quest::selfcast(5365);
quest::selfcast(278);
quest::selfcast(939);
quest::selfcast(3391);
quest::selfcast(5390);
$client->Message(315, "$NPCName whispers to you, 'Thank you $name!'");
} else {
$client->Message(315, "$NPCName whispers to you, 'Use the correct amount, $name!'");
quest::givecash($copper,$silver,$gold,$platinum);
}
}
if ($platinum == 500) {
if (($ulevel < 80)&&($ulevel >= 25)) {
quest::selfcast(5278);
quest::selfcast(5415);
quest::selfcast(5312);
quest::selfcast(5405);
quest::selfcast(5409);
quest::selfcast(5521);
quest::selfcast(5365);
quest::selfcast(278);
quest::selfcast(939);
quest::selfcast(3391);
quest::selfcast(5390);
$client->Message(315, "$NPCName whispers to you, 'Thank you $name!'");
} else {
$client->Message(315, "$NPCName whispers to you, 'Use the correct amount, $name!'");
quest::givecash($copper,$silver,$gold,$platinum);
}
}
if ($platinum == 100) {
if (($ulevel > 10) && ($ulevel < 25)) {
quest::selfcast(5415);
quest::selfcast(5312);
quest::selfcast(5405);
quest::selfcast(5409);
quest::selfcast(5521);
quest::selfcast(5365);
quest::selfcast(278);
quest::selfcast(939);
quest::selfcast(3391);
quest::selfcast(5390);
$client->Message(315, "$NPCName whispers to you, 'Thank you $name!'");
} else {
$client->Message(315, "$NPCName whispers to you, 'Use the correct amount, $name!'");
quest::givecash($copper,$silver,$gold,$platinum);
}
}
if (($platinum < 100) || ($platinum < 500) && ($platinum > 100) || ($platinum < 1000) && ($platinum > 100) && ($platinum > 500) || ($platinum > 1000)) {
$client->Message(315, "$NPCName whispers to you, 'Use the correct amount, $name!'");
quest::givecash($copper,$silver,$gold,$platinum);
}
}

It simply charges a fee based on the user level. It also buffs them upon correct payment.

Enjoy!

Gregk
10-29-2010, 07:24 PM
Very Nice! I do like some minimal Chatter in PoK, feels a bit more home like, but I might change some of the shouts to whispers and says. I like your buff script for npc buff bots I plan to add to zones with some of the more difficult mobs. I don't want to nerf any mobs or add crazy weapon damage, but I do want it so a single group can take on a solid mob if they have the strategy and tactics. This will do that I believe. Give an edge, but not tip the scale. Thank you!

provocating
01-12-2011, 03:44 PM
I would like to add the ability for the buff bot to do a random MGB and have it call out with minute warnings, like 5 minutes, 4, 3, 2, 1 just like a player would do. Players could still pay immediately and get what they want but they would occasionally zone in and be able to get a free MGB.

I am getting stuck on the 5 minute warning. There seems to be no way to pause for 60 seconds or is there ?

provocating
01-12-2011, 04:21 PM
Persistence is the key. I think I have it now.

Huppy
02-09-2011, 03:34 AM
I would like to add the ability for the buff bot to do a random MGB and have it call out with minute warnings, like 5 minutes, 4, 3, 2, 1 just like a player would do. Players could still pay immediately and get what they want but they would occasionally zone in and be able to get a free MGB.

I am getting stuck on the 5 minute warning. There seems to be no way to pause for 60 seconds or is there ?

THIS would be great !!! :)

Durge
05-10-2011, 10:55 PM
I used the same set up, but I can't figure out what is wrong here, can anyone help?


sub EVENT_SAY{

$client->Message(7, " ");
my $NPCName = $npc->Ram();

if($text=~/Hail/i) {
if ($ulevel <= 10) {
quest::selfcast(5415);
quest::selfcast(5312);
quest::selfcast(5405);
quest::selfcast(5409);
quest::selfcast(5521);
quest::selfcast(5365);
quest::selfcast(278);
quest::selfcast(939);
quest::selfcast(3391);
quest::selfcast(5390);
$client->Message(315, "$NPCName whispers to you, 'Since you are level 10 or lower you get free buffs, $name! Good luck to you.'");
}
if (($ulevel > 10) && ($ulevel < 25)) {
$client->Message(315, "$NPCName whispers to you, 'Hello $name, I will give you buffs in exchange for 100 platinum.'");
}
if (($ulevel >= 25) && ($ulevel < 70)) {
$client->Message(315, "$NPCName whispers to you, 'Hello $name, I will give you buffs in exchange for 500 platinum.'");
}
if ($ulevel >= 70) {
$client->Message(315, "$NPCName whispers to you, 'Hello $name, I will give you buffs in exchange for 1,000 platinum.'");
}
}
}


sub EVENT_ITEM {

$client->Message(7, " ");
my $NPCName = $npc->Ram();

if ($platinum == 1000) {
if ($ulevel >= 70) {
quest::selfcast(5278);
quest::selfcast(5415);
quest::selfcast(5312);
quest::selfcast(5405);
quest::selfcast(5409);
quest::selfcast(5521);
quest::selfcast(5365);
quest::selfcast(278);
quest::selfcast(939);
quest::selfcast(3391);
quest::selfcast(5390);
$client->Message(315, "$NPCName whispers to you, 'Thank you $name!'");
} else {
$client->Message(315, "$NPCName whispers to you, 'Use the correct amount of platinum, $name!'");
quest::givecash($copper,$silver,$gold,$platinum);
}
}
if ($platinum == 500) {
if (($ulevel < 75)&&($ulevel >= 25)) {
quest::selfcast(5278);
quest::selfcast(5415);
quest::selfcast(5312);
quest::selfcast(5405);
quest::selfcast(5409);
quest::selfcast(5521);
quest::selfcast(5365);
quest::selfcast(278);
quest::selfcast(939);
quest::selfcast(3391);
quest::selfcast(5390);
$client->Message(315, "$NPCName whispers to you, 'Thank you $name!'");
} else {
$client->Message(315, "$NPCName whispers to you, 'Use the correct amount of platinum, $name!'");
quest::givecash($copper,$silver,$gold,$platinum);
}
}
if ($platinum == 100) {
if (($ulevel > 10) && ($ulevel < 25)) {
quest::selfcast(5415);
quest::selfcast(5312);
quest::selfcast(5405);
quest::selfcast(5409);
quest::selfcast(5521);
quest::selfcast(5365);
quest::selfcast(278);
quest::selfcast(939);
quest::selfcast(3391);
quest::selfcast(5390);
$client->Message(315, "$NPCName whispers to you, 'Thank you $name!'");
} else {
$client->Message(315, "$NPCName whispers to you, 'Use the correct amount platinum, $name!'");
quest::givecash($copper,$silver,$gold,$platinum);
}
}
if (($platinum < 100) || ($platinum < 500) && ($platinum > 100) || ($platinum < 1000) && ($platinum > 100) && ($platinum > 500) || ($platinum > 1000)) {
$client->Message(315, "$NPCName whispers to you, 'Use the correct amount of platinum, $name!'");
quest::givecash($copper,$silver,$gold,$platinum);
}
}

lerxst2112
05-10-2011, 11:16 PM
Can you give us more details of what works and what doesn't? Have you tried slimming down the script to the bare minimum and adding additional functions one at a time to see when it breaks?

lich2594
05-11-2011, 07:11 AM
Without any details as to what's causing you the problems...

Try using:

my $NPCName = $npc->GetCleanName();

instead of:

my $NPCName = $npc->Ram();

Durge
05-11-2011, 07:35 AM
Ok I'll try that, and the problem is when i hail the npc (Ram) just a blank line appears on my chat window.

lich2594
05-11-2011, 07:38 AM
Ok I'll try that, and the problem is when i hail the npc (Ram) just a blank line appears on my chat window.

If it still appears as a blank line, I would suggest removing everything inside of the if statement, and replacing it with a single output to test that your NPC functions.

example:

if($text=~/Hail/i) { $client->Message(315, "$NPCName whispers to you, 'Ugh... do I work?'"); }

If it works with the single line statement, in this post, and not with all of the other checks... that simply means you have an error inside of the IF bracket. Remove everything, then add one line at a time. (Remember to change your level, to the desired level that you want to check to make sure that it works.)

Usually, you will get a blank line if none of the IF brackets are triggered.

lerxst2112
05-11-2011, 08:42 AM
I would guess the blank lines come from this:

$client->Message(7, " ");

lich2594
05-11-2011, 08:43 AM
I would guess the blank lines come from this:

$client->Message(7, " ");

That's correct... and since it isn't within the IF bracket, it will always execute as long as there isn't an error prior to that point in the script.

Durge
05-12-2011, 07:36 AM
I tried even one small message and it still didn't work.
Here is what I have.
I also tried with the name you gave me and it didn't work.
sub EVENT_SAY {

$client->Message(7, " ");
my $NPCName = $npc->Ram();
my $Hello = quest::saylink("Hello", 1);

if($text=~/Hail/i) {
$client->Message(315, "$NPCName whispers to you, '[$Hello], I am a test bot.'");
}
}

lich2594
05-12-2011, 07:41 AM
After changing the quest files, are you reloading quest memory? If I remember correctly, the command is: #reload pl (I haven't worked on the Emu in a while.)

Durge
05-12-2011, 07:13 PM
hmm, that didn't work either.

lerxst2112
05-12-2011, 08:28 PM
This line is wrong.

my $NPCName = $npc->Ram();

Replace with this as noted above:

my $NPCName = $npc->GetCleanName();

provocating
05-12-2011, 08:43 PM
After changing the quest files, are you reloading quest memory? If I remember correctly, the command is: #reload pl (I haven't worked on the Emu in a while.)

#reloadquest

Durge
05-12-2011, 10:24 PM
Yes i know it was wrong, I had already tried with "GetCleanName" and changed it back.

lerxst2112
05-12-2011, 10:27 PM
Well, like I said before. Strip the script down to the bare minimum, no saylinks, no npc name, nothing but a simple response to the hail, and if that works add things and see where you break it.

provocating
05-13-2011, 12:08 PM
Since this thread popped back up, I got back on finalizing my buff bot.

One thing I was never able to do is get the chanter or Cleric bot to cast spells that have a target of group v2. Spells like the Druid Skin like Nature work just fine.

I have tried combinations like these. I have in remarks what happened with each spell.

#$npc->SpellFinished(3479, $client->GetID()); #Buff bot cast virtue on herself
#$ent->CastSpell(3479, $ent, 10, -1, -1); #I cast virtue on myself
#$npc->CastSpell(3479, $ent, 10, -1, -1); #Buff bot cast virtue on herself
#$npc->CastSpell(3479, $userid); #Buff bot cast virtue on herself

Yeah I could code it to where I cast Virtue on myself but that seems really lame. Plus people will complain they did not get it, because they moved or something.

Xevious
05-22-2011, 10:01 AM
Thanks for the script. This was a good one for me to start learning with and Buffy is now a happy part of my server interacting with players and providing buffs.

I made a few tweaks that I liked, and wanted to share my changes if anyone cares for them:

- Removed the extra line feeds from her interaction (the " - " lines)
- Consolidated the matching logic for requested spells. Asking for "port" fed back 3 matches per spell in the original logic.
- Put her "action" logic on a 5 minute timer and gave her 33% chance to log out (depop), 33% chance to shout one of three things, and a 33% chance to just sit down and wait for a customer.

In her setup in the database, I set her on a 15 min spawn with a 5 minute variable timer, just to give her a bit more random and player like function.




#A buff bot script.
#Buffs a player for pp.

#SpellList is the array containing the names of the spells. SpellCost is the amount in pp for each spell. SpellID is the spell that is cast by the npc.
#Note these are 3 arrays. Each position in the array corosponds to the same position in the other arrays.
#So I have this set so that if you say 'Spirit of Wolf' and pay 2 pp, then the npc will cast spell 278 on you.
#I am setting the amounts to pp just because they can be any amount you wish, this requires changing the EVENT_ITEM function to handle the other money types.
@SpellList = ("Bind Affinity","Chloroplast","Port to Arcstone","Port to Barindu","Port to Blightfire Moors","Port to Bloodfields","Port to Buried Sea","Port to Butcher","Port to Cobalt Scar","Port to Commons","Port to Dawnshroud","Port to Feerrott","Port to Great Divide","Port to Grimling","Port to Iceclad","Port to Karana","Port to Knowledge","Port to Lavastorm","Port to Misty","Port to Natimbi","Port to Ro","Port to Steamfont","Port to Stonebrunt","Port to Surefall Glade","Port to the Combines","Port to the Nexus","Port to The Steppes","Port to Toxxulia","Port to Twilight","Port to Undershore","Port to Wakening Lands","Port to Emerald Jungle","Everlasting Breath","Levitation","Natureskin","Protection of the Cabbage","Regrowth","Resist Cold","Resist Disease","Resist Fire","Resist Magic","Resist Poison","See Invisible","Shield of Blades","Shield of Thorns","Skin like Diamond","Skin like Nature","Port to Sky Fire Mountains","Spirit of Eagle","Spirit of the Shrew","Spirit of Wolf","Storm Strength");
@SpellCost = ("2", "10", "15", "15", "2", "15", "15", "5", "10", "5", "8", "8", "8", "5", "8", "5", "8", "8", "8", "15", "8", "8", "5", "5", "8", "5", "20", "5", "8", "15", "10", "8", "2", "2", "15", "15", "15", "8", "10", "5", "10", "10", "2", "15", "10", "8", "10", "8", "15", "8", "2", "10");
@SpellID = ("35", "145", "8965", "5731", "9957", "6184", "11981", "553", "1440", "551", "2429", "556", "1438", "2419", "1434", "550", "3184", "554", "558", "4966", "555", "557", "3792", "2020", "1517", "2432", "9954", "552", "2424", "8235", "1398", "1737", "2881", "2894", "1559", "2188", "1568", "61", "63", "60", "64", "62", "80", "1560", "356", "422", "423", "1736", "2517", "4054", "278", "430");

sub EVENT_SPAWN
{
quest::settimer("buffy", 300);
quest::shout ("Hello everyone! I'm back for awhile offering druid buffs near the bank. Hail me if you are interested.");
}

sub EVENT_TIMER
{
#$npc->SetAppearance(1);
if($timer eq "buffy")
{
my $random_number = int(rand(8));
if ($random_number == 0 || $random_number == 1 || $random_numer == 2)
{
$npc->SetAppearance(1);
quest::shout ("Camping out for a bit. See you later!");
quest::depop();
}
elsif ($random_number == 3)
{
$npc->SetAppearance(0);
quest::shout("Need a port? Come see me by the tree at the main bank!");
}
elsif ($random_number == 4)
{
$npc->SetAppearance(0);
quest::shout("Giving druid buffs for pp by the tree near the bank!");
}
elsif ($random_number == 5)
{
$npc->SetAppearance(0);
quest::shout("Get your buffs here! Come see me over by the big bank!");
}
if ($random_number == 6 || $random_number == 7 || $random_numer == 8)
{
$npc->SetAppearance(1);
}
}
}

sub EVENT_SAY
{
my $all = quest::saylink("List", 1);
my $ports = quest::saylink("Ports",1);
my $buffs = quest::saylink("Buffs",1);
#Spacer between Text messages to make them easier to read
#$client->Message(7, "-");
my $NPCName = $npc->GetCleanName();
if ($text =~/Hail/i)
{
$npc->SetAppearance(0);
$client->Message(315, "$NPCName whispers to you, 'If you need a buff or a Port just let me know, or I can [$all] them for you. If you prefer to just see the [$buffs] or [$ports] I can do that too. You may also enter a partial name and I can find it.'");
}
#Counts each row for the While
my $count = 1;
#Counts each element in the Array for the While
my $n = 0;
if ($text !~ /Hail/i)
{
while ($SpellList[$n])
{
#This searches the list to find possible matches. The lc() command makes all text lowercase.
#It is easier to make all text lower case for comparison, if the user types uppercase it will still match.
if ((lc($SpellList[$n]) =~ lc($text) && lc($SpellList[$n]) ne lc($text)) || ($text =~ /^List$/i) || (($text =~ /Buffs/i) && ($SpellList[$n] !~ /Port to/i)) || (($text =~ /Ports/i) && ($SpellList[$n] =~ /Port to/i)))
{
my $SpellList = quest::saylink($SpellList[$n]);
my $SpellCost = $SpellCost[$n];
$client->Message(315, "$NPCName whispers to you, 'Possible match is: $SpellList and it costs $SpellCost pp");
}
#if ((lc($SpellList[$n]) =~ lc($text) && lc($SpellList[$n]) ne lc($text)) || (($text =~ /Buffs/i) && ($SpellList[$n] !~ /Port to/i)))
#{
# my $SpellList = quest::saylink($SpellList[$n]);
# my $SpellCost = $SpellCost[$n];
# $client->Message(315, "$NPCName whispers to you, 'Possible match is: $SpellList and it costs $SpellCost pp");
#}
#if ((lc($SpellList[$n]) =~ lc($text) && lc($SpellList[$n]) ne lc($text)) || (($text =~ /Ports/i) && ($SpellList[$n] =~ /Port to/i)) )
#{
# my $SpellList = quest::saylink($SpellList[$n]);
# my $SpellCost = $SpellCost[$n];
# $client->Message(315, "$NPCName whispers to you, 'Possible match is: $SpellList and it costs $SpellCost pp");
#}

#This is the command that is executed when a the user enters a spell.
if (lc($SpellList[$n]) eq lc($text) && $text !~ /^List$/i)
{
#Creates a global variable. You must set the qgolbal field in the npc_types table to 1 for each npc you wish to handle global variables.
#buff is the name, $text is what the varible should be eq too, 0 only this npc, char, and zone apply to the variable, M5 is 5 minutes.
quest::setglobal("buff", $text, 0, "M5");
#I'm not sure why I need the next line, the line above should set the $qglobals{buff}, but it wouldn't work for me.
$qglobals{buff} = $text;
$client->Message(315, "Please give me $SpellCost[$n]pp, and I'll cast $qglobals{buff} for you!");
}
$n++;
$count++;
}
}
}

sub EVENT_ITEM
{
my $correctmoney = 0;
#Counts each row for the While
my $count = 1;
#Counts each element in the Array for the While
my $n = 0;
#Cycles through each spell in the array until it matches the requested spell, and the amount pp required.
while ($SpellList[$n])
{
if(($SpellList[$n] eq $qglobals{buff}) && ($platinum == $SpellCost[$n]))
{
$client->Message(315, "Thank you for the $SpellCost[$n]pp, prepare for $qglobals{buff}!");
if ($SpellList[$n] =~ /Port to/i)
{
quest::selfcast($SpellID[$n])
}
else
{
$npc->CastSpell($SpellID[$n], $userid);
}
#set this to 1 so that we don't return money we shouldn't.
$correctmoney = 1;
}
$n++;
$count++;
}
#Returns the money if it is not the correct amount.
if ($correctmoney == 0 )
{
if(($copper > 0) || ($silver > 0) || ($gold > 0) || ($platinum > 0))
{
$client->Message(315, "I don't need these coins, you may have them back.");
quest::givecash($copper,$silver,$gold,$platinum);
}
}
#deletes the $qglobals{buff} variable.
quest::delglobal("buff");
}

provocating
05-22-2011, 10:06 AM
I have three on my server now. A cleric, a druid and an enchanter. I also have them doing a MGB at random intervals, like a minimum of around 40 minutes with a max around 80 minutes. The start giving MGB calls every minute, 5 minutes before time for the MGB. The still act like buff vendors and give random calls through the zone with random text.