PDA

View Full Version : Knock knock


foley
01-30-2002, 02:35 AM
That's right, my door code is ready to be released for feedback. Basic doors work, there is support for locked doors, though the zone data packets that are sent when zoning do not tell you if a door is locked or what the key is, so we will have to manually enter this data into the database. Also "triggered" objects are supported, ie. elevators, but again, this information isn't sent in the zone data packets so we will have to enter this information manually. Also, I noticed that on the live servers when you open double doors, you only need to click on one of the doors to open them both. I think we can accomplish this using the "trigger" code, but for now, you will have to click on both doors in a double door set to open them.

Directions
1. Download this zip file zoneobjects.zip (http://www.geocities.com/bdigital43/index.html)
2. Unzip this file, put the ZoneObject.h and ZoneObject.cpp file into the zone directory of your EQEmu Source Code and put the ZoneObjects.sql file into your mysql\bin directory.
3. start up mysql.exe in your mysql\bin directory and type use eq (or whatever your database name is).
4. type source zoneobjects.sql (you should get a bunch of OKs indicating successful database inserts)
5. follow the coding directions below to update zone.exe

foley
01-30-2002, 02:39 AM
Code Directions
Add Zoneobject.cpp and ZoneObject.h to your project.

Add the following line to Client::Process() inside the if (Connected()) block:
zone->CheckZoneObjects();

Modify the case CLIENT_CONNECTING4: { in client_process.cpp block to look like the following:
if (app->opcode == 0x0a20)
{
cout << "Login packet 4" << endl;

APPLAYER* outapp;

ZoneObject_Struct *zos;
ZoneObject_Struct *dzos;
int numzoneobjects,deflatedsize;

numzoneobjects=zone->GetZoneObjects(zos);
if(numzoneobjects>0)
{
dzos=new ZoneObject_Struct[numzoneobjects];
deflatedsize=DeflatePacket((unsigned char*)(zos), sizeof(ZoneObject_Struct)*numzoneobjects, (unsigned char*)(dzos), sizeof(ZoneObject_Struct)*numzoneobjects);
delete zos;

outapp = new APPLAYER;
outapp->pBuffer = new uchar[deflatedsize+2];
outapp->opcode = 0xf721;
*(int16 *)(outapp->pBuffer)=numzoneobjects;
memcpy((outapp->pBuffer)+2, dzos, deflatedsize);
outapp->size = deflatedsize+2;
packet_manager.MakeEQPacket(outapp);
delete outapp;
delete dzos;
}

outapp = new APPLAYER;
outapp->opcode = 0xd820; // Unknown
outapp->size = 0;
QueuePacket(outapp);
delete outapp;

client_state = CLIENT_CONNECTING5;
break;
}
}


Add the following case to the switch(app->opcode) block that is within the case CLIENT_CONNECTED in client_process.cpp
case OP_ZoneObjectOpenRequest: {
APPLAYER *outapp;
ZoneObjectOpen_Struct *zoos = (ZoneObjectOpen_Struct *)app->pBuffer;
ZoneObject *zo=zone->GetZoneObject(zoos->zoneobject_id);
cout << "zoneobjectid=" << int(zo->GetZoneObjectID()) << " initialstate=" << int(zo->zoneobjectstruct.initialstate) << " item=" << uint32(zoos->item_nr) << endl;
if(zo && zo->zoneobjectstruct.initialstate) // check if open
{
cout << "closing zone object" << endl;
outapp = new APPLAYER;
outapp->opcode=OP_ZoneObjectOpen;
outapp->size=2;
outapp->pBuffer=new uchar[outapp->size];
outapp->pBuffer[0]=zoos->zoneobject_id;
outapp->pBuffer[1]=0x03; // seems to say 'close'

entity_list.QueueCloseClients(this,outapp,true); // tell other clients
packet_manager.MakeEQPacket(outapp); // tell client who closed the object
delete outapp;

zo->zoneobjectstruct.initialstate=0;
zone->CloseZoneObject(zoos->zoneobject_id);
}
else if(zo && (zoos->item_nr==0xffff || zo->GetKeyNumber()==zoos->item_nr || zoos->item_nr==0x0000))
{
cout << "opening zone object" << endl;
outapp = new APPLAYER;
outapp->opcode=OP_ZoneObjectOpen;
outapp->size=2;
outapp->pBuffer=new uchar[outapp->size];
outapp->pBuffer[0]=zoos->zoneobject_id;
outapp->pBuffer[1]=0x02; // seems to say 'open'
if(zoos->item_nr==0x0000)
{
cout << "auto close request?" << endl;
outapp->pBuffer[1]=0x03;
}

entity_list.QueueCloseClients(this,outapp,true); // tell other clients
packet_manager.MakeEQPacket(outapp); // tell client who opened the door
delete outapp;

zo->zoneobjectstruct.initialstate=1;
zone->AddOpenedZoneObject(zoos->zoneobject_id, zo->opentimer);
}
else if(zo)
{
Message(13, "It's locked and you're not holding the key.");
break;
}
if(zo)
{
uint32 triggerid=zo->trigger_id;
if(triggerid!=65535)
{
ZoneObject *tzo=zone->GetZoneObject(triggerid);
if(tzo && tzo->zoneobjectstruct.initialstate && !zone->GetZoneObjectStatus(triggerid)) // check if open
{
cout << "closing triggered object:" << triggerid << endl;
outapp = new APPLAYER;
outapp->opcode=OP_ZoneObjectOpen;
outapp->size=2;
outapp->pBuffer=new uchar[outapp->size];
outapp->pBuffer[0]=triggerid;
outapp->pBuffer[1]=0x03; // seems to say 'close'
entity_list.QueueCloseClients(this,outapp,true); // tell other clients
packet_manager.MakeEQPacket(outapp); // tell client who closed the object
delete outapp;

tzo->zoneobjectstruct.initialstate=0;
zone->AddOpenedZoneObject(triggerid, tzo->opentimer);
}
else if(tzo && !zone->GetZoneObjectStatus(triggerid))
{
cout << "opening triggered object:" << triggerid << endl;
outapp = new APPLAYER;
outapp->opcode=OP_ZoneObjectOpen;
outapp->size=2;
outapp->pBuffer=new uchar[outapp->size];
outapp->pBuffer[0]=triggerid;
outapp->pBuffer[1]=0x02; // seems to say 'open'
entity_list.QueueCloseClients(this,outapp,true); // tell other clients
packet_manager.MakeEQPacket(outapp); // tell client who opened the door
delete outapp;

tzo->zoneobjectstruct.initialstate=1;
zone->AddOpenedZoneObject(triggerid, tzo->opentimer);
}
}
}
break;
}

foley
01-30-2002, 02:43 AM
Add the following functions prototypes to zone.h
public:
int GetZoneObjectStatus(char);
void AddOpenedZoneObject(char, uint32);
void CloseZoneObject(char);
void CheckZoneObjects();
int GetZoneObjects(char *, ZoneObject_Struct*&);
ZoneObject *GetZoneObject(char);
private:
int numzoneobjects;
LinkedList<ZoneObject*> ZoneObjects;
LinkedList<ZoneObject*> opened_zone_object_list;

And also add the following include to zone.h
#include "zoneobject.h"

Add the following line to the Zone constructor
numzoneobjects=GetZoneObjectsFromDB();

Add the following function definitions to zone.cpp
int Zone::GetZoneObjectsFromDB() {
char *query = 0;
int buf_len = 256;
int chars = -1;
MYSQL_RES *result;
MYSQL_ROW row;
int numzoneobjects;

while (chars == -1 || chars >= buf_len)
{
if (query != 0)
{
delete[] query;
query = 0;
buf_len *= 2;
}
query = new char[buf_len];
chars = snprintf(query, buf_len, "SELECT * FROM zoneobjects WHERE zonename='%s'", short_name);
}
if (!mysql_query(&database.mysql, query))
{
delete[] query;
result = mysql_store_result(&database.mysql);
if (result)
{
numzoneobjects=int(mysql_num_rows(result));
for(int i=0; i< numzoneobjects; i++)
{
row = mysql_fetch_row(result);
ZoneObject *newzoneobject=new ZoneObject;

strcpy(newzoneobject->zoneobjectstruct.name, row[1]);
newzoneobject->zoneobjectstruct.x=atof(row[2]);
newzoneobject->zoneobjectstruct.y=atof(row[3]);
newzoneobject->zoneobjectstruct.z=atof(row[4]);
newzoneobject->zoneobjectstruct.heading=atof(row[5]);
newzoneobject->zoneobjectstruct.unknown1=atof(row[6]);
newzoneobject->zoneobjectstruct.unknown2=atof(row[7]);
newzoneobject->zoneobjectstruct.zoneobject_id=atoi(row[8]);
newzoneobject->zoneobjectstruct.type=atoi(row[9]);
newzoneobject->zoneobjectstruct.initialstate=atoi(row[10]);
newzoneobject->zoneobjectstruct.holdstateforever=atoi(row[11]);
newzoneobject->zoneobjectstruct.unknown3=atof(row[12]);
newzoneobject->zoneobjectstruct.unknown4=atof(row[13]);
newzoneobject->zoneobjectstruct.unknown5=atof(row[14]);
newzoneobject->zoneobjectstruct.unknown6=atof(row[15]);
newzoneobject->item_nr=atoi(row[16]);
newzoneobject->trigger_id=atoi(row[17]);
newzoneobject->opentimer=atoi(row[18]);
ZoneObjects.Append(newzoneobject);
}
cout << numzoneobjects << " Zone Objects Loaded" << endl;
}
mysql_free_result(result);
}
else
{
cerr << "Error in GetZoneObjects query '" << query << "' " << mysql_error(&database.mysql) << endl;
delete[] query;
}
return numzoneobjects;
}
int Zone::GetZoneObjects(ZoneObject_Struct* &zos)
{
LinkedListIterator<ZoneObject*> iterator(ZoneObjects);

zos = new ZoneObject_Struct[numzoneobjects];
int i=0;
iterator.Reset();
while (iterator.MoreElements())
{
zos[i]=iterator.GetData()->zoneobjectstruct;
iterator.Advance();
i++;
}
return numzoneobjects;
}
int Zone::GetZoneObjectStatus(char zoneobject_id) // Is it open?
{
LinkedListIterator<ZoneObject*> iterator(opened_zone_object_list);

iterator.Reset();
while (iterator.MoreElements())
{
if(iterator.GetData()->GetZoneObjectID()==zoneobject_id)
return 1;
iterator.Advance();
}
return 0;
}
void Zone::CheckZoneObjects() // If timer has run out, close it
{
LinkedListIterator<ZoneObject*> iterator(opened_zone_object_list);

iterator.Reset();
while (iterator.MoreElements())
{
if(iterator.GetData()->timer->Check())
{
ZoneObject *pzo;
pzo=GetZoneObject(iterator.GetData()->GetZoneObjectID());
if(!pzo->zoneobjectstruct.holdstateforever)
pzo->zoneobjectstruct.initialstate=0;
iterator.RemoveCurrent();
}
iterator.Advance();
}
}
ZoneObject *Zone::GetZoneObject(char zoneobject_id)
{
LinkedListIterator<ZoneObject*> iterator(ZoneObjects);

iterator.Reset();
while (iterator.MoreElements())
{
if(iterator.GetData()->GetZoneObjectID()==zoneobject_id)
return iterator.GetData();
iterator.Advance();
}
return 0;
}
void Zone::AddOpenedZoneObject(char zoneobject_id, uint32 opentimer)
{
ZoneObject *newzoneobject=new ZoneObject;
newzoneobject->SetZoneObjectID(zoneobject_id);
newzoneobject->timer=new Timer(opentimer);
opened_zone_object_list.Append(newzoneobject);
}
void Zone::CloseZoneObject(char zoneobject_id)
{
LinkedListIterator<ZoneObject*> iterator(opened_zone_object_list);

iterator.Reset();
while (iterator.MoreElements())
{
if(iterator.GetData()->GetZoneObjectID()==zoneobject_id)
{
iterator.RemoveCurrent();
return;
}
iterator.Advance();
}
}

Add the Following 2 lines to eq_opcodes.h
#define OP_ZoneObjectOpenRequest 0x8d20
#define OP_ZoneObjectOpen 0x8e20

Add the Following structs to eq_packet_structs.h
struct ZoneObject_Struct
{
char name[16]; // Filename of object? Determines what the object looks like
float x;
float y;
float z;
float heading;
float unknown1;
float unknown2;
char zoneobject_id; // uniquely identifies the object within the zone
char type; // determines animation (can do cool things with this)
char initialstate; // is it initially open,spinniing etc.
char holdstateforever; // stay open forever, or return to "closed" after 11 seconds
char unknown3;
char unknown4;
char unknown5;
char unknown6;
};

struct CompressedZoneObject_Struct
{
uint16 count; // number of objects
struct ZoneObject_Struct *zoneobjects;
};

struct ZoneObjectOpen_Struct
{
char zoneobject_id; // id within the zone of the door
char action; // 01
char placeholder[2];
uint16 item_nr; // unique item number player is holding(key)
char placeholder2[2];
char unknown[2];
char placeholder3[2];
};

foley
01-30-2002, 03:13 AM
In case anyone was wondering the following zones are included in the data set.
Antonica:
All EXCEPT Cazic-Thule, Arena, and Beholder's Maze
Faydwer:
All EXCEPT Kedge Keep and Unrest
Odus:
All EXCEPT Erud's Crossing and Stonebrunt Mountains
Kunark:
None
Velious:
None
Luclin:
None
Planes:
None

darvik
01-30-2002, 03:25 AM
So , will this allow things such as teleporters to work also? Like say the firepots in TD (If they were put in the db) ?

foley
01-30-2002, 05:45 AM
So , will this allow things such as teleporters to work also? Like say the firepots in TD (If they were put in the db) ?

No I don't believe this will accomplish that, though I will have to check into that.

Nefarious
01-30-2002, 06:52 AM
nice foley =)

now.. to see if it works... =p

Pyrotek
01-31-2002, 01:05 AM
Looks good, more tables of info to maintain. :/