Thread: Say Links
View Single Post
  #1  
Old 04-13-2009, 04:55 AM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default Say Links

This is an interesting idea I had a while back, but never really put much thought into it until recently. Basically, the idea is that we could make a way for quest text from NPCs to have links in them that would essentially look like item links, but instead of showing the item when you click them, it would make the NPC respond as if you had said what ever the name of the link was.

For example, I could have an NPC that says something like this:

Quote:
Soandso says,'Would you like to test a say link?'
And, if you clicked the word "test" there, it would reply as if you had typed "/say test".

So far, I have the basic concept working. I have been able to get this to work with a predefined catch phrase. If we could figure out how to get the actual link name from the quest script, I think it would be pretty easy to make this fully functional.

Here is what I have so far:

NOTE: This is test code, not a finished product yet. Just for development purposes

In client_packet.cpp, replace the following:
Code:
void Client::Handle_OP_ItemLinkClick(const EQApplicationPacket *app)
{
	if(app->size != sizeof(ItemViewRequest_Struct)){
		LogFile->write(EQEMuLog::Error, "Wrong size on OP_ItemLinkClick.  Got: %i, Expected: %i", app->size, sizeof(ItemViewRequest_Struct));
		DumpPacket(app);
		return;
	}
	DumpPacket(app);
	ItemViewRequest_Struct* ivrs = (ItemViewRequest_Struct*)app->pBuffer;

	//todo: verify ivrs->link_hash based on a rule, in case we don't care about people being able to sniff data from the item DB

	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;
	}

	ItemInst* inst = database.CreateItem(item, item->MaxCharges, ivrs->augments[0], ivrs->augments[1], ivrs->augments[2], ivrs->augments[3], ivrs->augments[4]);
	if (inst) {
		SendItemPacket(0, inst, ItemPacketViewLink);
		safe_delete(inst);
	}
	return;
}
With this:
Code:
void Client::Handle_OP_ItemLinkClick(const EQApplicationPacket *app)
{
	if(app->size != sizeof(ItemViewRequest_Struct)){
		LogFile->write(EQEMuLog::Error, "Wrong size on OP_ItemLinkClick.  Got: %i, Expected: %i", app->size, sizeof(ItemViewRequest_Struct));
		DumpPacket(app);
		return;
	}
	DumpPacket(app);
	ItemViewRequest_Struct* ivrs = (ItemViewRequest_Struct*)app->pBuffer;

	//todo: verify ivrs->link_hash based on a rule, in case we don't care about people being able to sniff data from the item DB

	const Item_Struct* item = database.GetItem(ivrs->item_id);
	if (!item) {
		if (ivrs->item_id == 999999)
		{
			this->ChannelMessageReceived(8, 1, 100, "test");
			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]);
	if (inst) {
		SendItemPacket(0, inst, ItemPacketViewLink);
		safe_delete(inst);
	}
	return;
}
Then, to test that, you just set an NPC to use this example quest script:
Code:
sub EVENT_SAY {

my $clientver = $client->GetClientVersion(); #this is just so the example works for all clients
my $test_sof = sprintf("%c%06X%s%s%c",0x12,999999,"00000000000000000000000000000000000000000000","test",0x12);
my $test = sprintf("%c%06X%s%s%c",0x12,999999,"000000000000000000000000000000000000000","test",0x12);

  if($text=~/hail/i && $clientver == 3) {
      quest::say("Would you like to $test_sof a say link?"); }

  if($text=~/hail/i && $clientver != 3) {
      quest::say("Would you like to $test a say link?"); }

  if ($text =~/test/i) {
      quest::say ("This test was a success!"); }

}
Then, simply hail the NPC and click the "test" link in the message and it will reply appropriately.

I am sure we could make a quest command that would make creating say links very quick. It could be something like quest::saylink(message), where "message" would be the name of the link. The only hard part would be figuring out a way to pass the message string into the Handle_OP_ItemLinkClick function. I don't know if it would even be possible, but if so, it should be easy to finish this off. It is too bad that the name of the item link isn't passed from the client when they click a link, or this would be extremely simple to finish off. I just can't think of any way to possibly pass that string into this function.

This definitely isn't a high priority or anything, but I thought it would be pretty cool to see working. I am actually surprised SOE hasn't done something like this yet. I think it would definitely bump the EQ quest system a little closer to being current. Not that I mind typing them out, but I bet some players would really like it. Of course, players would still be able to type it out if they preferred to do so.

If anyone has any suggestions on how to finish this off, I am sure some people would enjoy playing with it

Edit:
The only way I can think of to maybe get this working would be to have the quest::saylink() command set to automatically generate unique bogus item IDs for every saylink used in each quest file and store them to memory when the server boots up. It would basically be like generating a list of fake items, accept it shouldn't take too much memory since it only needs an item ID and then the message, not all other item stats. As long as it started at item ID 500k on up, I don't think we would ever have to worry about real item IDs ever overlapping into the say link ones. This would be above my coding skill level to write though, but maybe there is a simpler way to do it.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!

Last edited by trevius; 04-13-2009 at 01:14 PM..
Reply With Quote