PDA

View Full Version : Client popup window (like in the tutorial zone)


Derision
08-25-2008, 11:50 AM
Discussion: http://eqemulator.net/forums/showthread.php?t=26312

This patch allows the quest system to send a 'popup' window to the client as you see in the tutorial zone.

Patch against the code from KLS' SVN on googlecode:


diff -u --recursive ../kikiaemu-read-only/common/eq_packet_structs.h ./common/eq_packet_structs.h
--- ../kikiaemu-read-only/common/eq_packet_structs.h 2008-08-25 15:39:01.000000000 +0100
+++ ./common/eq_packet_structs.h 2008-08-25 16:14:21.000000000 +0100
@@ -2929,6 +2929,16 @@
uint8 unknown5;
};

+// 4244 bytes. Is not really an 'OnLevelMessage', it causes a popup box to display in the client
+// Text looks like HTML.
+struct OnLevelMessage_Struct {
+/*0000*/ char Title[128];
+/*0128*/ char Text[4100];
+/*4228*/ uint32 unknown4228;
+/*4232*/ uint32 unknown4232;
+/*4236*/ uint32 unknown4236;
+/*4240*/ uint32 unknown4240;
+};

struct BankerChange_Struct {
uint32 platinum;
diff -u --recursive ../kikiaemu-read-only/utils/patch_Titanium.conf ./utils/patch_Titanium.conf
--- ../kikiaemu-read-only/utils/patch_Titanium.conf 2008-08-25 15:41:12.000000000 +0100
+++ ./utils/patch_Titanium.conf 2008-08-25 16:14:48.000000000 +0100
@@ -448,7 +448,7 @@
OP_OpenDiscordMerchant=0x0000 #8 bytes
OP_DiscordMerchantInventory=0x0000 #long item packet
OP_GiveMoney=0x0000 #16 bytes, pp, gp, sp, cp.
-OP_OnLevelMessage=0x0000
+OP_OnLevelMessage=0x1dde
OP_RequestKnowledgeBase=0x0000
OP_KnowledgeBase=0x0000
OP_SlashAdventure=0x571a # /adventure
diff -u --recursive ../kikiaemu-read-only/zone/client.cpp ./zone/client.cpp
--- ../kikiaemu-read-only/zone/client.cpp 2008-08-25 15:43:43.000000000 +0100
+++ ./zone/client.cpp 2008-08-25 16:13:25.000000000 +0100
@@ -3276,3 +3276,22 @@
safe_delete(outapp);
}

+void Client::SendPopupToClient(char *Title, char *Text) {
+
+ EQApplicationPacket *outapp = new EQApplicationPacket(OP_OnLevelMessage, sizeof(OnLevelMessage_Struct));
+ OnLevelMessage_Struct *olms = (OnLevelMessage_Struct *) outapp->pBuffer;
+
+ if((strlen(Title) > (sizeof(olms->Title)-1)) ||
+ (strlen(Text) > (sizeof(olms->Text)-1))) return;
+
+ strcpy(olms->Title, Title);
+ strcpy(olms->Text, Text);
+
+ olms->unknown4228 = 0xffffffff;
+ olms->unknown4232 = 0xffffffff;
+ olms->unknown4236 = 0x00000000;
+ olms->unknown4240 = 0xffffffff;
+
+ QueuePacket(outapp);
+ safe_delete(outapp);
+}
diff -u --recursive ../kikiaemu-read-only/zone/client.h ./zone/client.h
--- ../kikiaemu-read-only/zone/client.h 2008-08-25 15:43:43.000000000 +0100
+++ ./zone/client.h 2008-08-25 16:12:45.000000000 +0100
@@ -684,6 +684,7 @@
int FindSpellBookSlotBySpellID(int16 spellid);
int GetNextAvailableSpellBookSlot();
int16 GetMaxSkillAfterSpecializationRules(SkillType skillid, int16 maxSkill);
+ void SendPopupToClient(char *Title, char *Text);


protected:
diff -u --recursive ../kikiaemu-read-only/zone/perlparser.cpp ./zone/perlparser.cpp
--- ../kikiaemu-read-only/zone/perlparser.cpp 2008-08-25 15:43:43.000000000 +0100
+++ ./zone/perlparser.cpp 2008-08-25 16:11:17.000000000 +0100
@@ -1756,6 +1756,17 @@
XSRETURN_EMPTY;
}

+XS(XS__popup); // prototype to pass -Wmissing-prototypes
+XS(XS__popup) {
+ dXSARGS;
+
+ if (items != 2)
+ Perl_croak(aTHX_ "Usage: popup(windowtitle, text)");
+
+ quest_manager.popup(SvPV_nolen(ST(0)), SvPV_nolen(ST(1)));
+
+ XSRETURN_EMPTY;
+}
/*

This is the callback perl will look for to setup the
@@ -1880,6 +1891,7 @@
newXS(strcpy(buf, "playergender"), XS__playergender, file);
newXS(strcpy(buf, "playersize"), XS__playersize, file);
newXS(strcpy(buf, "playertexture"), XS__playertexture, file);
+ newXS(strcpy(buf, "popup"), XS__popup, file);
XSRETURN_YES;
}

diff -u --recursive ../kikiaemu-read-only/zone/questmgr.cpp ./zone/questmgr.cpp
--- ../kikiaemu-read-only/zone/questmgr.cpp 2008-08-25 15:43:43.000000000 +0100
+++ ./zone/questmgr.cpp 2008-08-25 16:12:16.000000000 +0100
@@ -1387,4 +1387,9 @@
void QuestManager::playertexture(int newtexture)
{
initiator->SendIllusionPacket(initiator->GetRace(), 0xFF, newtexture);
-}
\ No newline at end of file
+}
+
+void QuestManager::popup(char *title, char *text) {
+
+ if(initiator) initiator->SendPopupToClient(title, text);
+}
diff -u --recursive ../kikiaemu-read-only/zone/questmgr.h ./zone/questmgr.h
--- ../kikiaemu-read-only/zone/questmgr.h 2008-08-25 15:43:43.000000000 +0100
+++ ./zone/questmgr.h 2008-08-25 16:11:41.000000000 +0100
@@ -146,6 +146,7 @@
void playergender(int gender_id);
void playersize(int newsize);
void playertexture(int newtexture);
+ void popup(char *title, char *text);

//not in here because it retains perl types
//thing ChooseRandom(array_of_things)


To use it, from a Perl quest:


quest::popup("Join the revolution!", "<br>&nbsp;&nbsp; &nbsp;&nbsp;Welcome to the Mines of Gloomingdeep. Your fellow captives
need your help to fight the kobolds. When you are ready to leave the tutorial, talk to
Arias and he will show you the way to your home city. Should you decide to leave, you
will be able to return to the tutorial from the character select screen until you are
level ten.<br><br>&nbsp;&nbsp;&nbsp;&nbsp;If you need to refresh your memory on topics
that we have already covered, feel free to click on the question mark icon on the
<c \"#00A000\">Toolbar</c> located at the top of your screen.
<br ><br>&nbsp;&nbsp;&nbsp;&nbsp;<c \"#F07F00\">Click 'OK' to continue .</c>");


Note that I broke the example up onto multiple lines for readability. It all needs to be on one line in your quest (unless you can have multiline strings in Perl).

The first argument is the window title, the second is the text to display in the window, which looks like HTML. The above example comes out looking like this:

http://www.rama.demon.co.uk/popup.jpg

Only one popup can be active at a time. If you send another while one is already up, it will overwrite the one already showing.

OP_OnLevelMessage needs to be changed from 0x0000 to 0x1dde in patch_Titanium.conf (same value as is already in patch_6.2.conf)

Derision
08-26-2008, 03:17 PM
My guess was right, the text field is 4096 bytes, so the struct is actually this:


struct OnLevelMessage_Struct {
/*0000*/ char Title[128];
/*0128*/ char Text[4096];
/*4224*/ uint32 Buttons;
/*4228*/ uint32 unknown4228;
/*4232*/ uint32 PopupID;
/*4236*/ uint32 unknown4236;
/*4240*/ uint32 unknown4240;
};


If buttons = 0, just the OK button is displayed and this sends the opcode when pressed.

If buttons = 1, Yes and No buttons are displayed. Clicking Yes sends the opcode, clicking No does nothing.

If buttons = 256, the OK button is displayed, along with the MP3 Player controls!