|
|
|
 |
 |
 |
 |
|
 |
 |
|
 |
 |
|
 |
|
| Development::Development Forum for development topics and for those interested in EQEMu development. (Not a support forum) |

04-19-2009, 11:43 AM
|
|
Sarnak
|
|
Join Date: Mar 2008
Posts: 47
|
|
Trev
This is a great idea. I've always hated the quest system (typing text) in EQ.
Good luck with it.
War
|
 |
|
 |

04-19-2009, 05:01 PM
|
 |
Developer
|
|
Join Date: Aug 2006
Location: USA
Posts: 5,946
|
|
I have been thinking about this a bit more and I think I know of a way to make it work smoothly with the minimal amount of work. Here is what I am thinking:
1. Add a new table named "saylinks" that has 2 fields: ID and Phrase. The ID field would just be an auto-incrementing ID number. The Phrase field would be a the string for the actual phrase we are wanting to create a link fro.
2. Add an in-game command that will allow admins to add a phrase to the new saylink table. This command would be called something like #addsaylink <message> and it would just add the new message and assign it to the auto-incremented ID. This way, an admin can go through their quest prompts from in game and add the links as they see them. This is optional, but I think it would be a nice feature to help simplify the process. Of course, people could simple update the table manually if they preferred.
3. Create a new quest command that would generate the hash of the item link directly into a script text message. For example:
Code:
quest::say("This is a quest::saylink(link) example.");
And that line would show this when the NPC says it:
Code:
Soanso says,'This is a link example'
This may be one of the hardest parts, because I am not sure how to have it convert the quest command directly into the hash when it is inside of a string like that. I am pretty sure that quest::ChooseRandom() works inside of a string like that, so I may have to do some looking into how it works for that command. Otherwise, we would have to do something like this instead:
Code:
my $link = quest::saylink(link);
quest::say("This is a $link example.");
Which should be easy enough to do, but for scripting purposes, it would make things much quicker and simpler to do it the first way inside the actual string.
4. The quest::saylink() command would be set to query the saylink table in the database. Since the ID numbers would start at 1 and go up from there, the saylink quest function would then simple add 1 million to that number to create the item_id number for the hash. So, if the table had the first phrase as ID 1, that would be converted to 1000001 as the ID number. Then, the Handle_OP_ItemLinkClick would just be set to look for any item_id over 1 million and handle any that are as a say link.
5. Once the Handle_OP_ItemLinkClick finds a hash that needs to be treated as a say link, it will just do a simple database query in the saylink table for the phrase that matches that item ID. Since the item ID had 1 million added to it, it would need to subtract 1 million before doing the query. Then, it would simply parse it like it does in the code I first submitted here.
I think the hard parts are going to be getting the quest command to output an item link from directly within a string, and also to get the queries working perfectly. I am not much of a query guru, so I may need help to make sure the query is set properly. Basically it would just be querying the string that would be the hard part. We would need to make sure that it finds the exact match, and not just a partial or one that just contains the string.
The saylink table would be set to use the phrase as the key, so there wouldn't be multiple entries for the same phrase. There isn't any need to have more than 1 entry for the same string anyway.
Last, there would just need to be a few error messages set in place to report if something is missing. Like, if you try to use quest::saylink() without actually having that string in the saylink table. It could have the NPC give some warning about needing to update the database.
I don't know how many admins would use a system like this. I just think it would be something interesting and new. I have a feeling that once people actually see it working, it will grow on them quickly.
|
 |
|
 |
 |
|
 |

04-19-2009, 07:28 PM
|
 |
Developer
|
|
Join Date: Aug 2006
Location: USA
Posts: 5,946
|
|
Just thought of a way to make this considerably more simple to use. Basically, everything would remain the same, accept you would no longer need to update the saylink table manually or via commands at all. The only thing people wanting to use this system would need to do would be to add the quest::saylink() functions into their quest::say() messages to replace the current ones they have set.
The idea is that the quest::saylink() command would do it's query of the saylink table to see if it had a matching string. If it doesn't find a match, the new idea is that it would simply create one itself at the time the link is generated. So, once the scripts have the quest::saylink() command added, as players go through the quest prompts in-game, it will populate the saylink table automatically and then save them for future use.
I think this is probably about as simple as it can get. Now, if only I can figure out how to actually make it do all of that properly :P
By using this system along with the $client->Message function, you could in theory have complete conversations between the player and an NPC without any other player seeing a single message. This seems like it might be useful in highly populated city areas to reduce spam considerably. It also might make some players feel more comfortable to go through all of an NPC's quest prompts. I know at least a few people who feel like they are spamming others when they speak with NPCs, and so they are shy about doing it. I can't wait to try this system out if it ever gets completed. Any suggestions are more than welcome 
Last edited by trevius; 04-20-2009 at 03:33 AM..
|
 |
|
 |

04-19-2009, 09:33 PM
|
|
Developer
|
|
Join Date: Dec 2007
Posts: 122
|
|
I might be missing something, but why mess with the database at all? What about structuring it something like:
quest::saylink(text,value)
and have the function return a link to a fictitious item. You could use your plan of using item values over 1,000,000, or maybe negative item values if you wanted to be sure of never interfering with anything. Then you could adjust the code to activate a ChannelMessageReceived function based on the value you entered.
So, for example quest::saylink("test",1) would create a link on the word "test." When you clicked it, it would send a message of SayLink1, or something along those lines. That way, you could have multiple saylinks in one quest without too much complexity. I won't have a chance to look at the source for a bit, but I have a basic idea of how it might be coded.
|
 |
|
 |

04-20-2009, 01:44 AM
|
|
Developer
|
|
Join Date: Dec 2007
Posts: 122
|
|
I played around with the idea a little bit tonight, and here's what I've come up with as a first attempt.
Code:
Index: zone/client_packet.cpp
===================================================================
--- zone/client_packet.cpp (revision 437)
+++ zone/client_packet.cpp (working copy)
@@ -2163,8 +2166,17 @@
const Item_Struct* item = database.GetItem(ivrs->item_id);
if (!item) {
- Message(13, "Error: The item for the link you have clicked on does not exist!");
- return;
+ if (ivrs->item_id > 1000000)
+ {
+ char response[20];
+ sprintf(response,"SayLink%u",ivrs->item_id - 1000000);
+ this->ChannelMessageReceived(8, 1, 100, response);
+ return;
+ }
+ else {
+ Message(13, "Error: The item for the link you have clicked on does not exist!");
+ return;
+ }
}
ItemInst* inst = database.CreateItem(item, item->MaxCharges, ivrs->augments[0], ivrs->augments[1], ivrs->augments[2], ivrs->augments[3], ivrs->augments[4]);
@@ -7155,7 +7167,7 @@
if(!p_timers.Load(&database)) {
LogFile->write(EQEMuLog::Error, "Unable to load ability timers from the database for %s (%i)!", GetCleanName(), CharacterID());
}
-
+
#ifdef _EQDEBUG
printf("Dumping inventory on load:\n");
m_inv.dumpInventory();
Index: zone/perlparser.cpp
===================================================================
--- zone/perlparser.cpp (revision 437)
+++ zone/perlparser.cpp (working copy)
@@ -2446,7 +2446,31 @@
XSRETURN_UV(quantity);
}
+XS(XS__SayLink);
+XS(XS__SayLink) {
+ dXSARGS;
+ if (items != 2)
+ Perl_croak(aTHX_ "Usage: saylink(text, saylinkID)");
+ dXSTARG;
+ Const_char * RETVAL;
+ char text[250];
+ uint16 ID;
+
+ strcpy(text,(char *)SvPV_nolen(ST(0)));
+
+ ID = (int)SvUV(ST(1));
+
+ RETVAL = quest_manager.SayLink(text,ID);
+
+ sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG;
+ XSRETURN(1);
+}
+
+
+
+
+
/*
This is the callback perl will look for to setup the
quest package's XSUBs
@@ -2617,6 +2641,7 @@
newXS(strcpy(buf, "updatespawntimer"), XS__UpdateSpawnTimer, file);
newXS(strcpy(buf, "MerchantSetItem"), XS__MerchantSetItem, file);
newXS(strcpy(buf, "MerchantCountItem"), XS__MerchantCountItem, file);
+ newXS(strcpy(buf, "saylink"), XS__SayLink, file);
XSRETURN_YES;
}
Index: zone/questmgr.cpp
===================================================================
--- zone/questmgr.cpp (revision 437)
+++ zone/questmgr.cpp (working copy)
@@ -1821,3 +1821,10 @@
return Quant; // return the quantity of itemid (0 if it was never found)
}
+
+const char * QuestManager::SayLink(char* text, uint16 value) {
+ char linktext[250];
+ sprintf(linktext,"%c%06X%s%s%c",0x12,1000000+value,"000000000000000000000000000000000000000",text,0x12);
+ strcpy(text,linktext);
+ return text;
+};
Index: zone/questmgr.h
===================================================================
--- zone/questmgr.h (revision 437)
+++ zone/questmgr.h (working copy)
@@ -197,6 +197,8 @@
void MerchantSetItem(int32 NPCid, int32 itemid, int32 quantity = 0);
int32 MerchantCountItem(int32 NPCid, int32 itemid);
+
+ const char* SayLink(char* text, uint16 value);
//not in here because it retains perl types
//thing ChooseRandom(array_of_things)
It only does the Titanium formating at the moment, and it will break if there are ever legitimate item ids over 1 million, but I tested a couple of different things and it seems to do all right. There's not much in the way of error checking, so it'll probably crash the zone if anything too strange gets entered as parameters.
The syntax is quest::saylink(message,n)
And when the link is clicked, it sends a message "SayLinkn". Here was my simple test script:
Code:
my $test1 = quest::saylink("trying,1");
my $test2 = quest::saylink("forget,2");
sub EVENT_SAY {
if($text=~/Hail/i) {
quest::say("I've noticed that sometimes certain words I say just feel... different. Should I keep $test1 to see what I can do with them, or just $test2 the whole thing?");
}
if($text=~/SayLink1/) {
quest::say("You're right, I bet I can make something out of them.");
}
if($text=~/SayLink2/) {
quest::say("I knew it was too much to hope for.");
}
}
|
 |
|
 |
 |
|
 |

04-20-2009, 04:52 AM
|
 |
Developer
|
|
Join Date: Aug 2006
Location: USA
Posts: 5,946
|
|
Thanks for the info
I had thought about doing something like that, but it wouldn't be quite as ideal as what I am wanting to do with it. Basically, I want to make the saylinks an option to players. So, if they prefer clicking the links, they can click them, but if they prefer to just type the phrase, they can do that as well. And, it wouldn't require any extra scripting to handle the saylinks or normal say messages. I know at least a few players who play almost solely with the keyboard and only ever have to touch their mouse when they are looting a corpse.
The idea you had would work fine, but it would make quest scripting a bit more involved, which is one of the main things I am trying not to do. If I can't get the way I am wanting to do it working, we could definitely put it in the way you have it coded though.
Here is the difference of what it would take to write the same exact quest to use your code as it would for what I am suggesting (including the option to /say the phrase):
Your idea:
Code:
my $test1 = quest::saylink("test,1");
sub EVENT_SAY {
if($text=~/Hail/i) {
quest::say("Would you like to $test1 a say link?");
}
if($text=~/SayLink1/) {
quest::say("The test was a success!");
}
if($text=~/test/i) {
quest::say("The test was a success!");
}
}
My idea:
Code:
my $test1 = quest::saylink("test");
sub EVENT_SAY {
if($text=~/Hail/i) {
quest::say("Would you like to $test1 a say link?");
}
if($text=~/test/i) {
quest::say("The test was a success!");
}
}
Not really a huge deal, but it would get tougher to manage if you have long scripts with lots of phrases and text.
I really appreciate the help on this though. I think it will be something cool to play with when it is all done. I bet players will be really surprised to see it when it first shows up on servers. And, I bet it isn't long before EQLive has something similar lol.
Last edited by trevius; 04-20-2009 at 02:12 PM..
|
 |
|
 |

04-20-2009, 07:39 AM
|
|
Sarnak
|
|
Join Date: Jan 2008
Posts: 47
|
|
What're you saying Trev? That we've had some great ideas that showed up on Live? Why, that just means SoE listens to its fanbase. 
|
| 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 11:48 AM.
|
|
 |
|
 |
|
|
|
 |
|
 |
|
 |