|
|
 |
 |
 |
 |
|
 |
 |
|
 |
 |
|
 |
|
Quests::Q&A This is the quest support section |
 |
|
 |

01-09-2010, 10:14 PM
|
 |
Developer
|
|
Join Date: Aug 2006
Location: USA
Posts: 5,946
|
|
Sub and Function Files for Perl?
I was thinking it would be cool if we had an easy way to force our current scripts to read a function or subroutine file prior to reading the actual script file. This would allow some repeatable sections of scripts to be created as functions which are run through 1 or 2 files to handle the sub or function part of the script. This is probably fairly basic stuff for you Perl people out there, but I didn't know it was even possible until recently and I think it would be awesome if I could get it working lol.
The idea is that we might have a file named "perl_functions.pl" in our quest directory and for any NPC script that we wanted to have access to the functions in that file, we would add a line similar to this:
Code:
require "./home/eqemu/server/quests/perl_functions.pl";
And then the NPC script would be able to use any of the functions set from that file.
So, for those not familiar with a system like this, here is an example of how it would work:
TestNPC.pl
Code:
require "./home/eqemu/server/quests/perl_functions.pl";
Sub EVENT_ATTACK {
&CastSpellOnTarget(9425);
}
perl_functions.pl
Code:
sub CastSpellOnTarget {
my $CastSpellID = $_[0]; #Use the Spell ID Supplied to the Function - "$_[0]" means to use the first argument given
my $Cur_Target = $npc->GetTarget(); #Get the current Target for this NPC
if ($Cur_Target) { #Only cast if the NPC actually has a Target
my $My_Target = $Cur_Target->GetID(); #Get the Entity ID of the Target
$npc->CastSpell($CastSpellID, $My_Target); #Cast the requested Spell ID on the NPC Target
}
}
(Note: this section of code would be much more useful in an EVENT_TIMER where the $client is not exported)
With that section of script being set as a function that can then be called at any point, we can reduce the overhead within long scripts that repeat the same section of scripting over and over.
At this point, I just can't get the require to work right to run functions from other files like I need for a system like this. Does anyone know how to do that?
If we can get this working, I think it would allow for some special perl functions to be made that don't necessarily need to be added into the source code. Then, we could even add a page on the wiki that contains a compiled list of functions different people have made so everyone can make use of them just by adding the require line (or whatever is needed) to any NPC scripts they might want to use it on.
Last edited by trevius; 01-09-2010 at 10:34 PM..
|
 |
|
 |

01-09-2010, 10:18 PM
|
 |
Discordant
|
|
Join Date: Mar 2009
Location: Ottawa
Posts: 495
|
|
I would really like all of the perl functions listed like this (if that's possible), particularly since I'd like to be able to overload some of them (quest::say actually).
Admittedly, I don't really understand how the perl scripts interact with the server, the whole C/perl combination thing confuses me.
|
 |
|
 |

01-09-2010, 10:32 PM
|
 |
Developer
|
|
Join Date: Aug 2006
Location: USA
Posts: 5,946
|
|
Yeah, I don't quite understand how they interact either yet, which is why I posted this lol. But, if we can get it working, I imagine you would use Quest Objects and make functions to use them to replace stuff like quest::say(). For example, you might make something like this:
TestNPC.pl
Code:
require "./home/eqemu/server/quests/perl_functions.pl";
Sub EVENT_SAY {
if ($text =~/hail/i)
{
&NPCWhisper("Hello, $name!"); #Call the function from the perl_functions.pl file
}
}
perl_functions.pl
Code:
sub NPCWhisper {
my $TextColor = 7; #Set the Text Color for the Message (this one is beige)
my $MyMessage = $_[0]; #Use the Message Supplied to the Function - "$_[0]" means to use the first argument given
if ($client) {
$client->Message($TextColor, "-"); #Spacer between Text messages to make them easier to read
my $NPCName = $npc->GetCleanName(); #Get the clean name of the NPC sending the message
$client->Message($TextColor, "$NPCName whispers, '$MyMessage'"); #Send a message to the player simulating a whisper directly to them from the NPC
}
}
|
 |
|
 |

01-09-2010, 11:21 PM
|
 |
Discordant
|
|
Join Date: Mar 2009
Location: Ottawa
Posts: 495
|
|
I was working on a script to change languages of every npc in the game to something more akin to their race, as part of some customization for my server to make languages feel more important.
I wanted to overload quest::say() to automatically do a lookup on the npc's race and then select a language that I had set in a data structure.
|
 |
|
 |

01-10-2010, 12:53 AM
|
 |
Developer
|
|
Join Date: Aug 2006
Location: USA
Posts: 5,946
|
|
Yeah, if someone can help me get this system working properly to let NPC quest files access other files, you could probably build a function that includes an array or hash that will convert each race to whatever language you want that race to speak and then have them speak in that language. It might work something like this:
TestNPC.pl
Code:
require "./home/eqemu/server/quests/perl_functions.pl";
Sub EVENT_SAY {
if ($text =~/hail/i)
{
&RacialLanguageSay("Hello, $name!");
}
}
perl_functions.pl
Code:
sub RacialLanguageSay {
my $MyMessage = $_[0]; #Use the Message Supplied to the Function - "$_[0]" means to use the first argument given
my $NPCRace = $npc->GetRace(); #Get the Race of the NPC that is Speaking
# Create a hash of each language that each race should use
%RaceLanguages = (
1 => 1, # NPC Race - Language Note
2 => 2, # NPC Race - Language Note
3 => 3, # NPC Race - Language Note
4 => 4, # NPC Race - Language Note
5 => 5, # NPC Race - Language Note
6 => 5, # NPC Race - Language Note
7 => 5, # NPC Race - Language Note
8 => 6, # NPC Race - Language Note
9 => 7, # NPC Race - Language Note
10 => 8, # NPC Race - Language Note
11 => 9, # NPC Race - Language Note
12 => 9, # NPC Race - Language Note
13 => 9, # NPC Race - Language Note
14 => 2, # NPC Race - Language Note
15 => 3, # NPC Race - Language Note
16 => 4, # NPC Race - Language Note
17 => 12, # NPC Race - Language Note
18 => 15, # NPC Race - Language Note
19 => 15, # NPC Race - Language Note
20 => 15, # NPC Race - Language Note
21 => 19, # NPC Race - Language Note
22 => 19, # NPC Race - Language Note
23 => 19, # NPC Race - Language Note
24 => 2, # NPC Race - Language Note
25 => 3, # NPC Race - Language Note
26 => 4, # NPC Race - Language Note
27 => 5, # NPC Race - Language Note
28 => 6, # NPC Race - Language Note
);
#Note that the above languages and races are just made up as examples
quest::say($MyMessage, $RaceLanguages{$NPCRace});
}
This would then be usable from any of your scripts as long as you added the require (or whatever is ultimately needed) to get your NPC script to read the perl_functions.pl file. Stuff like this is exactly why I want to get this system working. It could allow more flexibility to servers without requiring updates to source code. It might make perl a bit more load, but I don't really know enough to say if it would be a noticeable impact or not.
BTW, here is a page that explains require(), use(), Libaries, Modules and other similar things that might help in getting this to work.
http://www.perl.com/pub/a/2002/05/14...rl.html?page=3
I have tried a few ways, but no luck so far.
Last edited by trevius; 01-10-2010 at 01:08 AM..
|
 |
|
 |

01-10-2010, 01:08 AM
|
 |
Discordant
|
|
Join Date: Mar 2009
Location: Ottawa
Posts: 495
|
|
Ah right, I understand what you were trying to say now.
Yeah, it would be nice if we could have an included file or (more extensible), a folder that perl would include for user defined functions.
|
 |
|
 |

01-10-2010, 01:17 AM
|
 |
Developer
|
|
Join Date: Aug 2006
Location: USA
Posts: 5,946
|
|
I haven't ever really played with the quest plugins in the plugins folder, so maybe they already do what I am wanting to do. Though, it is my understanding that you have to restart the whole server to get new plugins to take effect.
If plugins can already do it, then I will just get started on some new plugins I guess lol.
Here is an example plugin I have in my plugins folder (I do not currently use it):
soulbinders.pl
Code:
#!/usr/bin/perl
sub soulbinder_say {
my $text = shift;
if($text=~/hail/i){
quest::say("Greetings $name. When a hero of our world is slain their soul returns to the place it was last bound and the body is reincarnated.
As a member of the Order of Eternity it is my duty to [bind your soul] to this location if that is your wish.");
} elsif($text=~/bind my soul/i) {
quest::say("Binding your soul. You will return here when you die.");
quest::selfcast(2049);
}
}
If this is doing what I think it is, then I should be able to call that just by doing the following in any NPC script:
TestNPC.pl
Code:
Sub EVENT_SAY {
plugin::soulbinder_say($text);
}
LOL, if that is true, then I will be bonking myself for not looking into plugins a long time ago. Then, we will just need a way to reload the plugins without having to restart the server to start using the changes/additions.
Last edited by trevius; 01-10-2010 at 05:08 AM..
|
 |
|
 |

01-10-2010, 04:45 AM
|
Administrator
|
|
Join Date: Sep 2006
Posts: 1,348
|
|
Yeah plugins basically work like this. It's plugin not pluggin though.
|

01-10-2010, 05:13 AM
|
 |
Developer
|
|
Join Date: Aug 2006
Location: USA
Posts: 5,946
|
|
Oops, typo. I fixed it, thanks.
So, I am guessing that plugins get loaded into memory when the server starts? That would probably explain why they only update when the server is restarted. Any possibility of a way to make them update without a restart? If not, no biggie, but it would be helpful for testing purposes. I plan to add a decent number of plugins now that I know how to use them somewhat.
I will still need to figure out how the "shift" works for using the arguments, but it doesn't seem too hard. I also need to to play around with it and see how well it works for returning data. I have read that for certain perl features similar to this to work, the result of the file must always be true. That is why the files all end with "1;" as the last line. I am not sure that this is required for our plugin system yet, but some testing can probably determine that.
|
 |
|
 |

01-10-2010, 05:24 AM
|
Developer
|
|
Join Date: Feb 2004
Location: UK
Posts: 1,540
|
|
require does work.
If I put this in /tmp/myfunc.pl
Code:
sub MyFunc {
quest::say("This is MyFunc().");
}
return 1;
And this in Guard_Bixby.pl
Code:
require ("/tmp/myfunc.pl");
sub EVENT_SAY {
quest::say("Before call to MyFunc().");
MyFunc();
quest::say("After call to MyFunc().");
}
It works fine. Apparently you need the 'return 1' at the end of the required .pl file to tell Perl any initialisation code in that file executed OK, otherwise it returns this error:
Code:
/tmp/myfunc.pl did not return a true value at Guard_Bixby.pl line 1.
|

05-14-2010, 10:22 AM
|
Fire Beetle
|
|
Join Date: May 2010
Posts: 3
|
|
Late to the party here, but that's always been possible. If load-order is controlled, you can just overwrite the function directly by using a different scope modifier - i.e. sub qstxxxsomescope::sub_whisper. Furthermore, since pretty much everything in Perl is a higher order function, you can make a function or even a closure to pass to another function... this would allow you to, for example, alter a quest on the fly for any mob in the game. You could use this to do stuff like have a central quest giver who assigns dynamic and random tasks - i.e., go talk to this guy or that guy while modifying the target's scripts all on the fly, etc. You can modify the behavior of every mob in the zone using these overrides in as little as one command.
|
Thread Tools |
|
Display Modes |
Hybrid Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -4. The time now is 05:56 PM.
|
|
 |
|
 |
|
|
|
 |
|
 |
|
 |